Compare commits

..

45 Commits

Author SHA1 Message Date
Kevin Jahns
013b2b6886 13.6.9 2023-11-20 12:56:27 +01:00
Kevin Jahns
c2e7076400 add iterator type checks 2023-11-20 12:53:58 +01:00
Kevin Jahns
289ff16f66 Merge pull request #590 from haines/map-iterator-types
Fix typing of `Y.Map` iterators
2023-11-20 12:40:42 +01:00
Kevin Jahns
9f8c55885f update github workflow 2023-11-20 12:46:12 +01:00
Kevin Jahns
5861876e6f Merge pull request #587 from SamyPesse/patch-1
Only emit "load" when sync is set to true
2023-11-20 12:36:25 +01:00
Kevin Jahns
37236fa31f update license. closes #471 2023-11-20 12:39:51 +01:00
Kevin Jahns
b32f5434f1 Merge pull request #557 from tonny008/patch-1
fix comment in doc
2023-11-20 12:28:12 +01:00
Kevin Jahns
61e84c5f99 Merge pull request #579 from jsejcksn/fix/docs/readme
docs(readme): fix typo
2023-11-20 12:27:12 +01:00
Kevin Jahns
b531438369 Merge pull request #595 from himself65/expose-content-doc
feat: expose some types
2023-11-20 12:22:46 +01:00
Kevin Jahns
ac49dbcbd8 Merge pull request #583 from nikgraf/improve-docs
add documentation on V2 events
2023-11-14 20:30:04 +01:00
Kevin Jahns
da8ca5168e Merge pull request #596 from siddug/patch-1
Adding www.btw.so to the platforms who use Yjs
2023-11-11 11:16:19 +01:00
Siddhartha Gunti
a3d69bba72 Adding www.btw.so to the platforms who use Yjs
Repo here: https://github.com/btw-so/btw
2023-11-07 18:54:22 +05:30
Alex Yang
e5f286cf89 feat: expose some types 2023-11-06 16:51:23 -06:00
Kevin Jahns
c14a8d70f1 Merge pull request #593 from himself65/remove-unused-check
fix: remove unused if-statement check
2023-11-02 20:23:06 +01:00
Alex Yang
f52569b8fa fix: remove unused if-statement check 2023-10-30 19:41:09 -05:00
Andrew Haines
25bef2308f Fix typing of Y.Map iterators
Signed-off-by: Andrew Haines <andrew@haines.org.nz>
2023-10-25 15:00:48 +01:00
Samy Pessé
e7572d61c6 Only emit "load" when sync is set to true 2023-10-22 11:03:25 +02:00
Nik Graf
e6afc51b84 add documentation on V2 events 2023-10-07 20:56:02 +02:00
Jesse Jackson
171d801e0a docs(readme): fix typo
Update link text for Swift bindings: from "yrb" to "yswift"
2023-10-05 00:41:48 -05:00
Kevin Jahns
9a7b659919 bump lib0 2023-09-23 16:59:32 +02:00
Kevin Jahns
e0a9c0d9bb Merge pull request #577 from EricHasegawa/patch-1
Correct typos in INTERNALS.md
2023-09-19 13:15:58 +02:00
Eric Hasegawa
3a758f89a1 Correct typos in INTERNALS.md 2023-09-18 13:30:15 -07:00
Kevin Jahns
b5051e91ac Merge pull request #533 from booxood/fix-docs-example
docs: fix "Example: Syncing clients without loading the Y.Doc" code
2023-09-18 19:32:01 +02:00
Kevin Jahns
2fe8907ab0 13.6.8 2023-09-18 10:22:28 +02:00
Kevin Jahns
29270b5f3e fix "can't read origin of undefined" - fixes #417 2023-09-18 09:55:50 +02:00
Kevin Jahns
a099e98bd6 create error on call - fixes #569 2023-09-07 13:41:35 +02:00
Kevin Jahns
1b0da31d00 Merge pull request #567 from stevenfabre/main
Added Liveblocks Yjs to the list of providers
2023-09-06 17:01:29 +02:00
Kevin Jahns
a1fda219e4 lint readme 2023-09-02 17:39:49 +02:00
Kevin Jahns
09687221ac Merge pull request #568 from himself65/docs-update
docs: add `@toeverything/y-indexeddb`
2023-09-01 13:01:57 +02:00
Alex Yang
4d7a366f6e docs: add @toeverything/y-indexeddb 2023-08-31 17:21:36 -05:00
Steven Fabre
0b30413f6e Liveblocks in Yjs README
Signed-off-by: Steven Fabre <hello@stevenfabre.com>
2023-08-31 05:34:05 -04:00
Kevin Jahns
eeae74decf sponsors update 2023-08-29 16:34:26 +02:00
Kevin Jahns
5ac498d62e Merge pull request #566 from IllumiDesk/docs/add-illumidesk-ref
Adds IllumiDesk as a reference to the using list
2023-08-29 16:33:32 +02:00
Greg Werner
9a9a1ffeeb Adds IllumiDesk as a reference to the using list
Signed-off-by: Greg Werner <werner.greg@gmail.com>
2023-08-28 14:45:43 -04:00
Kevin Jahns
1ed12434a1 Merge pull request #556 from AdventureBeard/patch-1
Update README.md
2023-08-28 12:26:31 +02:00
Kevin Jahns
7a4975ee85 Merge branch 'main' into patch-1 2023-08-28 12:26:18 +02:00
Kevin Jahns
92ee76ad6e Merge pull request #564 from akshaykmr/readme-update-who-is-using
add oorja.io to who is using yjs
2023-08-24 14:01:32 +02:00
Kevin Jahns
97c09a6cca fix #509 2023-08-24 13:52:38 +02:00
Kevin Jahns
2e3ba0f81f Merge pull request #565 from himself65/himself65-patch-1
Update README.md
2023-08-23 16:46:17 +02:00
Alex Yang
61abf3a1db Update README.md 2023-08-23 09:25:18 -05:00
Akshay Kumar
bd867cb161 add oorja to who is using yjs 2023-08-23 19:31:58 +05:30
Kevin Jahns
87b7d3e951 add Yjs-compatible ports to documentation 2023-08-23 15:42:48 +02:00
GQ
7bdf94167a fix comment 2023-07-31 15:05:33 +08:00
Braden
03b9a806e8 Update README.md 2023-07-23 14:40:03 -05:00
Liucw
1ce1751432 docs: fix "Example: Syncing clients without loading the Y.Doc" code 2023-05-17 14:52:25 +08:00
14 changed files with 106 additions and 36 deletions

