y-protocols
Advanced tools
Comparing version 0.0.5 to 0.0.6
270
awareness.js
@@ -5,34 +5,110 @@ /** | ||
import * as Y from 'yjs' | ||
import * as encoding from 'lib0/encoding.js' | ||
import * as decoding from 'lib0/decoding.js' | ||
import * as error from 'lib0/error.js' | ||
import * as time from 'lib0/time.js' | ||
import * as math from 'lib0/math.js' | ||
import { Observable } from 'lib0/observable.js' | ||
import * as Y from 'yjs' | ||
const messageUsersStateChanged = 0 | ||
const outdatedTimeout = 30000 | ||
/** | ||
* This is just a template for a Yjs instance with awareness. | ||
* We do not really extend it. | ||
* @typedef {Object} MetaClientState | ||
* @property {number} MetaClientState.clock | ||
* @property {number} MetaClientState.lastUpdated unix timestamp | ||
*/ | ||
export class YWithAwareness extends Y.Doc { | ||
constructor () { | ||
/** | ||
* The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information | ||
* (cursor, username, status, ..). Each client can update its own local state and listen to state changes of | ||
* remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline. | ||
* | ||
* Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override | ||
* its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is | ||
* applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that | ||
* a remote client is offline, it may propagate a message with | ||
* `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a | ||
* message is received, and the known clock of that client equals the received clock, it will override the state with `null`. | ||
* | ||
* Before a client disconnects, it should propagate a `null` state with an updated clock. | ||
* | ||
* Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state. | ||
* | ||
* @extends {Observable<string>} | ||
*/ | ||
export class Awareness extends Observable { | ||
/** | ||
* @param {Y.Doc} doc | ||
*/ | ||
constructor (doc) { | ||
super() | ||
this.doc = doc | ||
/** | ||
* @type {Object<string,Object>} | ||
* Maps from client id to client state | ||
* @type {Map<number, Object<string, any>>} | ||
*/ | ||
this._localAwarenessState = {} | ||
this.awareness = new Map() | ||
this.awarenessClock = new Map() | ||
this.states = new Map() | ||
/** | ||
* @type {Map<number, MetaClientState>} | ||
*/ | ||
this.meta = new Map() | ||
this._checkInterval = setInterval(() => { | ||
const now = time.getUnixTime() | ||
if (this.getLocalState() !== null && outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(doc.clientID)).lastUpdated) { | ||
// renew local clock | ||
this.setLocalState(this.getLocalState()) | ||
} | ||
/** | ||
* @type {Array<number>} | ||
*/ | ||
const remove = [] | ||
this.meta.forEach((meta, clientid) => { | ||
if (outdatedTimeout <= now - meta.lastUpdated) { | ||
remove.push(clientid) | ||
} | ||
}) | ||
if (remove.length > 0) { | ||
removeAwarenessStates(this, remove, 'timeout') | ||
} | ||
}, math.floor(outdatedTimeout / 10)) | ||
doc.on('destroy', () => { | ||
this.destroy() | ||
}) | ||
} | ||
destroy () { | ||
clearInterval(this._checkInterval) | ||
} | ||
/** | ||
* @return {Object<string,Object>} | ||
* @return {Object<string,Object>|null} | ||
*/ | ||
getLocalAwarenessInfo () { | ||
throw error.methodUnimplemented() | ||
getLocalState () { | ||
return this.states.get(this.doc.clientID) || null | ||
} | ||
/** | ||
* @return {Map<string,Object<string,Object>>} | ||
* @param {Object<string,any>|null} state | ||
*/ | ||
getAwarenessInfo () { | ||
throw error.methodUnimplemented() | ||
setLocalState (state) { | ||
const clientID = this.doc.clientID | ||
const currLocalMeta = this.meta.get(clientID) | ||
const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1 | ||
if (state === null) { | ||
this.states.delete(clientID) | ||
} else { | ||
this.states.set(clientID, state) | ||
} | ||
this.meta.set(clientID, { | ||
clock, | ||
lastUpdated: time.getUnixTime() | ||
}) | ||
const added = [] | ||
const updated = [] | ||
const removed = [] | ||
if (state === null) { | ||
removed.push(clientID) | ||
} else if (currLocalMeta === undefined) { | ||
added.push(clientID) | ||
} else { | ||
updated.push(clientID) | ||
} | ||
this.emit('change', [{ added, updated, removed }, 'local']) | ||
} | ||
@@ -43,24 +119,58 @@ /** | ||
*/ | ||
setAwarenessField (field, value) { | ||
throw error.methodUnimplemented() | ||
setLocalStateField (field, value) { | ||
const state = this.getLocalState() | ||
if (state !== null) { | ||
state[field] = value | ||
this.setLocalState(state) | ||
} | ||
} | ||
/** | ||
* @return {Map<number,Object<string,any>>} | ||
*/ | ||
getStates () { | ||
return this.states | ||
} | ||
} | ||
/** | ||
* @typedef {Object} UserStateUpdate | ||
* @property {number} UserStateUpdate.clientID | ||
* @property {number} UserStateUpdate.clock | ||
* @property {Object} UserStateUpdate.state | ||
* Mark (remote) clients as inactive and remove them from the list of active peers. | ||
* This change will be propagated to remote clients. | ||
* | ||
* @param {Awareness} awareness | ||
* @param {Array<number>} clients | ||
* @param {any} origin | ||
*/ | ||
export const removeAwarenessStates = (awareness, clients, origin) => { | ||
const removed = [] | ||
for (let i = 0; i < clients.length; i++) { | ||
const clientID = clients[i] | ||
if (awareness.states.has(clientID)) { | ||
awareness.states.delete(clientID) | ||
if (clientID === awareness.doc.clientID) { | ||
const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID)) | ||
curMeta.clock++ | ||
curMeta.lastUpdated = time.getUnixTime() | ||
awareness.meta.set(clientID, curMeta) | ||
} | ||
removed.push(clientID) | ||
} | ||
} | ||
if (removed.length > 0) { | ||
awareness.emit('change', [{ added: [], updated: [], removed }, origin]) | ||
} | ||
} | ||
/** | ||
* @param {encoding.Encoder} encoder | ||
* @param {Array<UserStateUpdate>} stateUpdates | ||
* @param {Awareness} awareness | ||
* @param {Array<number>} clients | ||
* @return {Uint8Array} | ||
*/ | ||
export const writeUsersStateChange = (encoder, stateUpdates) => { | ||
const len = stateUpdates.length | ||
encoding.writeVarUint(encoder, messageUsersStateChanged) | ||
export const encodeAwarenessUpdate = (awareness, clients) => { | ||
const len = clients.length | ||
const encoder = encoding.createEncoder() | ||
encoding.writeVarUint(encoder, len) | ||
for (let i = 0; i < len; i++) { | ||
const { clientID, state, clock } = stateUpdates[i] | ||
const clientID = clients[i] | ||
const state = awareness.states.get(clientID) || null | ||
const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock | ||
encoding.writeVarUint(encoder, clientID) | ||
@@ -70,9 +180,13 @@ encoding.writeVarUint(encoder, clock) | ||
} | ||
return encoding.toUint8Array(encoder) | ||
} | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {YWithAwareness} y | ||
* @param {Awareness} awareness | ||
* @param {Uint8Array} update | ||
* @param {any} origin This will be added to the emitted change event | ||
*/ | ||
export const readUsersStateChange = (decoder, y) => { | ||
export const applyAwarenessUpdate = (awareness, update, origin) => { | ||
const decoder = decoding.createDecoder(update) | ||
const timestamp = time.getUnixTime() | ||
const added = [] | ||
@@ -86,84 +200,28 @@ const updated = [] | ||
const state = JSON.parse(decoding.readVarString(decoder)) | ||
const uClock = y.awarenessClock.get(clientID) || 0 | ||
y.awarenessClock.set(clientID, clock) | ||
if (state === null) { | ||
// only write if clock increases. cannot overwrite | ||
if (y.awareness.has(clientID) && uClock < clock) { | ||
y.awareness.delete(clientID) | ||
const clientMeta = awareness.meta.get(clientID) | ||
const uClock = clientMeta === undefined ? 0 : clientMeta.clock | ||
if (uClock < clock || (uClock === clock && state === null && awareness.states.has(clientID))) { | ||
if (state === null) { | ||
awareness.states.delete(clientID) | ||
} else { | ||
awareness.states.set(clientID, state) | ||
} | ||
awareness.meta.set(clientID, { | ||
clock, | ||
lastUpdated: timestamp | ||
}) | ||
if (clientMeta === undefined && state !== null) { | ||
added.push(clientID) | ||
} else if (clientMeta !== undefined && state === null) { | ||
removed.push(clientID) | ||
} | ||
} else if (uClock <= clock) { // allow to overwrite (e.g. when client was on, then offline) | ||
if (y.awareness.has(clientID)) { | ||
} else if (state !== null) { | ||
updated.push(clientID) | ||
} else { | ||
added.push(clientID) | ||
} | ||
y.awareness.set(clientID, state) | ||
y.awarenessClock.set(clientID, clock) | ||
} | ||
} | ||
if (added.length > 0 || updated.length > 0 || removed.length > 0) { | ||
// @ts-ignore We know emit is defined | ||
y.emit('awareness', [{ | ||
awareness.emit('change', [{ | ||
added, updated, removed | ||
}]) | ||
}, origin]) | ||
} | ||
} | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {encoding.Encoder} encoder | ||
* @return {Array<UserStateUpdate>} | ||
*/ | ||
export const forwardUsersStateChange = (decoder, encoder) => { | ||
const len = decoding.readVarUint(decoder) | ||
const updates = [] | ||
encoding.writeVarUint(encoder, messageUsersStateChanged) | ||
encoding.writeVarUint(encoder, len) | ||
for (let i = 0; i < len; i++) { | ||
const clientID = decoding.readVarUint(decoder) | ||
const clock = decoding.readVarUint(decoder) | ||
const state = decoding.readVarString(decoder) | ||
encoding.writeVarUint(encoder, clientID) | ||
encoding.writeVarUint(encoder, clock) | ||
encoding.writeVarString(encoder, state) | ||
updates.push({ clientID, state: JSON.parse(state), clock }) | ||
} | ||
return updates | ||
} | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {YWithAwareness} y | ||
*/ | ||
export const readAwarenessMessage = (decoder, y) => { | ||
switch (decoding.readVarUint(decoder)) { | ||
case messageUsersStateChanged: | ||
readUsersStateChange(decoder, y) | ||
break | ||
} | ||
} | ||
/** | ||
* @typedef {Object} UserState | ||
* @property {number} UserState.clientID | ||
* @property {any} UserState.state | ||
* @property {number} UserState.clock | ||
*/ | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {encoding.Encoder} encoder | ||
* @return {Array<UserState>} Array of state updates | ||
*/ | ||
export const forwardAwarenessMessage = (decoder, encoder) => { | ||
/** | ||
* @type {Array<UserState>} | ||
*/ | ||
let s = [] | ||
switch (decoding.readVarUint(decoder)) { | ||
case messageUsersStateChanged: | ||
s = forwardUsersStateChange(decoder, encoder) | ||
} | ||
return s | ||
} |
@@ -38,3 +38,3 @@ 'use strict'; | ||
exports.messagePermissionDenied = messagePermissionDenied; | ||
exports.readAuthMessage = readAuthMessage; | ||
exports.writePermissionDenied = writePermissionDenied; | ||
exports.readAuthMessage = readAuthMessage; |
@@ -7,4 +7,6 @@ 'use strict'; | ||
var decoding = require('lib0/dist/decoding.js'); | ||
var Y = require('yjs'); | ||
var error = require('lib0/dist/error.js'); | ||
var time = require('lib0/dist/time.js'); | ||
var math = require('lib0/dist/math.js'); | ||
var observable_js = require('lib0/dist/observable.js'); | ||
require('yjs'); | ||
@@ -15,29 +17,103 @@ /** | ||
const messageUsersStateChanged = 0; | ||
const outdatedTimeout = 30000; | ||
/** | ||
* This is just a template for a Yjs instance with awareness. | ||
* We do not really extend it. | ||
* @typedef {Object} MetaClientState | ||
* @property {number} MetaClientState.clock | ||
* @property {number} MetaClientState.lastUpdated unix timestamp | ||
*/ | ||
class YWithAwareness extends Y.Doc { | ||
constructor () { | ||
/** | ||
* The Awareness class implements a simple shared state protocol that can be used for non-persistent data like awareness information | ||
* (cursor, username, status, ..). Each client can update its own local state and listen to state changes of | ||
* remote clients. Every client may set a state of a remote peer to `null` to mark the client as offline. | ||
* | ||
* Each client is identified by a unique client id (something we borrow from `doc.clientID`). A client can override | ||
* its own state by propagating a message with an increasing timestamp (`clock`). If such a message is received, it is | ||
* applied if the known state of that client is older than the new state (`clock < newClock`). If a client thinks that | ||
* a remote client is offline, it may propagate a message with | ||
* `{ clock: currentClientClock, state: null, client: remoteClient }`. If such a | ||
* message is received, and the known clock of that client equals the received clock, it will override the state with `null`. | ||
* | ||
* Before a client disconnects, it should propagate a `null` state with an updated clock. | ||
* | ||
* Awareness states must be updated every 30 seconds. Otherwise the Awareness instance will delete the client state. | ||
* | ||
* @extends {Observable<string>} | ||
*/ | ||
class Awareness extends observable_js.Observable { | ||
/** | ||
* @param {Y.Doc} doc | ||
*/ | ||
constructor (doc) { | ||
super(); | ||
this.doc = doc; | ||
/** | ||
* @type {Object<string,Object>} | ||
* Maps from client id to client state | ||
* @type {Map<number, Object<string, any>>} | ||
*/ | ||
this._localAwarenessState = {}; | ||
this.awareness = new Map(); | ||
this.awarenessClock = new Map(); | ||
this.states = new Map(); | ||
/** | ||
* @type {Map<number, MetaClientState>} | ||
*/ | ||
this.meta = new Map(); | ||
this._checkInterval = setInterval(() => { | ||
const now = time.getUnixTime(); | ||
if (this.getLocalState() !== null && outdatedTimeout / 2 <= now - /** @type {{lastUpdated:number}} */ (this.meta.get(doc.clientID)).lastUpdated) { | ||
// renew local clock | ||
this.setLocalState(this.getLocalState()); | ||
} | ||
/** | ||
* @type {Array<number>} | ||
*/ | ||
const remove = []; | ||
this.meta.forEach((meta, clientid) => { | ||
if (outdatedTimeout <= now - meta.lastUpdated) { | ||
remove.push(clientid); | ||
} | ||
}); | ||
if (remove.length > 0) { | ||
removeAwarenessStates(this, remove, 'timeout'); | ||
} | ||
}, math.floor(outdatedTimeout / 10)); | ||
doc.on('destroy', () => { | ||
this.destroy(); | ||
}); | ||
} | ||
destroy () { | ||
clearInterval(this._checkInterval); | ||
} | ||
/** | ||
* @return {Object<string,Object>} | ||
* @return {Object<string,Object>|null} | ||
*/ | ||
getLocalAwarenessInfo () { | ||
throw error.methodUnimplemented() | ||
getLocalState () { | ||
return this.states.get(this.doc.clientID) || null | ||
} | ||
/** | ||
* @return {Map<string,Object<string,Object>>} | ||
* @param {Object<string,any>|null} state | ||
*/ | ||
getAwarenessInfo () { | ||
throw error.methodUnimplemented() | ||
setLocalState (state) { | ||
const clientID = this.doc.clientID; | ||
const currLocalMeta = this.meta.get(clientID); | ||
const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1; | ||
if (state === null) { | ||
this.states.delete(clientID); | ||
} else { | ||
this.states.set(clientID, state); | ||
} | ||
this.meta.set(clientID, { | ||
clock, | ||
lastUpdated: time.getUnixTime() | ||
}); | ||
const added = []; | ||
const updated = []; | ||
const removed = []; | ||
if (state === null) { | ||
removed.push(clientID); | ||
} else if (currLocalMeta === undefined) { | ||
added.push(clientID); | ||
} else { | ||
updated.push(clientID); | ||
} | ||
this.emit('change', [{ added, updated, removed }, 'local']); | ||
} | ||
@@ -48,24 +124,58 @@ /** | ||
*/ | ||
setAwarenessField (field, value) { | ||
throw error.methodUnimplemented() | ||
setLocalStateField (field, value) { | ||
const state = this.getLocalState(); | ||
if (state !== null) { | ||
state[field] = value; | ||
this.setLocalState(state); | ||
} | ||
} | ||
/** | ||
* @return {Map<number,Object<string,any>>} | ||
*/ | ||
getStates () { | ||
return this.states | ||
} | ||
} | ||
/** | ||
* @typedef {Object} UserStateUpdate | ||
* @property {number} UserStateUpdate.clientID | ||
* @property {number} UserStateUpdate.clock | ||
* @property {Object} UserStateUpdate.state | ||
* Mark (remote) clients as inactive and remove them from the list of active peers. | ||
* This change will be propagated to remote clients. | ||
* | ||
* @param {Awareness} awareness | ||
* @param {Array<number>} clients | ||
* @param {any} origin | ||
*/ | ||
const removeAwarenessStates = (awareness, clients, origin) => { | ||
const removed = []; | ||
for (let i = 0; i < clients.length; i++) { | ||
const clientID = clients[i]; | ||
if (awareness.states.has(clientID)) { | ||
awareness.states.delete(clientID); | ||
if (clientID === awareness.doc.clientID) { | ||
const curMeta = /** @type {MetaClientState} */ (awareness.meta.get(clientID)); | ||
curMeta.clock++; | ||
curMeta.lastUpdated = time.getUnixTime(); | ||
awareness.meta.set(clientID, curMeta); | ||
} | ||
removed.push(clientID); | ||
} | ||
} | ||
if (removed.length > 0) { | ||
awareness.emit('change', [{ added: [], updated: [], removed }, origin]); | ||
} | ||
}; | ||
/** | ||
* @param {encoding.Encoder} encoder | ||
* @param {Array<UserStateUpdate>} stateUpdates | ||
* @param {Awareness} awareness | ||
* @param {Array<number>} clients | ||
* @return {Uint8Array} | ||
*/ | ||
const writeUsersStateChange = (encoder, stateUpdates) => { | ||
const len = stateUpdates.length; | ||
encoding.writeVarUint(encoder, messageUsersStateChanged); | ||
const encodeAwarenessUpdate = (awareness, clients) => { | ||
const len = clients.length; | ||
const encoder = encoding.createEncoder(); | ||
encoding.writeVarUint(encoder, len); | ||
for (let i = 0; i < len; i++) { | ||
const { clientID, state, clock } = stateUpdates[i]; | ||
const clientID = clients[i]; | ||
const state = awareness.states.get(clientID) || null; | ||
const clock = /** @type {MetaClientState} */ (awareness.meta.get(clientID)).clock; | ||
encoding.writeVarUint(encoder, clientID); | ||
@@ -75,9 +185,13 @@ encoding.writeVarUint(encoder, clock); | ||
} | ||
return encoding.toUint8Array(encoder) | ||
}; | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {YWithAwareness} y | ||
* @param {Awareness} awareness | ||
* @param {Uint8Array} update | ||
* @param {any} origin This will be added to the emitted change event | ||
*/ | ||
const readUsersStateChange = (decoder, y) => { | ||
const applyAwarenessUpdate = (awareness, update, origin) => { | ||
const decoder = decoding.createDecoder(update); | ||
const timestamp = time.getUnixTime(); | ||
const added = []; | ||
@@ -91,91 +205,33 @@ const updated = []; | ||
const state = JSON.parse(decoding.readVarString(decoder)); | ||
const uClock = y.awarenessClock.get(clientID) || 0; | ||
y.awarenessClock.set(clientID, clock); | ||
if (state === null) { | ||
// only write if clock increases. cannot overwrite | ||
if (y.awareness.has(clientID) && uClock < clock) { | ||
y.awareness.delete(clientID); | ||
const clientMeta = awareness.meta.get(clientID); | ||
const uClock = clientMeta === undefined ? 0 : clientMeta.clock; | ||
if (uClock < clock || (uClock === clock && state === null && awareness.states.has(clientID))) { | ||
if (state === null) { | ||
awareness.states.delete(clientID); | ||
} else { | ||
awareness.states.set(clientID, state); | ||
} | ||
awareness.meta.set(clientID, { | ||
clock, | ||
lastUpdated: timestamp | ||
}); | ||
if (clientMeta === undefined && state !== null) { | ||
added.push(clientID); | ||
} else if (clientMeta !== undefined && state === null) { | ||
removed.push(clientID); | ||
} | ||
} else if (uClock <= clock) { // allow to overwrite (e.g. when client was on, then offline) | ||
if (y.awareness.has(clientID)) { | ||
} else if (state !== null) { | ||
updated.push(clientID); | ||
} else { | ||
added.push(clientID); | ||
} | ||
y.awareness.set(clientID, state); | ||
y.awarenessClock.set(clientID, clock); | ||
} | ||
} | ||
if (added.length > 0 || updated.length > 0 || removed.length > 0) { | ||
// @ts-ignore We know emit is defined | ||
y.emit('awareness', [{ | ||
awareness.emit('change', [{ | ||
added, updated, removed | ||
}]); | ||
}, origin]); | ||
} | ||
}; | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {encoding.Encoder} encoder | ||
* @return {Array<UserStateUpdate>} | ||
*/ | ||
const forwardUsersStateChange = (decoder, encoder) => { | ||
const len = decoding.readVarUint(decoder); | ||
const updates = []; | ||
encoding.writeVarUint(encoder, messageUsersStateChanged); | ||
encoding.writeVarUint(encoder, len); | ||
for (let i = 0; i < len; i++) { | ||
const clientID = decoding.readVarUint(decoder); | ||
const clock = decoding.readVarUint(decoder); | ||
const state = decoding.readVarString(decoder); | ||
encoding.writeVarUint(encoder, clientID); | ||
encoding.writeVarUint(encoder, clock); | ||
encoding.writeVarString(encoder, state); | ||
updates.push({ clientID, state: JSON.parse(state), clock }); | ||
} | ||
return updates | ||
}; | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {YWithAwareness} y | ||
*/ | ||
const readAwarenessMessage = (decoder, y) => { | ||
switch (decoding.readVarUint(decoder)) { | ||
case messageUsersStateChanged: | ||
readUsersStateChange(decoder, y); | ||
break | ||
} | ||
}; | ||
/** | ||
* @typedef {Object} UserState | ||
* @property {number} UserState.clientID | ||
* @property {any} UserState.state | ||
* @property {number} UserState.clock | ||
*/ | ||
/** | ||
* @param {decoding.Decoder} decoder | ||
* @param {encoding.Encoder} encoder | ||
* @return {Array<UserState>} Array of state updates | ||
*/ | ||
const forwardAwarenessMessage = (decoder, encoder) => { | ||
/** | ||
* @type {Array<UserState>} | ||
*/ | ||
let s = []; | ||
switch (decoding.readVarUint(decoder)) { | ||
case messageUsersStateChanged: | ||
s = forwardUsersStateChange(decoder, encoder); | ||
} | ||
return s | ||
}; | ||
exports.YWithAwareness = YWithAwareness; | ||
exports.writeUsersStateChange = writeUsersStateChange; | ||
exports.readUsersStateChange = readUsersStateChange; | ||
exports.forwardUsersStateChange = forwardUsersStateChange; | ||
exports.readAwarenessMessage = readAwarenessMessage; | ||
exports.forwardAwarenessMessage = forwardAwarenessMessage; | ||
exports.Awareness = Awareness; | ||
exports.applyAwarenessUpdate = applyAwarenessUpdate; | ||
exports.encodeAwarenessUpdate = encodeAwarenessUpdate; | ||
exports.removeAwarenessStates = removeAwarenessStates; |
@@ -49,3 +49,3 @@ 'use strict'; | ||
exports.readHistorySnapshot = readHistorySnapshot; | ||
exports.writeHistorySnapshot = writeHistorySnapshot; | ||
exports.readHistorySnapshot = readHistorySnapshot; |
@@ -54,3 +54,3 @@ 'use strict'; | ||
encoding.writeVarUint(encoder, messageYjsSyncStep1); | ||
const sv = Y.encodeDocumentStateVector(doc); | ||
const sv = Y.encodeStateVector(doc); | ||
encoding.writeVarUint8Array(encoder, sv); | ||
@@ -135,8 +135,8 @@ }; | ||
exports.messageYjsUpdate = messageYjsUpdate; | ||
exports.readSyncMessage = readSyncMessage; | ||
exports.readSyncStep1 = readSyncStep1; | ||
exports.readSyncStep2 = readSyncStep2; | ||
exports.readUpdate = readUpdate; | ||
exports.writeSyncStep1 = writeSyncStep1; | ||
exports.writeSyncStep2 = writeSyncStep2; | ||
exports.readSyncStep1 = readSyncStep1; | ||
exports.readSyncStep2 = readSyncStep2; | ||
exports.writeUpdate = writeUpdate; | ||
exports.readUpdate = readUpdate; | ||
exports.readSyncMessage = readSyncMessage; |
{ | ||
"name": "y-protocols", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "Yjs encoding protocols", | ||
@@ -33,5 +33,6 @@ "files": [ | ||
"dependencies": { | ||
"lib0": "0.0.4" | ||
"lib0": "0.0.5" | ||
}, | ||
"devDependencies": { | ||
"yjs": "13.0.0-83", | ||
"rollup": "^1.1.2", | ||
@@ -38,0 +39,0 @@ "rollup-cli": "^1.0.9", |
@@ -50,3 +50,3 @@ /** | ||
encoding.writeVarUint(encoder, messageYjsSyncStep1) | ||
const sv = Y.encodeDocumentStateVector(doc) | ||
const sv = Y.encodeStateVector(doc) | ||
encoding.writeVarUint8Array(encoder, sv) | ||
@@ -53,0 +53,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
32112
11
821
0
40
4
+ Addedlib0@0.0.5(transitive)
- Removedlib0@0.0.4(transitive)
Updatedlib0@0.0.5