diff --git a/.jsdoc.json b/.jsdoc.json
index 1cca0d93..86397dac 100644
--- a/.jsdoc.json
+++ b/.jsdoc.json
@@ -17,7 +17,7 @@
"useCollapsibles": true,
"collapse": true,
"resources": {
- "y-js.org": "yjs.website"
+ "yjs.dev": "Yjs website"
},
"logo": {
"url": "https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png",
diff --git a/README.md b/README.md
index 42e54230..be5c2aee 100644
--- a/README.md
+++ b/README.md
@@ -1,305 +1,855 @@
-# 
+# 
-Yjs is a framework for offline-first p2p shared editing on structured data like
-text, richtext, json, or XML. It is fairly easy to get started, as Yjs hides
-most of the complexity of concurrent editing. For additional information, demos,
-and tutorials visit [y-js.org](http://y-js.org/).
+> A CRDT framework with a powerful abstraction of shared data
-:warning: Checkout the [v13 docs](./README.v13.md) for the upcoming release :warning:
+Yjs is a [CRDT implementation](#Yjs-CRDT-Algorithm) that exposes its internal
+data structure as *shared types*. Shared types are common data types like `Map`
+or `Array` with superpowers: changes are automatically distributed to other
+peers and merged without merge conflicts.
-### Extensions
-Yjs only knows how to resolve conflicts on shared data. You have to choose a ..
+Yjs is **network agnostic** (p2p!), supports many existing **rich text
+editors**, **offline editing**, **version snapshots**, **undo/redo** and
+**shared cursors**. It scales well with an unlimited number of users and is well
+suited for even large documents.
-* *Connector* - a communication protocol that propagates changes to the clients
-* *Database* - a database to store your changes
-* one or more *Types* - that represent the shared data
+* Demos: [https://github.com/yjs/yjs-demos](https://github.com/yjs/yjs-demos)
+* Discuss: [https://discuss.yjs.dev](https://discuss.yjs.dev)
+* Benchmarks:
+ [https://github.com/dmonad/crdt-benchmarks](https://github.com/dmonad/crdt-benchmarks)
-Connectors, Databases, and Types are available as modules that extend Yjs. Here
-is a list of the modules we know of:
+:warning: This is the documentation for v13 (still in alpha). For the stable v12
+release checkout the [v12 docs](./README.v12.md) :warning:
-##### Connectors
+## Table of Contents
-|Name | Description |
-|----------------|-----------------------------------|
-|[webrtc](https://github.com/y-js/y-webrtc) | Propagate updates Browser2Browser via WebRTC|
-|[websockets](https://github.com/y-js/y-websockets-client) | Set up [a central server](https://github.com/y-js/y-websockets-client), and connect to it via websockets |
-|[xmpp](https://github.com/y-js/y-xmpp) | Propagate updates in a XMPP multi-user-chat room ([XEP-0045](http://xmpp.org/extensions/xep-0045.html))|
-|[ipfs](https://github.com/ipfs-labs/y-ipfs-connector) | Connector for the [Interplanetary File System](https://ipfs.io/)!|
-|[test](https://github.com/y-js/y-test) | A Connector for testing purposes. It is designed to simulate delays that happen in worst case scenarios|
+* [Overview](#Overview)
+ * [Bindings](#Bindings)
+ * [Providers](#Providers)
+* [Getting Started](#Getting-Started)
+* [API](#API)
+ * [Shared Types](#Shared-Types)
+ * [Y.Doc](#YDoc)
+ * [Document Updates](#Document-Updates)
+ * [Relative Positions](#Relative-Positions)
+ * [Y.UndoManager](#YUndoManager)
+* [Miscellaneous](#Miscellaneous)
+ * [Typescript Declarations](#Typescript-Declarations)
+* [Yjs CRDT Algorithm](#Yjs-CRDT-Algorithm)
+* [Evaluation](#Evaluation)
+ * [Existing shared editing libraries](#Exisisting-Javascript-Libraries)
+ * [CRDT Algorithms](#CRDT-Algorithms)
+ * [Comparison of CRDT with OT](#Comparing-CRDT-with-OT)
+ * [Comparison of CRDT Algorithms](#Comparing-CRDT-Algorithms)
+ * [Comparison of Yjs with other Implementations](#Comparing-Yjs-with-other-Implementations)
+* [License and Author](#License-and-Author)
-##### Database adapters
+## Overview
-|Name | Description |
-|----------------|-----------------------------------|
-|[memory](https://github.com/y-js/y-memory) | In-memory storage. |
-|[indexeddb](https://github.com/y-js/y-indexeddb) | Offline storage for the browser |
-|[leveldb](https://github.com/y-js/y-leveldb) | Persistent storage for node apps |
+This repository contains a collection of shared types that can be observed for
+changes and manipulated concurrently. Network functionality and two-way-bindings
+are implemented in separate modules.
-##### Types
+### Bindings
-| Name | Description |
-|----------|-------------------|
-|[map](https://github.com/y-js/y-map) | A shared Map implementation. Maps from text to any stringify-able object |
-|[array](https://github.com/y-js/y-array) | A shared Array implementation |
-|[xml](https://github.com/y-js/y-xml) | An implementation of the DOM. You can create a two way binding to Browser DOM objects |
-|[text](https://github.com/y-js/y-text) | Collaborate on text. Supports two way binding to the [Ace Editor](https://ace.c9.io), [CodeMirror](https://codemirror.net/), [Monaco](https://github.com/Microsoft/monaco-editor), textareas, input elements, and HTML elements (e.g. <*h1*>, or <*p*>) |
-|[richtext](https://github.com/y-js/y-richtext) | Collaborate on rich text. Supports two way binding to the [Quill Rich Text Editor](http://quilljs.com/)|
+| Name | Cursors | Binding | Demo |
+|---|:-:|---|---|
+| [ProseMirror](https://prosemirror.net/) | ✔ | [y-prosemirror](http://github.com/yjs/y-prosemirror) | [demo](https://yjs-demos.now.sh/prosemirror/) |
+| [Quill](https://quilljs.com/) | | [y-quill](http://github.com/yjs/y-quill) | [demo](https://yjs-demos.now.sh/quill/) |
+| [CodeMirror](https://codemirror.net/) | ✔ | [y-codemirror](http://github.com/yjs/y-codemirror) | [demo](https://yjs-demos.now.sh/codemirror/) |
+| [Monaco](https://microsoft.github.io/monaco-editor/) | ✔ | [y-monaco](http://github.com/yjs/y-monaco) | [demo](https://yjs-demos.now.sh/monaco/) |
+| [Ace](https://ace.c9.io/) | | [y-ace](http://github.com/yjs/y-ace) | [demo](https://yjs-demos.now.sh/ace/) |
+| [Textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) | | [y-textarea](http://github.com/yjs/y-textarea) | [demo](https://yjs-demos.now.sh/textarea/) |
+| [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) | | [y-dom](http://github.com/yjs/y-dom) | [demo](https://yjs-demos.now.sh/dom/) |
-##### Other
+### Providers
-| Name | Description |
-|-----------|-------------------|
-|[y-element](http://y-js.org/y-element/) | Yjs Polymer Element |
+Setting up the communication between clients, managing awareness information,
+and storing shared data for offline usage is quite a hassle. **Providers**
+manage all that for you and are the perfect starting point for your
+collaborative app.
-## Use it!
-Install Yjs, and its modules with [bower](http://bower.io/), or
-[npm](https://www.npmjs.org/package/yjs).
+
+ - y-websocket
+ -
+A module that contains a simple websocket backend and a websocket client that
+connects to that backend. The backend can be extended to persist updates in a
+leveldb database.
+
+ - y-mesh
+ -
+[WIP] Creates a connected graph of webrtc connections with a high
+strength. It
+requires a signalling server that connects a client to the first peer. But after
+that the network manages itself. It is well suited for large and small networks.
+
+ - y-dat
+ -
+[WIP] Write document updates effinciently to the dat network using
+multifeed. Each client has
+an append-only log of CRDT local updates (hypercore). Multifeed manages and sync
+hypercores and y-dat listens to changes and applies them to the Yjs document.
+
+
-### Bower
+## Getting Started
-```
-bower install --save yjs y-array % add all y-* modules you want to use
-```
-You only need to include the `y.js` file. Yjs is able to automatically require
-missing modules.
-```
-
-```
+Install Yjs and a provider with your favorite package manager:
-### CDN
-
-```
-
-
-
-
-
-
-// ..
-// do the same for all modules you want to use
-```
-
-### Npm
-
-```
-npm install --save yjs % add all y-* modules you want to use
-```
-
-If you don't include via script tag, you have to explicitly include all modules!
-(Same goes for other module systems)
-```
-var Y = require('yjs')
-require('y-array')(Y) // add the y-array type to Yjs
-require('y-websockets-client')(Y)
-require('y-memory')(Y)
-require('y-map')(Y)
-require('y-text')(Y)
-// ..
-// do the same for all modules you want to use
-```
-
-### ES6 Syntax
-
-```
-import Y from 'yjs'
-import yArray from 'y-array'
-import yWebsocketsClient from 'y-webrtc'
-import yMemory from 'y-memory'
-import yMap from 'y-map'
-import yText from 'y-text'
-// ..
-Y.extend(yArray, yWebsocketsClient, yMemory, yArray, yMap, yText /*, .. */)
-```
-
-# Text editing example
-
-Install dependencies
-```
-bower i yjs y-memory y-webrtc y-array y-text
-```
-
-Here is a simple example of a shared textarea
-```HTML
-
-
-
-
-
-
-
-
-
-```
-
-## Get Help & Give Help
-There are some friendly people on [](https://gitter.im/y-js/yjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) who are eager to help, and answer questions. Please join!
-
-Report _any_ issues to the
-[Github issue page](https://github.com/y-js/yjs/issues)! I try to fix them very
-soon, if possible.
-
-# API
-
-### Y(options)
-* Y.extend(module1, module2, ..)
- * Add extensions to Y
- * `Y.extend(require('y-webrtc'))` has the same semantics as
- `require('y-webrtc')(Y)`
-* options.db
- * Will be forwarded to the database adapter. Specify the database adaper on
- `options.db.name`.
- * Have a look at the used database adapter repository to see all available
- options.
-* options.connector
- * Will be forwarded to the connector adapter. Specify the connector adaper on
- `options.connector.name`.
- * All our connectors implement a `room` property. Clients that specify the
- same room share the same data.
- * All of our connectors specify an `url` property that defines the connection
- endpoint of the used connector.
- * All of our connectors also have a default connection endpoint that you can
- use for development.
- * Set `options.connector.generateUserId = true` in order to genenerate a
- userid, instead of receiving one from the server. This way the `Y(..)` is
- immediately going to be resolved, without waiting for any confirmation from
- the server. Use with caution.
- * Have a look at the used connector repository to see all available options.
- * *Only if you know what you are doing:* Set
- `options.connector.preferUntransformed = true` in order receive the shared
- data untransformed. This is very efficient as the database content is simply
- copied to this client. This does only work if this client receives content
- from only one client.
-* options.sourceDir (browser only)
- * Path where all y-* modules are stored
- * Defaults to `/bower_components`
- * Not required when running on `nodejs` / `iojs`
- * When using nodejs you need to manually extend Yjs:
-```
-var Y = require('yjs')
-// you have to require a db, connector, and *all* types you use!
-require('y-memory')(Y)
-require('y-webrtc')(Y)
-require('y-map')(Y)
-// ..
-```
-* options.share
- * Specify on `options.share[arbitraryName]` types that are shared among all
- users.
- * E.g. Specify `options.share[arbitraryName] = 'Array'` to require y-array and
- create an y-array type on `y.share[arbitraryName]`.
- * If userA doesn't specify `options.share[arbitraryName]`, it won't be
- available for userA.
- * If userB specifies `options.share[arbitraryName]`, it still won't be
- available for userA. But all the updates are send from userB to userA.
- * In contrast to y-map, types on `y.share.*` cannot be overwritten or deleted.
- Instead, they are merged among all users. This feature is only available on
- `y.share.*`
- * Weird behavior: It is supported that two users specify different types with
- the same property name.
- E.g. userA specifies `options.share.x = 'Array'`, and userB specifies
- `options.share.x = 'Text'`. But they only share data if they specified the
- same type with the same property name
-* options.type (browser only)
- * Array of modules that Yjs needs to require, before instantiating a shared
- type.
- * By default Yjs requires the specified database adapter, the specified
- connector, and all modules that are used in `options.share.*`
- * Put all types here that you intend to use, but are not used in y.share.*
-
-### Instantiated Y object (y)
-`Y(options)` returns a promise that is fulfilled when..
-
-* All modules are loaded
- * The specified database adapter is loaded
- * The specified connector is loaded
- * All types are included
-* The connector is initialized, and a unique user id is set (received from the
- server)
- * Note: When using y-indexeddb, a retrieved user id is stored on `localStorage`
-
-The promise returns an instance of Y. We denote it with a lower case `y`.
-
-* y.share.*
- * Instances of the types you specified on options.share.*
- * y.share.* can only be defined once when you instantiate Y!
-* y.connector is an instance of Y.AbstractConnector
-* y.connector.onUserEvent(function (event) {..})
- * Observe user events (event.action is either 'userLeft' or 'userJoined')
-* y.connector.whenSynced(listener)
- * `listener` is executed when y synced with at least one user.
- * `listener` is not called when no other user is in the same room.
- * y-websockets-client aways waits to sync with the server
-* y.connector.disconnect()
- * Force to disconnect this instance from the other instances
-* y.connector.connect()
- * Try to reconnect to the other instances (needs to be supported by the
- connector)
- * Not supported by y-xmpp
-* y.close()
- * Destroy this object.
- * Destroys all types (they will throw weird errors if you still use them)
- * Disconnects from the other instances (via connector)
- * Returns a promise
-* y.destroy()
- * calls y.close()
- * Removes all data from the database
- * Returns a promise
-* y.db.stopGarbageCollector()
- * Stop the garbage collector. Call y.db.garbageCollect() to continue garbage
- collection
-* y.db.gc :: Boolean
- * Whether gc is turned on
-* y.db.gcTimeout :: Number (defaults to 50000 ms)
- * Time interval between two garbage collect cycles
- * It is required that all instances exchanged all messages after two garbage
- collect cycles (after 100000 ms per default)
-* y.db.userId :: String
- * The used user id for this client. **Never overwrite this**
-
-### Logging
-Yjs uses [debug](https://github.com/visionmedia/debug) for logging. The flag
-`y*` enables logging for all y-* components. You can selectively remove
-components you are not interested in: E.g. The flag `y*,-y:connector-message`
-will not log the long `y:connector-message` messages.
-
-##### Enable logging in Node.js
```sh
-DEBUG=y* node app.js
+npm i yjs@13.0.0-97 y-websocket@1.0.0-6
```
-Remove the colors in order to log to a file:
+Start the y-websocket server:
+
```sh
-DEBUG_COLORS=0 DEBUG=y* node app.js > log
+PORT=1234 node ./node_modules/y-websocket/bin/server.js
```
-##### Enable logging in the browser
+### Example: Observe types
+
```js
-localStorage.debug = 'y*'
+const yarray = doc.getArray('my-array')
+yarray.observe(event => {
+ console.log('yarray was modified')
+})
+// every time a local or remote client modifies yarray, the observer is called
+yarray.insert(0, ['val']) // => "yarray was modified"
```
-## License
-Yjs is licensed under the [MIT License](./LICENSE).
+### Example: Nest types
+
+Remember, shared types are just plain old data types. The only limitation is
+that a shared type must exist only once in the shared document.
+
+```js
+const ymap = doc.getMap('map')
+const foodArray = new Y.Array()
+foodArray.insert(0, ['apple', 'banana'])
+ymap.set('food', foodArray)
+ymap.get('food') === foodArray // => true
+ymap.set('fruit', foodArray) // => Error! foodArray is already defined
+```
+
+Now you understand how types are defined on a shared document. Next you can jump
+to the [demo repository](https://github.com/yjs/yjs-demos) or continue reading
+the API docs.
+
+## API
+
+```js
+import * as Y from 'yjs'
+```
+
+### Shared Types
+
+
+ Y.Array
+
+
+A shareable Array-like type that supports efficient insert/delete of elements
+at any position. Internally it uses a linked list of Arrays that is split when
+necessary.
+
+ const yarray = new Y.Array()
+
+ insert(index:number, content:Array<object|boolean|Array|string|number|Uint8Array|Y.Type>)
+ -
+Insert content at index. Note that content is an array of elements.
+I.e.
array.insert(0, [1]
splices the list and inserts 1 at
+position 0.
+
+ push(Array<Object|boolean|Array|string|number|Uint8Array|Y.Type>)
+
+ delete(index:number, length:number)
+
+ get(index:number)
+
+ length:number
+
+
+
+forEach(function(value:object|boolean|Array|string|number|Uint8Array|Y.Type,
+ index:number, array: Y.Array))
+
+
+
+ map(function(T, number, YArray):M):Array<M>
+
+ toArray():Array<object|boolean|Array|string|number|Uint8Array|Y.Type>
+ - Copies the content of this YArray to a new Array.
+ toJSON():Array<Object|boolean|Array|string|number>
+ -
+Copies the content of this YArray to a new Array. It transforms all child types
+to JSON using their
toJSON
method.
+
+ [Symbol.Iterator]
+ -
+ Returns an YArray Iterator that contains the values for each index in the array.
+
for (let value of yarray) { .. }
+
+ observe(function(YArrayEvent, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type is modified. In the case this type is modified in the event listener,
+the event listener will be called again after the current event listener returns.
+
+ unobserve(function(YArrayEvent, Transaction):void)
+ -
+ Removes an
observe
event listener from this type.
+
+ observeDeep(function(Array<YEvent>, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type or any of its children is modified. In the case this type is modified
+in the event listener, the event listener will be called again after the current
+event listener returns. The event listener receives all Events created by itself
+or any of its children.
+
+ unobserveDeep(function(Array<YEvent>, Transaction):void)
+ -
+ Removes an
observeDeep
event listener from this type.
+
+
+
+
+ Y.Map
+
+
+ A shareable Map type.
+
+ const ymap = new Y.Map()
+
+ get(key:string):object|boolean|string|number|Uint8Array|Y.Type
+
+ set(key:string, value:object|boolean|string|number|Uint8Array|Y.Type)
+
+ delete(key:string)
+
+ has(key:string):boolean
+
+ get(index:number)
+
+ toJSON():Object<string, Object|boolean|Array|string|number|Uint8Array>
+ -
+Copies the
[key,value]
pairs of this YMap to a new Object.It
+transforms all child types to JSON using their toJSON
method.
+
+ forEach(function(key:string,value:object|boolean|Array|string|number|Uint8Array|Y.Type))
+ -
+ Execute the provided function once for every key-value pair.
+
+ [Symbol.Iterator]
+ -
+ Returns an Iterator of
[key, value]
pairs.
+ for (let [key, value] of ymap) { .. }
+
+ entries()
+ -
+ Returns an Iterator of
[key, value]
pairs.
+
+ values()
+ -
+ Returns an Iterator of all values.
+
+ keys()
+ -
+ Returns an Iterator of all keys.
+
+ observe(function(YMapEvent, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type is modified. In the case this type is modified in the event listener,
+the event listener will be called again after the current event listener returns.
+
+ unobserve(function(YMapEvent, Transaction):void)
+ -
+ Removes an
observe
event listener from this type.
+
+ observeDeep(function(Array<YEvent>, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type or any of its children is modified. In the case this type is modified
+in the event listener, the event listener will be called again after the current
+event listener returns. The event listener receives all Events created by itself
+or any of its children.
+
+ unobserveDeep(function(Array<YEvent>, Transaction):void)
+ -
+ Removes an
observeDeep
event listener from this type.
+
+
+
+
+
+ Y.Text
+
+
+A shareable type that is optimized for shared editing on text. It allows to
+assign properties to ranges in the text. This makes it possible to implement
+rich-text bindings to this type.
+
+
+This type can also be transformed to the
+delta format. Similarly the
+YTextEvents compute changes as deltas.
+
+ const ytext = new Y.Text()
+
+ insert(index:number, content:string, [formattingAttributes:Object<string,string>])
+ -
+ Insert a string at index and assign formatting attributes to it.
+
ytext.insert(0, 'bold text', { bold: true })
+
+ delete(index:number, length:number)
+
+ format(index:number, length:number, formattingAttributes:Object<string,string>)
+ - Assign formatting attributes to a range in the text
+ applyDelta(delta)
+ - See Quill Delta
+ length:number
+
+ toString():string
+ - Transforms this type, without formatting options, into a string.
+ toJSON():string
+ - See
toString
+ toDelta():Delta
+ -
+Transforms this type to a Quill Delta
+
+ observe(function(YTextEvent, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type is modified. In the case this type is modified in the event listener,
+the event listener will be called again after the current event listener returns.
+
+ unobserve(function(YTextEvent, Transaction):void)
+ -
+ Removes an
observe
event listener from this type.
+
+ observeDeep(function(Array<YEvent>, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type or any of its children is modified. In the case this type is modified
+in the event listener, the event listener will be called again after the current
+event listener returns. The event listener receives all Events created by itself
+or any of its children.
+
+ unobserveDeep(function(Array<YEvent>, Transaction):void)
+ -
+ Removes an
observeDeep
event listener from this type.
+
+
+
+
+
+ YXmlFragment
+
+
+ A container that holds an Array of Y.XmlElements.
+
+ const yxml = new Y.XmlFragment()
+
+ insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)
+
+ delete(index:number, length:number)
+
+ get(index:number)
+
+ length:number
+
+ toArray():Array<Y.XmlElement|Y.XmlText>
+ - Copies the children to a new Array.
+ toDOM():DocumentFragment
+ - Transforms this type and all children to new DOM elements.
+ toString():string
+ - Get the XML serialization of all descendants.
+ toJSON():string
+ - See
toString
.
+ observe(function(YXmlEvent, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type is modified. In the case this type is modified in the event listener,
+the event listener will be called again after the current event listener returns.
+
+ unobserve(function(YXmlEvent, Transaction):void)
+ -
+ Removes an
observe
event listener from this type.
+
+ observeDeep(function(Array<YEvent>, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type or any of its children is modified. In the case this type is modified
+in the event listener, the event listener will be called again after the current
+event listener returns. The event listener receives all Events created by itself
+or any of its children.
+
+ unobserveDeep(function(Array<YEvent>, Transaction):void)
+ -
+ Removes an
observeDeep
event listener from this type.
+
+
+
+
+
+ Y.XmlElement
+
+
+A shareable type that represents an XML Element. It has a nodeName
,
+attributes, and a list of children. But it makes no effort to validate its
+content and be actually XML compliant.
+
+ const yxml = new Y.XmlElement()
+
+ insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)
+
+ delete(index:number, length:number)
+
+ get(index:number)
+
+ length:number
+
+ setAttribute(attributeName:string, attributeValue:string)
+
+ removeAttribute(attributeName:string)
+
+ getAttribute(attributeName:string):string
+
+ getAttributes(attributeName:string):Object<string,string>
+
+ toArray():Array<Y.XmlElement|Y.XmlText>
+ - Copies the children to a new Array.
+ toDOM():Element
+ - Transforms this type and all children to a new DOM element.
+ toString():string
+ - Get the XML serialization of all descendants.
+ toJSON():string
+ - See
toString
.
+ observe(function(YXmlEvent, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every
+time this type is modified. In the case this type is modified in the event
+listener, the event listener will be called again after the current event
+listener returns.
+
+ unobserve(function(YXmlEvent, Transaction):void)
+ -
+ Removes an
observe
event listener from this type.
+
+ observeDeep(function(Array<YEvent>, Transaction):void)
+ -
+Adds an event listener to this type that will be called synchronously every time
+this type or any of its children is modified. In the case this type is modified
+in the event listener, the event listener will be called again after the current
+event listener returns. The event listener receives all Events created by itself
+or any of its children.
+
+ unobserveDeep(function(Array<YEvent>, Transaction):void)
+ -
+ Removes an
observeDeep
event listener from this type.
+
+
+
+
+### Y.Doc
+
+```js
+const doc = new Y.Doc()
+```
+
+
+ clientID
+ - A unique id that identifies this client. (readonly)
+ transact(function(Transaction):void [, origin:any])
+ -
+Every change on the shared document happens in a transaction. Observer calls and
+the
update
event are called after each transaction. You should
+bundle changes into a single transaction to reduce the amount of event
+calls. I.e. doc.transact(() => { yarray.insert(..); ymap.set(..) })
+triggers a single change event.
You can specify an optional origin
+parameter that is stored on transaction.origin
and
+on('update', (update, origin) => ..)
.
+
+ get(string, Y.[TypeClass]):[Type]
+ - Define a shared type.
+ getArray(string):Y.Array
+ - Define a shared Y.Array type. Is equivalent to
y.get(string, Y.Array)
.
+ getMap(string):Y.Map
+ - Define a shared Y.Map type. Is equivalent to
y.get(string, Y.Map)
.
+ getXmlFragment(string):Y.XmlFragment
+ - Define a shared Y.XmlFragment type. Is equivalent to
y.get(string, Y.XmlFragment)
.
+ on(string, function)
+ - Register an event listener on the shared type
+ off(string, function)
+ - Unregister an event listener from the shared type
+
+
+#### Y.Doc Events
+
+
+ on('update', function(updateMessage:Uint8Array, origin:any, Y.Doc):void)
+ -
+Listen to document updates. Document updates must be transmitted to all other
+peers. You can apply document updates in any order and multiple times.
+
+ on('beforeTransaction', function(Y.Transaction, Y.Doc):void)
+ - Emitted before each transaction.
+ on('afterTransaction', function(Y.Transaction, Y.Doc):void)
+ - Emitted after each transaction.
+
+
+### Document Updates
+
+Changes on the shared document are encoded into *document updates*. Document
+updates are *commutative* and *idempotent*. This means that they can be applied
+in any order and multiple times.
+
+#### Example: Listen to update events and apply them on remote client
+
+```js
+const doc1 = new Y.Doc()
+const doc2 = new Y.Doc()
+
+doc1.on('update', update => {
+ Y.applyUpdate(doc2, update)
+})
+
+doc2.on('update', update => {
+ Y.applyUpdate(doc1, update)
+})
+
+// All changes are also applied to the other document
+doc1.getArray('myarray').insert(0, ['Hello doc2, you got this?'])
+doc2.getArray('myarray').get(0) // => 'Hello doc2, you got this?'
+```
+
+Yjs internally maintains a [state vector](#State-Vector) that denotes the next
+expected clock from each client. In a different interpretation it holds the
+number of structs created by each client. When two clients sync, you can either
+exchange the complete document structure or only the differences by sending the
+state vector to compute the differences.
+
+#### Example: Sync two clients by exchanging the complete document structure
+
+```js
+const state1 = Y.encodeStateAsUpdate(ydoc1)
+const state2 = Y.encodeStateAsUpdate(ydoc2)
+Y.applyUpdate(ydoc1, state2)
+Y.applyUpdate(ydoc2, state1)
+```
+
+#### Example: Sync two clients by computing the differences
+
+This example shows how to sync two clients with the minimal amount of exchanged
+data by computing only the differences using the state vector of the remote
+client. Syncing clients using the state vector requires another roundtrip, but
+can safe a lot of bandwidth.
+
+```js
+const stateVector1 = Y.encodeStateVector(ydoc1)
+const stateVector2 = Y.encodeStateVector(ydoc2)
+const diff1 = Y.encodeStateAsUpdate(ydoc1, stateVector2)
+const diff2 = Y.encodeStateAsUpdate(ydoc2, stateVector1)
+Y.applyUpdate(ydoc1, diff2)
+Y.applyUpdate(ydoc2, diff1)
+```
+
+
+ Y.applyUpdate(Y.Doc, update:Uint8Array, [transactionOrigin:any])
+ -
+Apply a document update on the shared document. Optionally you can specify
+
transactionOrigin
that will be stored on
+transaction.origin
+and ydoc.on('update', (update, origin) => ..)
.
+
+ Y.encodeStateAsUpdate(Y.Doc, [encodedTargetStateVector:Uint8Array]):Uint8Array
+ -
+Encode the document state as a single update message that can be applied on the
+remote document. Optionally specify the target state vector to only write the
+differences to the update message.
+
+ Y.encodeStateVector(Y.Doc):Uint8Array
+ - Computes the state vector and encodes it into an Uint8Array.
+
+
+### Relative Positions
+
+> This API is not stable yet
+
+This feature is intended for managing selections / cursors. When working with
+other users that manipulate the shared document, you can't trust that an index
+position (an integer) will stay at the intended location. A *relative position*
+is fixated to an element in the shared document and is not affected by remote
+changes. I.e. given the document `"a|c"`, the relative position is attached to
+`c`. When a remote user modifies the document by inserting a character before
+the cursor, the cursor will stay attached to the character `c`. `insert(1,
+'x')("a|c") = "ax|c"`. When the *relative position* is set to the end of the
+document, it will stay attached to the end of the document.
+
+#### Example: Transform to RelativePosition and back
+
+```js
+const relPos = Y.createRelativePositionFromTypeIndex(ytext, 2)
+const pos = Y.createAbsolutePositionFromRelativePosition(relPos, doc)
+pos.type === ytext // => true
+pos.index === 2 // => true
+```
+
+#### Example: Send relative position to remote client (json)
+
+```js
+const relPos = Y.createRelativePositionFromTypeIndex(ytext, 2)
+const encodedRelPos = JSON.stringify(relPos)
+// send encodedRelPos to remote client..
+const parsedRelPos = JSON.parse(encodedRelPos)
+const pos = Y.createAbsolutePositionFromRelativePosition(parsedRelPos, remoteDoc)
+pos.type === remoteytext // => true
+pos.index === 2 // => true
+```
+
+#### Example: Send relative position to remote client (Uint8Array)
+
+```js
+const relPos = Y.createRelativePositionFromTypeIndex(ytext, 2)
+const encodedRelPos = Y.encodeRelativePosition(relPos)
+// send encodedRelPos to remote client..
+const parsedRelPos = Y.decodeRelativePosition(encodedRelPos)
+const pos = Y.createAbsolutePositionFromRelativePosition(parsedRelPos, remoteDoc)
+pos.type === remoteytext // => true
+pos.index === 2 // => true
+```
+
+
+ Y.createRelativePositionFromTypeIndex(Uint8Array|Y.Type, number)
+
+ Y.createAbsolutePositionFromRelativePosition(RelativePosition, Y.Doc)
+
+ Y.encodeRelativePosition(RelativePosition):Uint8Array
+
+ Y.decodeRelativePosition(Uint8Array):RelativePosition
+
+
+
+### Y.UndoManager
+
+Yjs ships with an Undo/Redo manager for selective undo/redo of of changes on a
+Yjs type. The changes can be optionally scoped to transaction origins.
+
+```js
+const ytext = doc.getArray('array')
+const undoManager = new Y.UndoManager(ytext)
+
+ytext.insert(0, 'abc')
+undoManager.undo()
+ytext.toString() // => ''
+undoManager.redo()
+ytext.toString() // => 'abc'
+```
+
+
+ constructor(scope:Y.AbstractType|Array<Y.AbstractType>,
+ [[{captureTimeout:number,trackedOrigins:Set<any>,deleteFilter:function(item):boolean}]])
+ - Accepts either single type as scope or an array of types.
+ undo()
+
+ redo()
+
+ stopCapturing()
+
+
+
+on('stack-item-added', { stackItem: { meta: Map<any,any> }, type: 'undo'
+| 'redo' })
+
+
+ -
+Register an event that is called when a
StackItem
is added to the
+undo- or the redo-stack.
+
+
+
+on('stack-item-popped', { stackItem: { meta: Map<any,any> }, type: 'undo'
+| 'redo' })
+
+
+ -
+Register an event that is called when a
StackItem
is popped from
+the undo- or the redo-stack.
+
+
+
+#### Example: Stop Capturing
+
+UndoManager merges Undo-StackItems if they are created within time-gap
+smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next
+StackItem won't be merged.
+
+```js
+// without stopCapturing
+ytext.insert(0, 'a')
+ytext.insert(1, 'b')
+um.undo()
+ytext.toString() // => '' (note that 'ab' was removed)
+// with stopCapturing
+ytext.insert(0, 'a')
+um.stopCapturing()
+ytext.insert(0, 'b')
+um.undo()
+ytext.toString() // => 'a' (note that only 'b' was removed)
+```
+
+#### Example: Specify tracked origins
+
+Every change on the shared document has an origin. If no origin was specified,
+it defaults to `null`. By specifying `trackedTransactionOrigins` you can
+selectively specify which changes should be tracked by `UndoManager`. The
+UndoManager instance is always added to `trackedTransactionOrigins`.
+
+```js
+class CustomBinding {}
+
+const ytext = doc.getArray('array')
+const undoManager = new Y.UndoManager(ytext, new Set([42, CustomBinding]))
+
+ytext.insert(0, 'abc')
+undoManager.undo()
+ytext.toString() // => 'abc' (does not track because origin `null` and not part
+ // of `trackedTransactionOrigins`)
+ytext.delete(0, 3) // revert change
+
+doc.transact(() => {
+ ytext.insert(0, 'abc')
+}, 42)
+undoManager.undo()
+ytext.toString() // => '' (tracked because origin is an instance of `trackedTransactionorigins`)
+
+doc.transact(() => {
+ ytext.insert(0, 'abc')
+}, 41)
+undoManager.undo()
+ytext.toString() // => '' (not tracked because 41 is not an instance of
+ // `trackedTransactionorigins`)
+ytext.delete(0, 3) // revert change
+
+doc.transact(() => {
+ ytext.insert(0, 'abc')
+}, new CustomBinding())
+undoManager.undo()
+ytext.toString() // => '' (tracked because origin is a `CustomBinding` and
+ // `CustomBinding` is in `trackedTransactionorigins`)
+```
+
+#### Example: Add additional information to the StackItems
+
+When undoing or redoing a previous action, it is often expected to restore
+additional meta information like the cursor location or the view on the
+document. You can assign meta-information to Undo-/Redo-StackItems.
+
+```js
+const ytext = doc.getArray('array')
+const undoManager = new Y.UndoManager(ytext, new Set([42, CustomBinding]))
+
+undoManager.on('stack-item-added', event => {
+ // save the current cursor location on the stack-item
+ event.stackItem.meta.set('cursor-location', getRelativeCursorLocation())
+})
+
+undoManager.on('stack-item-popped', event => {
+ // restore the current cursor location on the stack-item
+ restoreCursorLocation(event.stackItem.meta.get('cursor-location'))
+})
+```
+
+## Miscellaneous
+
+### Typescript Declarations
+
+Yjs has type descriptions. But until [this
+ticket](https://github.com/Microsoft/TypeScript/issues/7546) is fixed, this is
+how you can make use of Yjs type declarations.
+
+```json
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ },
+ "maxNodeModuleJsDepth": 5
+}
+```
+
+## Yjs CRDT Algorithm
+
+*Conflict-free replicated data types* (CRDT) for collaborative editing are an
+alternative approach to *operational transformation* (OT). A very simple
+differenciation between the two approaches is that OT attempts to transform
+index positions to ensure convergence (all clients end up with the same
+content), while CRDTs use mathematical models that usually do not involve index
+transformations, like linked lists. OT is currently the de-facto standard for
+shared editing on text. OT approaches that support shared editing without a
+central source of truth (a central server) require too much bookkeeping to be
+viable in practice. CRDTs are better suited for distributed systems, provide
+additional guarantees that the document can be synced with remote clients, and
+do not require a central source of truth.
+
+Yjs implements a modified version of the algorithm described in [this
+paper](https://www.researchgate.net/publication/310212186_Near_Real-Time_Peer-to-Peer_Shared_Editing_on_Extensible_Data_Types).
+I will eventually publish a paper that describes why this approach works so well
+in practice. Note: Since operations make up the document structure, we prefer
+the term *struct* now.
+
+CRDTs suitable for shared text editing suffer from the fact that they only grow
+in size. There are CRDTs that do not grow in size, but they do not have the
+characteristics that are benificial for shared text editing (like intention
+preservation). Yjs implements many improvements to the original algorithm that
+diminish the trade-off that the document only grows in size. We can't garbage
+collect deleted structs (tombstones) while ensuring a unique order of the
+structs. But we can 1. merge preceeding structs into a single struct to reduce
+the amount of meta information, 2. we can delete content from the struct if it
+is deleted, and 3. we can garbage collect tombstones if we don't care about the
+order of the structs anymore (e.g. if the parent was deleted).
+
+**Examples:**
+
+1. If a user inserts elements in sequence, the struct will be merged into a
+ single struct. E.g. `array.insert(0, ['a']), array.insert(0, ['b']);` is
+ first represented as two structs (`[{id: {client, clock: 0}, content: 'a'},
+ {id: {client, clock: 1}, content: 'b'}`) and then merged into a single
+ struct: `[{id: {client, clock: 0}, content: 'ab'}]`.
+2. When a struct that contains content (e.g. `ItemString`) is deleted, the
+ struct will be replaced with an `ItemDeleted` that does not contain content
+ anymore.
+3. When a type is deleted, all child elements are transformed to `GC` structs. A
+ `GC` struct only denotes the existence of a struct and that it is deleted.
+ `GC` structs can always be merged with other `GC` structs if the id's are
+ adjacent.
+
+Especially when working on structured content (e.g. shared editing on
+ProseMirror), these improvements yield very good results when
+[benchmarking](https://github.com/dmonad/crdt-benchmarks) random document edits.
+In practice they show even better results, because users usually edit text in
+sequence, resulting in structs that can easily be merged. The benchmarks show
+that even in the worst case scenario that a user edits text from right to left,
+Yjs achieves good performance even for huge documents.
+
+### State Vector
+
+Yjs has the ability to exchange only the differences when syncing two clients.
+We use lamport timestamps to identify structs and to track in which order a
+client created them. Each struct has an `struct.id = { client: number, clock:
+number}` that uniquely identifies a struct. We define the next expected `clock`
+by each client as the *state vector*. This data structure is similar to the
+[version vectors](https://en.wikipedia.org/wiki/Version_vector) data structure.
+But we use state vectors only to describe the state of the local document, so we
+can compute the missing struct of the remote client. We do not use it to track
+causality.
+
+## License and Author
+
+Yjs and all related projects are [**MIT licensed**](./LICENSE).
+
+Yjs is based on my research as a student at the [RWTH
+i5](http://dbis.rwth-aachen.de/). Now I am working on Yjs in my spare time.
+
+Fund this project by donating on [Patreon](https://www.patreon.com/dmonad) or
+hiring [me](https://github.com/dmonad) for professional support.
diff --git a/README.v12.md b/README.v12.md
new file mode 100644
index 00000000..f750f721
--- /dev/null
+++ b/README.v12.md
@@ -0,0 +1,305 @@
+
+# 
+
+Yjs is a framework for offline-first p2p shared editing on structured data like
+text, richtext, json, or XML. It is fairly easy to get started, as Yjs hides
+most of the complexity of concurrent editing. For additional information, demos,
+and tutorials visit [y-js.org](http://y-js.org/).
+
+:warning: Checkout the [v13 docs](./README.md) for the upcoming release :warning:
+
+### Extensions
+Yjs only knows how to resolve conflicts on shared data. You have to choose a ..
+
+* *Connector* - a communication protocol that propagates changes to the clients
+* *Database* - a database to store your changes
+* one or more *Types* - that represent the shared data
+
+Connectors, Databases, and Types are available as modules that extend Yjs. Here
+is a list of the modules we know of:
+
+##### Connectors
+
+|Name | Description |
+|----------------|-----------------------------------|
+|[webrtc](https://github.com/y-js/y-webrtc) | Propagate updates Browser2Browser via WebRTC|
+|[websockets](https://github.com/y-js/y-websockets-client) | Set up [a central server](https://github.com/y-js/y-websockets-client), and connect to it via websockets |
+|[xmpp](https://github.com/y-js/y-xmpp) | Propagate updates in a XMPP multi-user-chat room ([XEP-0045](http://xmpp.org/extensions/xep-0045.html))|
+|[ipfs](https://github.com/ipfs-labs/y-ipfs-connector) | Connector for the [Interplanetary File System](https://ipfs.io/)!|
+|[test](https://github.com/y-js/y-test) | A Connector for testing purposes. It is designed to simulate delays that happen in worst case scenarios|
+
+##### Database adapters
+
+|Name | Description |
+|----------------|-----------------------------------|
+|[memory](https://github.com/y-js/y-memory) | In-memory storage. |
+|[indexeddb](https://github.com/y-js/y-indexeddb) | Offline storage for the browser |
+|[leveldb](https://github.com/y-js/y-leveldb) | Persistent storage for node apps |
+
+##### Types
+
+| Name | Description |
+|----------|-------------------|
+|[map](https://github.com/y-js/y-map) | A shared Map implementation. Maps from text to any stringify-able object |
+|[array](https://github.com/y-js/y-array) | A shared Array implementation |
+|[xml](https://github.com/y-js/y-xml) | An implementation of the DOM. You can create a two way binding to Browser DOM objects |
+|[text](https://github.com/y-js/y-text) | Collaborate on text. Supports two way binding to the [Ace Editor](https://ace.c9.io), [CodeMirror](https://codemirror.net/), [Monaco](https://github.com/Microsoft/monaco-editor), textareas, input elements, and HTML elements (e.g. <*h1*>, or <*p*>) |
+|[richtext](https://github.com/y-js/y-richtext) | Collaborate on rich text. Supports two way binding to the [Quill Rich Text Editor](http://quilljs.com/)|
+
+##### Other
+
+| Name | Description |
+|-----------|-------------------|
+|[y-element](http://y-js.org/y-element/) | Yjs Polymer Element |
+
+## Use it!
+Install Yjs, and its modules with [bower](http://bower.io/), or
+[npm](https://www.npmjs.org/package/yjs).
+
+### Bower
+
+```
+bower install --save yjs y-array % add all y-* modules you want to use
+```
+You only need to include the `y.js` file. Yjs is able to automatically require
+missing modules.
+```
+
+```
+
+### CDN
+
+```
+
+
+
+
+
+
+// ..
+// do the same for all modules you want to use
+```
+
+### Npm
+
+```
+npm install --save yjs % add all y-* modules you want to use
+```
+
+If you don't include via script tag, you have to explicitly include all modules!
+(Same goes for other module systems)
+```
+var Y = require('yjs')
+require('y-array')(Y) // add the y-array type to Yjs
+require('y-websockets-client')(Y)
+require('y-memory')(Y)
+require('y-map')(Y)
+require('y-text')(Y)
+// ..
+// do the same for all modules you want to use
+```
+
+### ES6 Syntax
+
+```
+import Y from 'yjs'
+import yArray from 'y-array'
+import yWebsocketsClient from 'y-webrtc'
+import yMemory from 'y-memory'
+import yMap from 'y-map'
+import yText from 'y-text'
+// ..
+Y.extend(yArray, yWebsocketsClient, yMemory, yArray, yMap, yText /*, .. */)
+```
+
+# Text editing example
+
+Install dependencies
+```
+bower i yjs y-memory y-webrtc y-array y-text
+```
+
+Here is a simple example of a shared textarea
+```HTML
+
+
+
+
+
+
+
+
+
+```
+
+## Get Help & Give Help
+There are some friendly people on [](https://gitter.im/y-js/yjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) who are eager to help, and answer questions. Please join!
+
+Report _any_ issues to the
+[Github issue page](https://github.com/y-js/yjs/issues)! I try to fix them very
+soon, if possible.
+
+# API
+
+### Y(options)
+* Y.extend(module1, module2, ..)
+ * Add extensions to Y
+ * `Y.extend(require('y-webrtc'))` has the same semantics as
+ `require('y-webrtc')(Y)`
+* options.db
+ * Will be forwarded to the database adapter. Specify the database adaper on
+ `options.db.name`.
+ * Have a look at the used database adapter repository to see all available
+ options.
+* options.connector
+ * Will be forwarded to the connector adapter. Specify the connector adaper on
+ `options.connector.name`.
+ * All our connectors implement a `room` property. Clients that specify the
+ same room share the same data.
+ * All of our connectors specify an `url` property that defines the connection
+ endpoint of the used connector.
+ * All of our connectors also have a default connection endpoint that you can
+ use for development.
+ * Set `options.connector.generateUserId = true` in order to genenerate a
+ userid, instead of receiving one from the server. This way the `Y(..)` is
+ immediately going to be resolved, without waiting for any confirmation from
+ the server. Use with caution.
+ * Have a look at the used connector repository to see all available options.
+ * *Only if you know what you are doing:* Set
+ `options.connector.preferUntransformed = true` in order receive the shared
+ data untransformed. This is very efficient as the database content is simply
+ copied to this client. This does only work if this client receives content
+ from only one client.
+* options.sourceDir (browser only)
+ * Path where all y-* modules are stored
+ * Defaults to `/bower_components`
+ * Not required when running on `nodejs` / `iojs`
+ * When using nodejs you need to manually extend Yjs:
+```
+var Y = require('yjs')
+// you have to require a db, connector, and *all* types you use!
+require('y-memory')(Y)
+require('y-webrtc')(Y)
+require('y-map')(Y)
+// ..
+```
+* options.share
+ * Specify on `options.share[arbitraryName]` types that are shared among all
+ users.
+ * E.g. Specify `options.share[arbitraryName] = 'Array'` to require y-array and
+ create an y-array type on `y.share[arbitraryName]`.
+ * If userA doesn't specify `options.share[arbitraryName]`, it won't be
+ available for userA.
+ * If userB specifies `options.share[arbitraryName]`, it still won't be
+ available for userA. But all the updates are send from userB to userA.
+ * In contrast to y-map, types on `y.share.*` cannot be overwritten or deleted.
+ Instead, they are merged among all users. This feature is only available on
+ `y.share.*`
+ * Weird behavior: It is supported that two users specify different types with
+ the same property name.
+ E.g. userA specifies `options.share.x = 'Array'`, and userB specifies
+ `options.share.x = 'Text'`. But they only share data if they specified the
+ same type with the same property name
+* options.type (browser only)
+ * Array of modules that Yjs needs to require, before instantiating a shared
+ type.
+ * By default Yjs requires the specified database adapter, the specified
+ connector, and all modules that are used in `options.share.*`
+ * Put all types here that you intend to use, but are not used in y.share.*
+
+### Instantiated Y object (y)
+`Y(options)` returns a promise that is fulfilled when..
+
+* All modules are loaded
+ * The specified database adapter is loaded
+ * The specified connector is loaded
+ * All types are included
+* The connector is initialized, and a unique user id is set (received from the
+ server)
+ * Note: When using y-indexeddb, a retrieved user id is stored on `localStorage`
+
+The promise returns an instance of Y. We denote it with a lower case `y`.
+
+* y.share.*
+ * Instances of the types you specified on options.share.*
+ * y.share.* can only be defined once when you instantiate Y!
+* y.connector is an instance of Y.AbstractConnector
+* y.connector.onUserEvent(function (event) {..})
+ * Observe user events (event.action is either 'userLeft' or 'userJoined')
+* y.connector.whenSynced(listener)
+ * `listener` is executed when y synced with at least one user.
+ * `listener` is not called when no other user is in the same room.
+ * y-websockets-client aways waits to sync with the server
+* y.connector.disconnect()
+ * Force to disconnect this instance from the other instances
+* y.connector.connect()
+ * Try to reconnect to the other instances (needs to be supported by the
+ connector)
+ * Not supported by y-xmpp
+* y.close()
+ * Destroy this object.
+ * Destroys all types (they will throw weird errors if you still use them)
+ * Disconnects from the other instances (via connector)
+ * Returns a promise
+* y.destroy()
+ * calls y.close()
+ * Removes all data from the database
+ * Returns a promise
+* y.db.stopGarbageCollector()
+ * Stop the garbage collector. Call y.db.garbageCollect() to continue garbage
+ collection
+* y.db.gc :: Boolean
+ * Whether gc is turned on
+* y.db.gcTimeout :: Number (defaults to 50000 ms)
+ * Time interval between two garbage collect cycles
+ * It is required that all instances exchanged all messages after two garbage
+ collect cycles (after 100000 ms per default)
+* y.db.userId :: String
+ * The used user id for this client. **Never overwrite this**
+
+### Logging
+Yjs uses [debug](https://github.com/visionmedia/debug) for logging. The flag
+`y*` enables logging for all y-* components. You can selectively remove
+components you are not interested in: E.g. The flag `y*,-y:connector-message`
+will not log the long `y:connector-message` messages.
+
+##### Enable logging in Node.js
+```sh
+DEBUG=y* node app.js
+```
+
+Remove the colors in order to log to a file:
+```sh
+DEBUG_COLORS=0 DEBUG=y* node app.js > log
+```
+
+##### Enable logging in the browser
+```js
+localStorage.debug = 'y*'
+```
+
+## License
+Yjs is licensed under the [MIT License](./LICENSE).
diff --git a/README.v13.md b/README.v13.md
deleted file mode 100644
index ad5becef..00000000
--- a/README.v13.md
+++ /dev/null
@@ -1,874 +0,0 @@
-
-# 
-
-> A CRDT framework with a powerful abstraction of shared data
-
-Yjs is a [CRDT implementation](#Yjs-CRDT-Algorithm) that exposes its internal
-data structure as *shared types*. Shared types are common data types like `Map`
-or `Array` with superpowers: changes are automatically distributed to other
-peers and merged without merge conflicts.
-
-Yjs is **network agnostic** (p2p!), supports many existing **rich text
-editors**, **offline editing**, **version snapshots**, **undo/redo** and
-**shared cursors**. It scales well with an unlimited number of users and is well
-suited for even large documents.
-
-* Chat: [https://gitter.im/y-js/yjs](https://gitter.im/y-js/yjs)
-* Demos: [https://github.com/y-js/yjs-demos](https://github.com/y-js/yjs-demos)
-* Benchmarks: [https://github.com/dmonad/crdt-benchmarks](https://github.com/dmonad/crdt-benchmarks)
-
-## Table of Contents
-
-* [Overview](#Overview)
- * [Bindings](#Bindings)
- * [Providers](#Providers)
-* [Getting Started](#Getting-Started)
-* [API](#API)
- * [Shared Types](#Shared-Types)
- * [Y.Doc](#YDoc)
- * [Document Updates](#Document-Updates)
- * [Relative Positions](#Relative-Positions)
- * [Y.UndoManager](#YUndoManager)
-* [Miscellaneous](#Miscellaneous)
- * [Typescript Declarations](#Typescript-Declarations)
-* [Yjs CRDT Algorithm](#Yjs-CRDT-Algorithm)
-* [Evaluation](#Evaluation)
- * [Existing shared editing libraries](#Exisisting-Javascript-Libraries)
- * [CRDT Algorithms](#CRDT-Algorithms)
- * [Comparison of CRDT with OT](#Comparing-CRDT-with-OT)
- * [Comparison of CRDT Algorithms](#Comparing-CRDT-Algorithms)
- * [Comparison of Yjs with other Implementations](#Comparing-Yjs-with-other-Implementations)
-* [License and Author](#License-and-Author)
-
-## Overview
-
-This repository contains a collection of shared types that can be observed for
-changes and manipulated concurrently. Network functionality and two-way-bindings
-are implemented in separate modules.
-
-### Bindings
-
-| Name | Cursors | Binding | Demo |
-|---|:-:|---|---|
-| [ProseMirror](https://prosemirror.net/) | ✔ | [y-prosemirror](http://github.com/y-js/y-prosemirror) | [demo](https://yjs-demos.now.sh/prosemirror/) |
-| [Quill](https://quilljs.com/) | | [y-quill](http://github.com/y-js/y-quill) | [demo](https://yjs-demos.now.sh/quill/) |
-| [CodeMirror](https://codemirror.net/) | ✔ | [y-codemirror](http://github.com/y-js/y-codemirror) | [demo](https://yjs-demos.now.sh/codemirror/) |
-| [Monaco](https://microsoft.github.io/monaco-editor/) | ✔ | [y-monaco](http://github.com/y-js/y-monaco) | [demo](https://yjs-demos.now.sh/monaco/) |
-| [Ace](https://ace.c9.io/) | | [y-ace](http://github.com/y-js/y-ace) | [demo](https://yjs-demos.now.sh/ace/) |
-| [Textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) | | [y-textarea](http://github.com/y-js/y-textarea) | [demo](https://yjs-demos.now.sh/textarea/) |
-| [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) | | [y-dom](http://github.com/y-js/y-dom) | [demo](https://yjs-demos.now.sh/dom/) |
-
-### Providers
-
-Setting up the communication between clients, managing awareness information,
-and storing shared data for offline usage is quite a hassle. **Providers**
-manage all that for you and are the perfect starting point for your
-collaborative app.
-
-
- - y-websocket
- -
-A module that contains a simple websocket backend and a websocket client that
-connects to that backend. The backend can be extended to persist updates in a
-leveldb database.
-
- - y-mesh
- -
-[WIP] Creates a connected graph of webrtc connections with a high
-strength. It
-requires a signalling server that connects a client to the first peer. But after
-that the network manages itself. It is well suited for large and small networks.
-
- - y-dat
- -
-[WIP] Write document updates effinciently to the dat network using
-multifeed. Each client has
-an append-only log of CRDT local updates (hypercore). Multifeed manages and sync
-hypercores and y-dat listens to changes and applies them to the Yjs document.
-
-
-
-## Getting Started
-
-Install Yjs and a provider with your favorite package manager:
-
-```sh
-npm i yjs@13.0.0-82 y-websocket@1.0.0-3 y-textarea
-```
-
-Start the y-websocket server:
-
-```sh
-PORT=1234 node ./node_modules/y-websocket/bin/server.js
-```
-
-### Example: Textarea Binding
-
-This is a complete example on how to create a connection to a
-[y-websocket](https://github.com/y-js/y-websocket) server instance, sync the
-shared document to all clients in a *room*, and bind a Y.Text type to a dom
-textarea. All changes to the textarea are automatically shared with everyone in
-the same room.
-
-```js
-import * as Y from 'yjs'
-import { WebsocketProvider } from 'y-websocket'
-import { TextareaBinding } from 'y-textarea'
-
-const doc = Y.Doc()
-const provider = new WebsocketProvider('ws://localhost:1234', 'roomname', doc)
-
-// Define a shared type on the document.
-const ytext = doc.getText('my resume')
-
-// use data bindings to bind types to editors
-const binding = new TextareaBinding(ytext, document.querySelector('textarea'))
-```
-
-#### Example: Observe types
-
-```js
-const yarray = doc.getArray('my-array')
-yarray.observe(event => {
- console.log('yarray was modified')
-})
-// every time a local or remote client modifies yarray, the observer is called
-yarray.insert(0, ['val']) // => "yarray was modified"
-```
-
-#### Example: Nest types
-
-Remember, shared types are just plain old data types. The only limitation is
-that a shared type must exist only once in the shared document.
-
-```js
-const ymap = doc.getMap('map')
-const foodArray = new Y.Array()
-foodArray.insert(0, ['apple', 'banana'])
-ymap.set('food', foodArray)
-ymap.get('food') === foodArray // => true
-ymap.set('fruit', foodArray) // => Error! foodArray is already defined
-```
-
-Now you understand how types are defined on a shared document. Next you can jump
-to the [demo repository](https://github.com/y-js/yjs-demos) or continue reading
-the API docs.
-
-## API
-
-```js
-import * as Y from 'yjs'
-```
-
-### Shared Types
-
-
- Y.Array
-
-
-A shareable Array-like type that supports efficient insert/delete of elements
-at any position. Internally it uses a linked list of Arrays that is split when
-necessary.
-
- const yarray = new Y.Array()
-
- insert(index:number, content:Array<object|boolean|Array|string|number|Uint8Array|Y.Type>)
- -
-Insert content at index. Note that content is an array of elements.
-I.e.
array.insert(0, [1]
splices the list and inserts 1 at
-position 0.
-
- push(Array<Object|boolean|Array|string|number|Uint8Array|Y.Type>)
-
- delete(index:number, length:number)
-
- get(index:number)
-
- length:number
-
-
-
-forEach(function(value:object|boolean|Array|string|number|Uint8Array|Y.Type,
- index:number, array: Y.Array))
-
-
-
- map(function(T, number, YArray):M):Array<M>
-
- toArray():Array<object|boolean|Array|string|number|Uint8Array|Y.Type>
- - Copies the content of this YArray to a new Array.
- toJSON():Array<Object|boolean|Array|string|number>
- -
-Copies the content of this YArray to a new Array. It transforms all child types
-to JSON using their
toJSON
method.
-
- [Symbol.Iterator]
- -
- Returns an YArray Iterator that contains the values for each index in the array.
-
for (let value of yarray) { .. }
-
- observe(function(YArrayEvent, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type is modified. In the case this type is modified in the event listener,
-the event listener will be called again after the current event listener returns.
-
- unobserve(function(YArrayEvent, Transaction):void)
- -
- Removes an
observe
event listener from this type.
-
- observeDeep(function(Array<YEvent>, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type or any of its children is modified. In the case this type is modified
-in the event listener, the event listener will be called again after the current
-event listener returns. The event listener receives all Events created by itself
-or any of its children.
-
- unobserveDeep(function(Array<YEvent>, Transaction):void)
- -
- Removes an
observeDeep
event listener from this type.
-
-
-
-
- Y.Map
-
-
- A shareable Map type.
-
- const ymap = new Y.Map()
-
- get(key:string):object|boolean|string|number|Uint8Array|Y.Type
-
- set(key:string, value:object|boolean|string|number|Uint8Array|Y.Type)
-
- delete(key:string)
-
- has(key:string):boolean
-
- get(index:number)
-
- toJSON():Object<string, Object|boolean|Array|string|number|Uint8Array>
- -
-Copies the
[key,value]
pairs of this YMap to a new Object.It
-transforms all child types to JSON using their toJSON
method.
-
- forEach(function(key:string,value:object|boolean|Array|string|number|Uint8Array|Y.Type))
- -
- Execute the provided function once for every key-value pair.
-
- [Symbol.Iterator]
- -
- Returns an Iterator of
[key, value]
pairs.
- for (let [key, value] of ymap) { .. }
-
- entries()
- -
- Returns an Iterator of
[key, value]
pairs.
-
- values()
- -
- Returns an Iterator of all values.
-
- keys()
- -
- Returns an Iterator of all keys.
-
- observe(function(YMapEvent, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type is modified. In the case this type is modified in the event listener,
-the event listener will be called again after the current event listener returns.
-
- unobserve(function(YMapEvent, Transaction):void)
- -
- Removes an
observe
event listener from this type.
-
- observeDeep(function(Array<YEvent>, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type or any of its children is modified. In the case this type is modified
-in the event listener, the event listener will be called again after the current
-event listener returns. The event listener receives all Events created by itself
-or any of its children.
-
- unobserveDeep(function(Array<YEvent>, Transaction):void)
- -
- Removes an
observeDeep
event listener from this type.
-
-
-
-
-
- Y.Text
-
-
-A shareable type that is optimized for shared editing on text. It allows to
-assign properties to ranges in the text. This makes it possible to implement
-rich-text bindings to this type.
-
-
-This type can also be transformed to the
-delta format. Similarly the
-YTextEvents compute changes as deltas.
-
- const ytext = new Y.Text()
-
- insert(index:number, content:string, [formattingAttributes:Object<string,string>])
- -
- Insert a string at index and assign formatting attributes to it.
-
ytext.insert(0, 'bold text', { bold: true })
-
- delete(index:number, length:number)
-
- format(index:number, length:number, formattingAttributes:Object<string,string>)
- - Assign formatting attributes to a range in the text
- applyDelta(delta)
- - See Quill Delta
- length:number
-
- toString():string
- - Transforms this type, without formatting options, into a string.
- toJSON():string
- - See
toString
- toDelta():Delta
- -
-Transforms this type to a Quill Delta
-
- observe(function(YTextEvent, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type is modified. In the case this type is modified in the event listener,
-the event listener will be called again after the current event listener returns.
-
- unobserve(function(YTextEvent, Transaction):void)
- -
- Removes an
observe
event listener from this type.
-
- observeDeep(function(Array<YEvent>, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type or any of its children is modified. In the case this type is modified
-in the event listener, the event listener will be called again after the current
-event listener returns. The event listener receives all Events created by itself
-or any of its children.
-
- unobserveDeep(function(Array<YEvent>, Transaction):void)
- -
- Removes an
observeDeep
event listener from this type.
-
-
-
-
-
- YXmlFragment
-
-
- A container that holds an Array of Y.XmlElements.
-
- const yxml = new Y.XmlFragment()
-
- insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)
-
- delete(index:number, length:number)
-
- get(index:number)
-
- length:number
-
- toArray():Array<Y.XmlElement|Y.XmlText>
- - Copies the children to a new Array.
- toDOM():DocumentFragment
- - Transforms this type and all children to new DOM elements.
- toString():string
- - Get the XML serialization of all descendants.
- toJSON():string
- - See
toString
.
- observe(function(YXmlEvent, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type is modified. In the case this type is modified in the event listener,
-the event listener will be called again after the current event listener returns.
-
- unobserve(function(YXmlEvent, Transaction):void)
- -
- Removes an
observe
event listener from this type.
-
- observeDeep(function(Array<YEvent>, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type or any of its children is modified. In the case this type is modified
-in the event listener, the event listener will be called again after the current
-event listener returns. The event listener receives all Events created by itself
-or any of its children.
-
- unobserveDeep(function(Array<YEvent>, Transaction):void)
- -
- Removes an
observeDeep
event listener from this type.
-
-
-
-
-
- Y.XmlElement
-
-
-A shareable type that represents an XML Element. It has a nodeName
,
-attributes, and a list of children. But it makes no effort to validate its
-content and be actually XML compliant.
-
- const yxml = new Y.XmlElement()
-
- insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)
-
- delete(index:number, length:number)
-
- get(index:number)
-
- length:number
-
- setAttribute(attributeName:string, attributeValue:string)
-
- removeAttribute(attributeName:string)
-
- getAttribute(attributeName:string):string
-
- getAttributes(attributeName:string):Object<string,string>
-
- toArray():Array<Y.XmlElement|Y.XmlText>
- - Copies the children to a new Array.
- toDOM():Element
- - Transforms this type and all children to a new DOM element.
- toString():string
- - Get the XML serialization of all descendants.
- toJSON():string
- - See
toString
.
- observe(function(YXmlEvent, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every
-time this type is modified. In the case this type is modified in the event
-listener, the event listener will be called again after the current event
-listener returns.
-
- unobserve(function(YXmlEvent, Transaction):void)
- -
- Removes an
observe
event listener from this type.
-
- observeDeep(function(Array<YEvent>, Transaction):void)
- -
-Adds an event listener to this type that will be called synchronously every time
-this type or any of its children is modified. In the case this type is modified
-in the event listener, the event listener will be called again after the current
-event listener returns. The event listener receives all Events created by itself
-or any of its children.
-
- unobserveDeep(function(Array<YEvent>, Transaction):void)
- -
- Removes an
observeDeep
event listener from this type.
-
-
-
-
-### Y.Doc
-
-```js
-const doc = new Y.Doc()
-```
-
-
- clientID
- - A unique id that identifies this client. (readonly)
- transact(function(Transaction):void [, origin:any])
- -
-Every change on the shared document happens in a transaction. Observer calls and
-the
update
event are called after each transaction. You should
-bundle changes into a single transaction to reduce the amount of event
-calls. I.e. doc.transact(() => { yarray.insert(..); ymap.set(..) })
-triggers a single change event.
You can specify an optional origin
-parameter that is stored on transaction.origin
and
-on('update', (update, origin) => ..)
.
-
- get(string, Y.[TypeClass]):[Type]
- - Define a shared type.
- getArray(string):Y.Array
- - Define a shared Y.Array type. Is equivalent to
y.get(string, Y.Array)
.
- getMap(string):Y.Map
- - Define a shared Y.Map type. Is equivalent to
y.get(string, Y.Map)
.
- getXmlFragment(string):Y.XmlFragment
- - Define a shared Y.XmlFragment type. Is equivalent to
y.get(string, Y.XmlFragment)
.
- on(string, function)
- - Register an event listener on the shared type
- off(string, function)
- - Unregister an event listener from the shared type
-
-
-#### Y.Doc Events
-
-
- on('update', function(updateMessage:Uint8Array, origin:any, Y.Doc):void)
- -
-Listen to document updates. Document updates must be transmitted to all other
-peers. You can apply document updates in any order and multiple times.
-
- on('beforeTransaction', function(Y.Transaction, Y.Doc):void)
- - Emitted before each transaction.
- on('afterTransaction', function(Y.Transaction, Y.Doc):void)
- - Emitted after each transaction.
-
-
-### Document Updates
-
-Changes on the shared document are encoded into *document updates*. Document
-updates are *commutative* and *idempotent*. This means that they can be applied
-in any order and multiple times.
-
-#### Example: Listen to update events and apply them on remote client
-
-```js
-const doc1 = new Y.Doc()
-const doc2 = new Y.Doc()
-
-doc1.on('update', update => {
- Y.applyUpdate(doc2, update)
-})
-
-doc2.on('update', update => {
- Y.applyUpdate(doc1, update)
-})
-
-// All changes are also applied to the other document
-doc1.getArray('myarray').insert(0, ['Hello doc2, you got this?'])
-doc2.getArray('myarray').get(0) // => 'Hello doc2, you got this?'
-```
-
-Yjs internally maintains a [state vector](#State-Vector) that denotes the next
-expected clock from each client. In a different interpretation it holds the
-number of structs created by each client. When two clients sync, you can either
-exchange the complete document structure or only the differences by sending the
-state vector to compute the differences.
-
-#### Example: Sync two clients by exchanging the complete document structure
-
-```js
-const state1 = Y.encodeStateAsUpdate(ydoc1)
-const state2 = Y.encodeStateAsUpdate(ydoc2)
-Y.applyUpdate(ydoc1, state2)
-Y.applyUpdate(ydoc2, state1)
-```
-
-#### Example: Sync two clients by computing the differences
-
-This example shows how to sync two clients with the minimal amount of exchanged
-data by computing only the differences using the state vector of the remote
-client. Syncing clients using the state vector requires another roundtrip, but
-can safe a lot of bandwidth.
-
-```js
-const stateVector1 = Y.encodeStateVector(ydoc1)
-const stateVector2 = Y.encodeStateVector(ydoc2)
-const diff1 = Y.encodeStateAsUpdate(ydoc1, stateVector2)
-const diff2 = Y.encodeStateAsUpdate(ydoc2, stateVector1)
-Y.applyUpdate(ydoc1, diff2)
-Y.applyUpdate(ydoc2, diff1)
-```
-
-
- Y.applyUpdate(Y.Doc, update:Uint8Array, [transactionOrigin:any])
- -
-Apply a document update on the shared document. Optionally you can specify
-
transactionOrigin
that will be stored on
-transaction.origin
-and ydoc.on('update', (update, origin) => ..)
.
-
- Y.encodeStateAsUpdate(Y.Doc, [encodedTargetStateVector:Uint8Array]):Uint8Array
- -
-Encode the document state as a single update message that can be applied on the
-remote document. Optionally specify the target state vector to only write the
-differences to the update message.
-
- Y.encodeStateVector(Y.Doc):Uint8Array
- - Computes the state vector and encodes it into an Uint8Array.
-
-
-### Relative Positions
-
-> This API is not stable yet
-
-This feature is intended for managing selections / cursors. When working with
-other users that manipulate the shared document, you can't trust that an index
-position (an integer) will stay at the intended location. A *relative position*
-is fixated to an element in the shared document and is not affected by remote
-changes. I.e. given the document `"a|c"`, the relative position is attached to
-`c`. When a remote user modifies the document by inserting a character before
-the cursor, the cursor will stay attached to the character `c`. `insert(1,
-'x')("a|c") = "ax|c"`. When the *relative position* is set to the end of the
-document, it will stay attached to the end of the document.
-
-#### Example: Transform to RelativePosition and back
-
-```js
-const relPos = Y.createRelativePositionFromTypeIndex(ytext, 2)
-const pos = Y.createAbsolutePositionFromRelativePosition(relPos, doc)
-pos.type === ytext // => true
-pos.index === 2 // => true
-```
-
-#### Example: Send relative position to remote client (json)
-
-```js
-const relPos = Y.createRelativePositionFromTypeIndex(ytext, 2)
-const encodedRelPos = JSON.stringify(relPos)
-// send encodedRelPos to remote client..
-const parsedRelPos = JSON.parse(encodedRelPos)
-const pos = Y.createAbsolutePositionFromRelativePosition(parsedRelPos, remoteDoc)
-pos.type === remoteytext // => true
-pos.index === 2 // => true
-```
-
-#### Example: Send relative position to remote client (Uint8Array)
-
-```js
-const relPos = Y.createRelativePositionFromTypeIndex(ytext, 2)
-const encodedRelPos = Y.encodeRelativePosition(relPos)
-// send encodedRelPos to remote client..
-const parsedRelPos = Y.decodeRelativePosition(encodedRelPos)
-const pos = Y.createAbsolutePositionFromRelativePosition(parsedRelPos, remoteDoc)
-pos.type === remoteytext // => true
-pos.index === 2 // => true
-```
-
-
- Y.createRelativePositionFromTypeIndex(Uint8Array|Y.Type, number)
-
- Y.createAbsolutePositionFromRelativePosition(RelativePosition, Y.Doc)
-
- Y.encodeRelativePosition(RelativePosition):Uint8Array
-
- Y.decodeRelativePosition(Uint8Array):RelativePosition
-
-
-
-### Y.UndoManager
-
-Yjs ships with an Undo/Redo manager for selective undo/redo of of changes on a
-Yjs type. The changes can be optionally scoped to transaction origins.
-
-```js
-const ytext = doc.getArray('array')
-const undoManager = new Y.UndoManager(ytext)
-
-ytext.insert(0, 'abc')
-undoManager.undo()
-ytext.toString() // => ''
-undoManager.redo()
-ytext.toString() // => 'abc'
-```
-
-
- constructor(scope:Y.AbstractType|Array<Y.AbstractType>,
- [[{captureTimeout:number,trackedOrigins:Set<any>,deleteFilter:function(item):boolean}]])
- - Accepts either single type as scope or an array of types.
- undo()
-
- redo()
-
- stopCapturing()
-
-
-
-on('stack-item-added', { stackItem: { meta: Map<any,any> }, type: 'undo'
-| 'redo' })
-
-
- -
-Register an event that is called when a
StackItem
is added to the
-undo- or the redo-stack.
-
-
-
-on('stack-item-popped', { stackItem: { meta: Map<any,any> }, type: 'undo'
-| 'redo' })
-
-
- -
-Register an event that is called when a
StackItem
is popped from
-the undo- or the redo-stack.
-
-
-
-#### Example: Stop Capturing
-
-UndoManager merges Undo-StackItems if they are created within time-gap
-smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next
-StackItem won't be merged.
-
-```js
-// without stopCapturing
-ytext.insert(0, 'a')
-ytext.insert(1, 'b')
-um.undo()
-ytext.toString() // => '' (note that 'ab' was removed)
-// with stopCapturing
-ytext.insert(0, 'a')
-um.stopCapturing()
-ytext.insert(0, 'b')
-um.undo()
-ytext.toString() // => 'a' (note that only 'b' was removed)
-```
-
-#### Example: Specify tracked origins
-
-Every change on the shared document has an origin. If no origin was specified,
-it defaults to `null`. By specifying `trackedTransactionOrigins` you can
-selectively specify which changes should be tracked by `UndoManager`. The
-UndoManager instance is always added to `trackedTransactionOrigins`.
-
-```js
-class CustomBinding {}
-
-const ytext = doc.getArray('array')
-const undoManager = new Y.UndoManager(ytext, new Set([42, CustomBinding]))
-
-ytext.insert(0, 'abc')
-undoManager.undo()
-ytext.toString() // => 'abc' (does not track because origin `null` and not part
- // of `trackedTransactionOrigins`)
-ytext.delete(0, 3) // revert change
-
-doc.transact(() => {
- ytext.insert(0, 'abc')
-}, 42)
-undoManager.undo()
-ytext.toString() // => '' (tracked because origin is an instance of `trackedTransactionorigins`)
-
-doc.transact(() => {
- ytext.insert(0, 'abc')
-}, 41)
-undoManager.undo()
-ytext.toString() // => '' (not tracked because 41 is not an instance of
- // `trackedTransactionorigins`)
-ytext.delete(0, 3) // revert change
-
-doc.transact(() => {
- ytext.insert(0, 'abc')
-}, new CustomBinding())
-undoManager.undo()
-ytext.toString() // => '' (tracked because origin is a `CustomBinding` and
- // `CustomBinding` is in `trackedTransactionorigins`)
-```
-
-#### Example: Add additional information to the StackItems
-
-When undoing or redoing a previous action, it is often expected to restore
-additional meta information like the cursor location or the view on the
-document. You can assign meta-information to Undo-/Redo-StackItems.
-
-```js
-const ytext = doc.getArray('array')
-const undoManager = new Y.UndoManager(ytext, new Set([42, CustomBinding]))
-
-undoManager.on('stack-item-added', event => {
- // save the current cursor location on the stack-item
- event.stackItem.meta.set('cursor-location', getRelativeCursorLocation())
-})
-
-undoManager.on('stack-item-popped', event => {
- // restore the current cursor location on the stack-item
- restoreCursorLocation(event.stackItem.meta.get('cursor-location'))
-})
-```
-
-## Miscellaneous
-
-### Typescript Declarations
-
-Yjs has type descriptions. But until [this
-ticket](https://github.com/Microsoft/TypeScript/issues/7546) is fixed, this is
-how you can make use of Yjs type declarations.
-
-```json
-{
- "compilerOptions": {
- "allowJs": true,
- "checkJs": true,
- },
- "maxNodeModuleJsDepth": 5
-}
-```
-
-## Yjs CRDT Algorithm
-
-*Conflict-free replicated data types* (CRDT) for collaborative editing are an
-alternative approach to *operational transformation* (OT). A very simple
-differenciation between the two approaches is that OT attempts to transform
-index positions to ensure convergence (all clients end up with the same
-content), while CRDTs use mathematical models that usually do not involve index
-transformations, like linked lists. OT is currently the de-facto standard for
-shared editing on text. OT approaches that support shared editing without a
-central source of truth (a central server) require too much bookkeeping to be
-viable in practice. CRDTs are better suited for distributed systems, provide
-additional guarantees that the document can be synced with remote clients, and
-do not require a central source of truth.
-
-Yjs implements a modified version of the algorithm described in [this
-paper](https://www.researchgate.net/publication/310212186_Near_Real-Time_Peer-to-Peer_Shared_Editing_on_Extensible_Data_Types).
-I will eventually publish a paper that describes why this approach works so well
-in practice. Note: Since operations make up the document structure, we prefer
-the term *struct* now.
-
-CRDTs suitable for shared text editing suffer from the fact that they only grow
-in size. There are CRDTs that do not grow in size, but they do not have the
-characteristics that are benificial for shared text editing (like intention
-preservation). Yjs implements many improvements to the original algorithm that
-diminish the trade-off that the document only grows in size. We can't garbage
-collect deleted structs (tombstones) while ensuring a unique order of the
-structs. But we can 1. merge preceeding structs into a single struct to reduce
-the amount of meta information, 2. we can delete content from the struct if it
-is deleted, and 3. we can garbage collect tombstones if we don't care about the
-order of the structs anymore (e.g. if the parent was deleted).
-
-**Examples:**
-
-1. If a user inserts elements in sequence, the struct will be merged into a
- single struct. E.g. `array.insert(0, ['a']), array.insert(0, ['b']);` is
- first represented as two structs (`[{id: {client, clock: 0}, content: 'a'},
- {id: {client, clock: 1}, content: 'b'}`) and then merged into a single
- struct: `[{id: {client, clock: 0}, content: 'ab'}]`.
-2. When a struct that contains content (e.g. `ItemString`) is deleted, the
- struct will be replaced with an `ItemDeleted` that does not contain content
- anymore.
-3. When a type is deleted, all child elements are transformed to `GC` structs. A
- `GC` struct only denotes the existence of a struct and that it is deleted.
- `GC` structs can always be merged with other `GC` structs if the id's are
- adjacent.
-
-Especially when working on structured content (e.g. shared editing on
-ProseMirror), these improvements yield very good results when
-[benchmarking](https://github.com/dmonad/crdt-benchmarks) random document edits.
-In practice they show even better results, because users usually edit text in
-sequence, resulting in structs that can easily be merged. The benchmarks show
-that even in the worst case scenario that a user edits text from right to left,
-Yjs achieves good performance even for huge documents.
-
-### State Vector
-
-Yjs has the ability to exchange only the differences when syncing two clients.
-We use lamport timestamps to identify structs and to track in which order a
-client created them. Each struct has an `struct.id = { client: number, clock:
-number}` that uniquely identifies a struct. We define the next expected `clock`
-by each client as the *state vector*. This data structure is similar to the
-[version vectors](https://en.wikipedia.org/wiki/Version_vector) data structure.
-But we use state vectors only to describe the state of the local document, so we
-can compute the missing struct of the remote client. We do not use it to track
-causality.
-
-## License and Author
-
-Yjs and all related projects are [**MIT licensed**](./LICENSE).
-
-Yjs is based on my research as a student at the [RWTH
-i5](http://dbis.rwth-aachen.de/). Now I am working on Yjs in my spare time.
-
-Fund this project by donating on [Patreon](https://www.patreon.com/dmonad) or
-hiring [me](https://github.com/dmonad) for professional support.
diff --git a/package.json b/package.json
index 0f318536..941d2f9a 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,8 @@
"test-exhaustive": "npm run lint && npm run dist && node ./dist/tests.js --repitition-time 10000",
"dist": "rm -rf dist && rollup -c",
"watch": "rollup -wc",
- "lint": "markdownlint README.v13.md && standard && tsc",
- "docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.v13.md --package ./package.json || true",
+ "lint": "markdownlint README.md && standard && tsc",
+ "docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.md --package ./package.json || true",
"serve-docs": "npm run docs && serve ./docs/",
"preversion": "npm run lint && PRODUCTION=1 npm run dist && npm run docs && node ./dist/tests.js --repitition-time 1000",
"postversion": "git push && git push --tags",
@@ -38,20 +38,20 @@
},
"repository": {
"type": "git",
- "url": "https://github.com/y-js/yjs.git"
+ "url": "https://github.com/yjs/yjs.git"
},
"keywords": [
"crdt"
],
"author": "Kevin Jahns",
- "email": "kevin.jahns@rwth-aachen.de",
+ "email": "kevin.jahns@protonmail.com",
"license": "MIT",
"bugs": {
- "url": "https://github.com/y-js/yjs/issues"
+ "url": "https://github.com/yjs/yjs/issues"
},
- "homepage": "http://y-js.org",
+ "homepage": "https://yjs.dev",
"dependencies": {
- "lib0": "0.0.6"
+ "lib0": "^0.1.0"
},
"devDependencies": {
"concurrently": "^3.6.1",
diff --git a/tests/y-array.tests.js b/tests/y-array.tests.js
index 953e862f..36804780 100644
--- a/tests/y-array.tests.js
+++ b/tests/y-array.tests.js
@@ -238,7 +238,7 @@ export const testInsertAndDeleteEventsForTypes2 = tc => {
}
/**
- * This issue has been reported here https://github.com/y-js/yjs/issues/155
+ * This issue has been reported here https://github.com/yjs/yjs/issues/155
* @param {t.TestCase} tc
*/
export const testNewChildDoesNotEmitEventInTransaction = tc => {