View File

@@ -16,16 +16,16 @@ jobs:
strategy:
matrix:
node-version: [16.x, 18.x]
node-version: [16.x, 20.x]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run lint
- run: npm run test-extensive
- run: npm run test
env:
CI: true

View File

@@ -149,8 +149,8 @@ concepts that can be used to create a custom network protocol:
* `update`: The Yjs document can be encoded to an *update* object that can be
parsed to reconstruct the document. Also every change on the document fires
an incremental document updates that allows clients to sync with each other.
The update object is an Uint8Array that efficiently encodes `Item` objects and
an incremental document update that allows clients to sync with each other.
The update object is a Uint8Array that efficiently encodes `Item` objects and
the delete set.
* `state vector`: A state vector defines the known state of each user (a set of
tuples `(client, clock)`). This object is also efficiently encoded as a

View File

@@ -1,7 +1,7 @@
The MIT License (MIT)
Copyright (c) 2014
- Kevin Jahns <kevin.jahns@rwth-aachen.de>.
Copyright (c) 2023
- Kevin Jahns <kevin.jahns@protonmail.com>.
- Chair of Computer Science 5 (Databases & Information Systems), RWTH Aachen University, Germany
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -60,12 +60,19 @@ on Yjs. [![Become a Sponsor](https://img.shields.io/static/v1?label=Become%20a%2
sharing analyses, documentation, spreadsheets, and dashboards.
* [Nosgestesclimat](https://nosgestesclimat.fr/groupe) The french carbon
footprint calculator has a group P2P mode based on yjs
* [oorja.io](https://oorja.io) Online meeting spaces extensible with
collaborative apps, end-to-end encrypted.
* [LegendKeeper](https://legendkeeper.com) Collaborative campaign planner and
worldbuilding app for tabletop RPGs.
* [IllumiDesk](https://illumidesk.com/) Build courses and content with A.I.
* [btw](https://www.btw.so) Open-source Medium alternative
## Table of Contents
* [Overview](#Overview)
* [Bindings](#Bindings)
* [Providers](#Providers)
* [Ports](#Ports)
* [Getting Started](#Getting-Started)
* [API](#API)
* [Shared Types](#Shared-Types)
@@ -137,6 +144,14 @@ Also includes a peer-sync mechanism to catch up on missed updates.
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.
</dd>
<dt><a href="https://github.com/liveblocks/liveblocks">@liveblocks/yjs</a></dt>
<dd>
<a href="https://liveblocks.io/document/yjs">Liveblocks Yjs</a> provides a fully
hosted WebSocket infrastructure and persisted data store for Yjs
documents. No configuration or maintenance is required. It also features
Yjs webhook events, REST API to read and update Yjs documents, and a
browser DevTools extension.
</dd>
<dt><a href="https://github.com/yousefED/matrix-crdt">Matrix-CRDT</a></dt>
<dd>
Use <a href="https://www.matrix.org">Matrix</a> as an off-the-shelf backend for
@@ -150,9 +165,30 @@ Encryption (E2EE).
<dd>
Adds persistent storage to a server with MongoDB. Can be used with the
y-websocket provider.
</dd>
<dt><a href="https://github.com/toeverything/AFFiNE/tree/master/packages/y-indexeddb">
@toeverything/y-indexeddb</a></dt>
<dd>
Like y-indexeddb, but with sub-documents support and fully TypeScript.
</dd>
</dl>
# Ports
There are several Yjs-compatible ports to other programming languages.
* [y-octo](https://github.com/toeverything/y-octo) - Rust implementation by
[AFFiNE](https://affine.pro)
* [y-crdt](https://github.com/y-crdt/y-crdt) - Rust implementation with multiple
language bindings to other languages
* [yrs](https://github.com/y-crdt/y-crdt/tree/main/yrs) - Rust interface
* [ypy](https://github.com/y-crdt/ypy) - Python binding
* [yrb](https://github.com/y-crdt/yrb) - Ruby binding
* [yswift](https://github.com/y-crdt/yswift) - Swift binding
* [yffi](https://github.com/y-crdt/y-crdt/tree/main/yffi) - C-FFI
* [ywasm](https://github.com/y-crdt/y-crdt/tree/main/ywasm) - WASM binding
* [ycs](https://github.com/yjs/ycs) - .Net compatible C# implementation.
## Getting Started
Install Yjs and a provider with your favorite package manager:
@@ -662,7 +698,8 @@ type. Doesn't log types that have not been defined (using
<b><code>on('update', function(updateMessage:Uint8Array, origin:any, Y.Doc):void)</code></b>
<dd>
Listen to document updates. Document updates must be transmitted to all other
peers. You can apply document updates in any order and multiple times.
peers. You can apply document updates in any order and multiple times. Use `updateV2`
to receive V2 events.
</dd>
<b><code>on('beforeTransaction', function(Y.Transaction, Y.Doc):void)</code></b>
<dd>Emitted before each transaction.</dd>
@@ -754,7 +791,7 @@ const diff2 = Y.diffUpdate(currentState2, stateVector1)
// sync clients
currentState1 = Y.mergeUpdates([currentState1, diff2])
currentState1 = Y.mergeUpdates([currentState1, diff1])
currentState2 = Y.mergeUpdates([currentState2, diff1])
```
#### Obfuscating Updates
@@ -787,8 +824,10 @@ Yjs implements two update formats. By default you are using the V1 update format
You can opt-in into the V2 update format wich provides much better compression.
It is not yet used by all providers. However, you can already use it if
you are building your own provider. All below functions are available with the
suffix "V2". E.g. `Y.applyUpdate``Y.applyUpdateV2`. We also support conversion
functions between both formats: `Y.convertUpdateFormatV1ToV2` & `Y.convertUpdateFormatV2ToV1`.
suffix "V2". E.g. `Y.applyUpdate``Y.applyUpdateV2`. Also when listening to updates
you need to specifically need listen for V2 events e.g. `yDoc.on('updateV2', …)`.
We also support conversion functions between both formats:
`Y.convertUpdateFormatV1ToV2` & `Y.convertUpdateFormatV2ToV1`.
#### Update API
@@ -1033,7 +1072,7 @@ doc.transact(() => {
ytext.insert(0, 'abc')
}, 41)
undoManager.undo()
ytext.toString() // => '' (not tracked because 41 is not an instance of
ytext.toString() // => 'abc' (not tracked because 41 is not an instance of
// `trackedTransactionorigins`)
ytext.delete(0, 3) // revert change

14
package-lock.json generated
View File

@@ -1,15 +1,15 @@
{
"name": "yjs",
"version": "13.6.7",
"version": "13.6.9",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "yjs",
"version": "13.6.7",
"version": "13.6.9",
"license": "MIT",
"dependencies": {
"lib0": "^0.2.74"
"lib0": "^0.2.86"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.1",
@@ -2481,9 +2481,9 @@
}
},
"node_modules/lib0": {
"version": "0.2.74",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.74.tgz",
"integrity": "sha512-roj9i46/JwG5ik5KNTkxP2IytlnrssAkD/OhlAVtE+GqectrdkfR+pttszVLrOzMDeXNs1MPt6yo66MUolWSiA==",
"version": "0.2.86",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.86.tgz",
"integrity": "sha512-kxigQTM4Q7NwJkEgdqQvU21qiR37twcqqLmh+/SbiGbRLfPlLVbHyY9sWp7PwXh0Xus9ELDSjsUOwcrdt5yZ4w==",
"dependencies": {
"isomorphic.js": "^0.2.4"
},
@@ -2492,7 +2492,7 @@
"0serve": "bin/0serve.js"
},
"engines": {
"node": ">=14"
"node": ">=16"
},
"funding": {
"type": "GitHub Sponsors ❤",

View File

@@ -1,6 +1,6 @@
{
"name": "yjs",
"version": "13.6.7",
"version": "13.6.9",
"description": "Shared Editing Library",
"main": "./dist/yjs.cjs",
"module": "./dist/yjs.mjs",
@@ -75,7 +75,7 @@
},
"homepage": "https://docs.yjs.dev",
"dependencies": {
"lib0": "^0.2.74"
"lib0": "^0.2.86"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.1",

View File

@@ -18,8 +18,10 @@ export {
Item,
AbstractStruct,
GC,
Skip,
ContentBinary,
ContentDeleted,
ContentDoc,
ContentEmbed,
ContentFormat,
ContentJSON,
@@ -93,6 +95,9 @@ export {
obfuscateUpdate,
obfuscateUpdateV2,
UpdateEncoderV1,
UpdateEncoderV2,
UpdateDecoderV1,
UpdateDecoderV2,
equalDeleteSets,
snapshotContainsUpdate
} from './internals.js'

View File

@@ -389,9 +389,8 @@ export class Item extends AbstractStruct {
}
if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) {
this.parent = null
}
// only set parent if this shouldn't be garbage collected
if (!this.parent) {
} else if (!this.parent) {
// only set parent if this shouldn't be garbage collected
if (this.left && this.left.constructor === Item) {
this.parent = this.left.parent
this.parentSub = this.left.parentSub

View File

@@ -683,7 +683,7 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
packJsonContent()
}
const lengthExceeded = error.create('Length exceeded!')
const lengthExceeded = () => error.create('Length exceeded!')
/**
* @param {Transaction} transaction
@@ -696,7 +696,7 @@ const lengthExceeded = error.create('Length exceeded!')
*/
export const typeListInsertGenerics = (transaction, parent, index, content) => {
if (index > parent._length) {
throw lengthExceeded
throw lengthExceeded()
}
if (index === 0) {
if (parent._searchMarker) {
@@ -798,7 +798,7 @@ export const typeListDelete = (transaction, parent, index, length) => {
n = n.right
}
if (length > 0) {
throw lengthExceeded
throw lengthExceeded()
}
if (parent._searchMarker) {
updateMarkerChanges(parent._searchMarker, startIndex, -startLength + length /* in case we remove the above exception */)

View File

@@ -41,7 +41,7 @@ export class YMapEvent extends YEvent {
* A shared Map implementation.
*
* @extends AbstractType<YMapEvent<MapType>>
* @implements {Iterable<MapType>}
* @implements {Iterable<[string, MapType]>}
*/
export class YMap extends AbstractType {
/**
@@ -152,7 +152,7 @@ export class YMap extends AbstractType {
/**
* Returns the values for each element in the YMap Type.
*
* @return {IterableIterator<any>}
* @return {IterableIterator<MapType>}
*/
values () {
return iterator.iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => v[1].content.getContent()[v[1].length - 1])
@@ -161,10 +161,10 @@ export class YMap extends AbstractType {
/**
* Returns an Iterator of [key, value] pairs
*
* @return {IterableIterator<any>}
* @return {IterableIterator<[string, MapType]>}
*/
entries () {
return iterator.iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => [v[0], v[1].content.getContent()[v[1].length - 1]])
return iterator.iteratorMap(createMapIterator(this._map), /** @param {any} v */ v => /** @type {any} */ ([v[0], v[1].content.getContent()[v[1].length - 1]]))
}
/**
@@ -183,7 +183,7 @@ export class YMap extends AbstractType {
/**
* Returns an Iterator of [key, value] pairs
*
* @return {IterableIterator<any>}
* @return {IterableIterator<[string, MapType]>}
*/
[Symbol.iterator] () {
return this.entries()

View File

@@ -113,7 +113,7 @@ export class Doc extends Observable {
this.whenSynced = provideSyncedPromise()
}
this.isSynced = isSynced === undefined || isSynced === true
if (!this.isLoaded) {
if (this.isSynced && !this.isLoaded) {
this.emit('load', [])
}
})

View File

@@ -15,6 +15,7 @@ import {
import * as time from 'lib0/time'
import * as array from 'lib0/array'
import * as logging from 'lib0/logging'
import { Observable } from 'lib0/observable'
export class StackItem {
@@ -169,6 +170,7 @@ export class UndoManager extends Observable {
* @type {Array<AbstractType<any>>}
*/
this.scope = []
this.doc = doc
this.addToScope(typeScope)
this.deleteFilter = deleteFilter
trackedOrigins.add(this)
@@ -189,7 +191,6 @@ export class UndoManager extends Observable {
*/
this.undoing = false
this.redoing = false
this.doc = doc
this.lastChange = 0
this.ignoreRemoteMapChanges = ignoreRemoteMapChanges
this.captureTimeout = captureTimeout
@@ -263,6 +264,7 @@ export class UndoManager extends Observable {
ytypes = array.isArray(ytypes) ? ytypes : [ytypes]
ytypes.forEach(ytype => {
if (this.scope.every(yt => yt !== ytype)) {
if (ytype.doc !== this.doc) logging.warn('[yjs#509] Not same Y.Doc') // use MultiDocUndoManager instead. also see https://github.com/yjs/yjs/issues/509
this.scope.push(ytype)
}
})

View File

@@ -251,7 +251,7 @@ const integrateStructs = (transaction, store, clientsStructRefs) => {
return nextStructsTarget
}
let curStructsTarget = getNextStructTarget()
if (curStructsTarget === null && stack.length === 0) {
if (curStructsTarget === null) {
return null
}

View File

@@ -8,6 +8,31 @@ import * as Y from '../src/index.js'
import * as t from 'lib0/testing'
import * as prng from 'lib0/prng'
/**
* @param {t.TestCase} _tc
*/
export const testIterators = _tc => {
const ydoc = new Y.Doc()
/**
* @type {Y.Map<number>}
*/
const ymap = ydoc.getMap()
// we are only checking if the type assumptions are correct
/**
* @type {Array<number>}
*/
const vals = Array.from(ymap.values())
/**
* @type {Array<[string,number]>}
*/
const entries = Array.from(ymap.entries())
/**
* @type {Array<string>}
*/
const keys = Array.from(ymap.keys())
console.log(vals, entries, keys)
}
/**
* Computing event changes after transaction should result in an error. See yjs#539
*