@liveblocks/client
Advanced tools
Comparing version 0.14.0 to 0.15.0-alpha.1
import { Op, SerializedCrdt } from "./live"; | ||
import { StorageUpdate } from "./types"; | ||
export declare type ApplyResult = { | ||
reverse: Op[]; | ||
modified: AbstractCrdt; | ||
modified: StorageUpdate; | ||
} | { | ||
@@ -13,3 +14,3 @@ modified: false; | ||
deleteItem: (id: string) => void; | ||
dispatch: (ops: Op[], reverseOps: Op[], modified: AbstractCrdt[]) => void; | ||
dispatch: (ops: Op[], reverseOps: Op[], storageUpdates: Map<string, StorageUpdate>) => void; | ||
} | ||
@@ -57,3 +58,3 @@ export declare abstract class AbstractCrdt { | ||
*/ | ||
abstract _detachChild(crdt: AbstractCrdt): void; | ||
abstract _detachChild(crdt: AbstractCrdt): ApplyResult; | ||
/** | ||
@@ -67,2 +68,3 @@ * INTERNAL | ||
abstract _toSerializedCrdt(): SerializedCrdt; | ||
abstract _getType(): string; | ||
} |
@@ -55,6 +55,3 @@ "use strict"; | ||
if (this._parent != null && this._parentKey != null) { | ||
const parent = this._parent; | ||
const reverse = this._serialize(this._parent._id, this._parentKey, __classPrivateFieldGet(this, _AbstractCrdt_doc, "f")); | ||
this._parent._detachChild(this); | ||
return { modified: parent, reverse }; | ||
return this._parent._detachChild(this); | ||
} | ||
@@ -61,0 +58,0 @@ return { modified: false }; |
@@ -6,1 +6,2 @@ export { LiveObject } from "./LiveObject"; | ||
export { createClient } from "./client"; | ||
export { liveObjectToJson, liveNodeToJson, patchLiveList, patchImmutableObject, patchLiveObject, patchLiveObjectKey, } from "./immutable"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createClient = exports.LiveList = exports.LiveMap = exports.LiveObject = void 0; | ||
exports.patchLiveObjectKey = exports.patchLiveObject = exports.patchImmutableObject = exports.patchLiveList = exports.liveNodeToJson = exports.liveObjectToJson = exports.createClient = exports.LiveList = exports.LiveMap = exports.LiveObject = void 0; | ||
var LiveObject_1 = require("./LiveObject"); | ||
@@ -12,1 +12,8 @@ Object.defineProperty(exports, "LiveObject", { enumerable: true, get: function () { return LiveObject_1.LiveObject; } }); | ||
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } }); | ||
var immutable_1 = require("./immutable"); | ||
Object.defineProperty(exports, "liveObjectToJson", { enumerable: true, get: function () { return immutable_1.liveObjectToJson; } }); | ||
Object.defineProperty(exports, "liveNodeToJson", { enumerable: true, get: function () { return immutable_1.liveNodeToJson; } }); | ||
Object.defineProperty(exports, "patchLiveList", { enumerable: true, get: function () { return immutable_1.patchLiveList; } }); | ||
Object.defineProperty(exports, "patchImmutableObject", { enumerable: true, get: function () { return immutable_1.patchImmutableObject; } }); | ||
Object.defineProperty(exports, "patchLiveObject", { enumerable: true, get: function () { return immutable_1.patchLiveObject; } }); | ||
Object.defineProperty(exports, "patchLiveObjectKey", { enumerable: true, get: function () { return immutable_1.patchLiveObjectKey; } }); |
@@ -17,2 +17,3 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
_serialize(parentId?: string, parentKey?: string, doc?: Doc): Op[]; | ||
_indexOfPosition(position: string): number; | ||
/** | ||
@@ -33,7 +34,7 @@ * INTERNAL | ||
*/ | ||
_detachChild(child: AbstractCrdt): void; | ||
_detachChild(child: AbstractCrdt): ApplyResult; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_setChildKey(key: string, child: AbstractCrdt): void; | ||
_setChildKey(key: string, child: AbstractCrdt, previousKey: string): ApplyResult; | ||
/** | ||
@@ -46,2 +47,6 @@ * INTERNAL | ||
*/ | ||
_getType(): string; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt(): SerializedCrdt; | ||
@@ -79,2 +84,3 @@ /** | ||
toArray(): T[]; | ||
toCrdtArray(): AbstractCrdt[]; | ||
/** | ||
@@ -81,0 +87,0 @@ * Tests whether all elements pass the test implemented by the provided function. |
@@ -78,2 +78,5 @@ "use strict"; | ||
} | ||
_indexOfPosition(position) { | ||
return __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((item) => item[1] === position); | ||
} | ||
/** | ||
@@ -127,3 +130,11 @@ * INTERNAL | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => (0, position_1.compare)(itemA[1], itemB[1])); | ||
return { reverse: [{ type: live_1.OpType.DeleteCrdt, id }], modified: this }; | ||
const newIndex = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === newKey); | ||
return { | ||
reverse: [{ type: live_1.OpType.DeleteCrdt, id }], | ||
modified: { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: newIndex, type: "insert" }], | ||
}, | ||
}; | ||
} | ||
@@ -134,7 +145,15 @@ /** | ||
_detachChild(child) { | ||
const indexToDelete = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((item) => item[0] === child); | ||
__classPrivateFieldGet(this, _LiveList_items, "f").splice(indexToDelete, 1); | ||
if (child) { | ||
const reverse = this._serialize(this._id, child._parentKey, this._doc); | ||
const indexToDelete = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((item) => item[0] === child); | ||
__classPrivateFieldGet(this, _LiveList_items, "f").splice(indexToDelete, 1); | ||
child._detach(); | ||
const storageUpdate = { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: indexToDelete, type: "delete" }], | ||
}; | ||
return { modified: storageUpdate, reverse }; | ||
} | ||
return { modified: false }; | ||
} | ||
@@ -144,3 +163,3 @@ /** | ||
*/ | ||
_setChildKey(key, child) { | ||
_setChildKey(key, child, previousKey) { | ||
var _a; | ||
@@ -158,2 +177,17 @@ child._setParentLink(this, key); | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => (0, position_1.compare)(itemA[1], itemB[1])); | ||
const newIndex = this._indexOfPosition(key); | ||
return { | ||
modified: { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: newIndex, type: "insert" }], | ||
}, | ||
reverse: [ | ||
{ | ||
type: live_1.OpType.SetParentKey, | ||
id: item === null || item === void 0 ? void 0 : item[0]._id, | ||
parentKey: previousKey, | ||
}, | ||
], | ||
}; | ||
} | ||
@@ -169,2 +203,8 @@ /** | ||
*/ | ||
_getType() { | ||
return "LiveList"; | ||
} | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt() { | ||
@@ -207,6 +247,13 @@ var _a; | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => (0, position_1.compare)(itemA[1], itemB[1])); | ||
const newIndex = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === position); | ||
if (this._doc && this._id) { | ||
const id = this._doc.generateId(); | ||
value._attach(id, this._doc); | ||
this._doc.dispatch(value._serialize(this._id, position, this._doc), [{ type: live_1.OpType.DeleteCrdt, id }], [this]); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: newIndex, type: "insert" }], | ||
}); | ||
this._doc.dispatch(value._serialize(this._id, position, this._doc), [{ type: live_1.OpType.DeleteCrdt, id }], storageUpdates); | ||
} | ||
@@ -252,3 +299,13 @@ } | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => (0, position_1.compare)(itemA[1], itemB[1])); | ||
const newIndex = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === position); | ||
if (this._doc && this._id) { | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: [ | ||
{ index: index, type: "delete" }, | ||
{ index: newIndex, type: "insert" }, | ||
], | ||
}); | ||
this._doc.dispatch([ | ||
@@ -267,3 +324,3 @@ { | ||
}, | ||
], [this]); | ||
], storageUpdates); | ||
} | ||
@@ -285,2 +342,8 @@ } | ||
if (childRecordId) { | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: index, type: "delete" }], | ||
}); | ||
this._doc.dispatch([ | ||
@@ -292,3 +355,3 @@ { | ||
}, | ||
], item[0]._serialize(this._id, item[1]), [this]); | ||
], item[0]._serialize(this._id, item[1]), storageUpdates); | ||
} | ||
@@ -301,2 +364,4 @@ } | ||
let reverseOps = []; | ||
let updateDelta = []; | ||
let i = 0; | ||
for (const item of __classPrivateFieldGet(this, _LiveList_items, "f")) { | ||
@@ -308,6 +373,14 @@ item[0]._detach(); | ||
reverseOps.push(...item[0]._serialize(this._id, item[1])); | ||
updateDelta.push({ index: i, type: "delete" }); | ||
} | ||
i++; | ||
} | ||
__classPrivateFieldSet(this, _LiveList_items, [], "f"); | ||
this._doc.dispatch(ops, reverseOps, [this]); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: updateDelta, | ||
}); | ||
this._doc.dispatch(ops, reverseOps, storageUpdates); | ||
} | ||
@@ -327,2 +400,5 @@ else { | ||
} | ||
toCrdtArray() { | ||
return __classPrivateFieldGet(this, _LiveList_items, "f").map((entry) => entry[0]); | ||
} | ||
/** | ||
@@ -329,0 +405,0 @@ * Tests whether all elements pass the test implemented by the provided function. |
@@ -34,6 +34,10 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
*/ | ||
_detachChild(child: AbstractCrdt): void; | ||
_detachChild(child: AbstractCrdt): ApplyResult; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType(): string; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt(): SerializedCrdt; | ||
@@ -40,0 +44,0 @@ /** |
@@ -119,3 +119,10 @@ "use strict"; | ||
__classPrivateFieldGet(this, _LiveMap_map, "f").set(key, child); | ||
return { modified: this, reverse }; | ||
return { | ||
modified: { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [key]: { type: "update" } }, | ||
}, | ||
reverse, | ||
}; | ||
} | ||
@@ -135,2 +142,3 @@ /** | ||
_detachChild(child) { | ||
const reverse = this._serialize(this._id, child._parentKey, this._doc); | ||
for (const [key, value] of __classPrivateFieldGet(this, _LiveMap_map, "f")) { | ||
@@ -142,2 +150,8 @@ if (value === child) { | ||
child._detach(); | ||
const storageUpdate = { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [child._parentKey]: { type: "delete" } }, | ||
}; | ||
return { modified: storageUpdate, reverse }; | ||
} | ||
@@ -147,2 +161,8 @@ /** | ||
*/ | ||
_getType() { | ||
return "LiveMap"; | ||
} | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt() { | ||
@@ -184,5 +204,11 @@ var _a; | ||
item._attach(id, this._doc); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [key]: { type: "update" } }, | ||
}); | ||
this._doc.dispatch(item._serialize(this._id, key, this._doc), oldValue | ||
? oldValue._serialize(this._id, key) | ||
: [{ type: live_1.OpType.DeleteCrdt, id }], [this]); | ||
: [{ type: live_1.OpType.DeleteCrdt, id }], storageUpdates); | ||
} | ||
@@ -215,2 +241,8 @@ } | ||
if (this._doc && item._id) { | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [key]: { type: "delete" } }, | ||
}); | ||
this._doc.dispatch([ | ||
@@ -222,3 +254,3 @@ { | ||
}, | ||
], item._serialize(this._id, key), [this]); | ||
], item._serialize(this._id, key), storageUpdates); | ||
} | ||
@@ -225,0 +257,0 @@ __classPrivateFieldGet(this, _LiveMap_map, "f").delete(key); |
@@ -34,3 +34,3 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
*/ | ||
_detachChild(child: AbstractCrdt): void; | ||
_detachChild(child: AbstractCrdt): ApplyResult; | ||
/** | ||
@@ -53,2 +53,6 @@ * INTERNAL | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType(): string; | ||
/** | ||
* Transform the LiveObject into a javascript object | ||
@@ -55,0 +59,0 @@ */ |
@@ -136,3 +136,10 @@ "use strict"; | ||
child._attach(id, this._doc); | ||
return { reverse, modified: this }; | ||
return { | ||
reverse, | ||
modified: { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { [key]: { type: "update" } }, | ||
}, | ||
}; | ||
} | ||
@@ -143,10 +150,20 @@ /** | ||
_detachChild(child) { | ||
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) { | ||
if (value === child) { | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key); | ||
if (child) { | ||
const reverse = this._serialize(this._id, child._parentKey, this._doc); | ||
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) { | ||
if (value === child) { | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key); | ||
} | ||
} | ||
} | ||
if (child) { | ||
child._detach(); | ||
const storageUpdate = { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { | ||
[child._parentKey]: { type: "delete" }, | ||
}, | ||
}; | ||
return { modified: storageUpdate, reverse }; | ||
} | ||
return { modified: false }; | ||
} | ||
@@ -198,2 +215,8 @@ /** | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType() { | ||
return "LiveObject"; | ||
} | ||
/** | ||
* Transform the LiveObject into a javascript object | ||
@@ -252,2 +275,8 @@ */ | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(keyAsString); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { [key]: { type: "delete" } }, | ||
}); | ||
this._doc.dispatch([ | ||
@@ -260,3 +289,3 @@ { | ||
}, | ||
], reverse, [this]); | ||
], reverse, storageUpdates); | ||
} | ||
@@ -291,2 +320,3 @@ /** | ||
}; | ||
const updateDelta = {}; | ||
for (const key in overrides) { | ||
@@ -315,2 +345,3 @@ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId); | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue); | ||
updateDelta[key] = { type: "update" }; | ||
} | ||
@@ -328,3 +359,9 @@ if (Object.keys(reverseUpdateOp.data).length !== 0) { | ||
} | ||
this._doc.dispatch(ops, reverseOps, [this]); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveObject", | ||
updates: updateDelta, | ||
}); | ||
this._doc.dispatch(ops, reverseOps, storageUpdates); | ||
} | ||
@@ -355,2 +392,3 @@ } | ||
} | ||
let updateDelta = {}; | ||
for (const key in op.data) { | ||
@@ -378,2 +416,3 @@ if (isLocal) { | ||
isModified = true; | ||
updateDelta[key] = { type: "update" }; | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, op.data[key]); | ||
@@ -384,3 +423,12 @@ } | ||
} | ||
return isModified ? { modified: this, reverse } : { modified: false }; | ||
return isModified | ||
? { | ||
modified: { | ||
node: this, | ||
type: "LiveObject", | ||
updates: updateDelta, | ||
}, | ||
reverse, | ||
} | ||
: { modified: false }; | ||
}, _LiveObject_applyDeleteObjectKey = function _LiveObject_applyDeleteObjectKey(op) { | ||
@@ -408,3 +456,10 @@ const key = op.key; | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key); | ||
return { modified: this, reverse }; | ||
return { | ||
modified: { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { [op.key]: { type: "delete" } }, | ||
}, | ||
reverse, | ||
}; | ||
}; |
@@ -23,4 +23,8 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
_attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult; | ||
_detachChild(crdt: AbstractCrdt): void; | ||
_detachChild(crdt: AbstractCrdt): ApplyResult; | ||
_apply(op: Op, isLocal: boolean): ApplyResult; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType(): string; | ||
} |
@@ -80,4 +80,10 @@ "use strict"; | ||
} | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType() { | ||
return "LiveRegister"; | ||
} | ||
} | ||
exports.LiveRegister = LiveRegister; | ||
_LiveRegister_data = new WeakMap(); |
@@ -63,3 +63,3 @@ import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback, StorageCallback, StorageUpdate, BroadcastOptions } from "./types"; | ||
presence: boolean; | ||
nodes: Set<AbstractCrdt>; | ||
storageUpdates: Map<string, StorageUpdate>; | ||
}; | ||
@@ -66,0 +66,0 @@ }; |
@@ -218,8 +218,8 @@ "use strict"; | ||
} | ||
function storageDispatch(ops, reverse, modified) { | ||
function storageDispatch(ops, reverse, storageUpdates) { | ||
if (state.isBatching) { | ||
state.batch.ops.push(...ops); | ||
for (const item of modified) { | ||
state.batch.updates.nodes.add(item); | ||
} | ||
storageUpdates.forEach((value, key) => { | ||
state.batch.updates.storageUpdates.set(key, (0, utils_1.mergeStorageUpdates)(state.batch.updates.storageUpdates.get(key), value)); | ||
}); | ||
state.batch.reverseOps.push(...reverse); | ||
@@ -231,6 +231,6 @@ } | ||
dispatch(ops); | ||
notify({ nodes: new Set(modified) }); | ||
notify({ storageUpdates: storageUpdates }); | ||
} | ||
} | ||
function notify({ nodes = new Set(), presence = false, others = [], }) { | ||
function notify({ storageUpdates = new Map(), presence = false, others = [], }) { | ||
if (others.length > 0) { | ||
@@ -249,24 +249,5 @@ state.others = makeOthers(state.users); | ||
} | ||
if (nodes.size > 0) { | ||
if (storageUpdates.size > 0) { | ||
for (const subscriber of state.listeners.storage) { | ||
subscriber(Array.from(nodes).map((m) => { | ||
if (m instanceof LiveObject_1.LiveObject) { | ||
return { | ||
type: "LiveObject", | ||
node: m, | ||
}; | ||
} | ||
else if (m instanceof LiveList_1.LiveList) { | ||
return { | ||
type: "LiveList", | ||
node: m, | ||
}; | ||
} | ||
else { | ||
return { | ||
type: "LiveMap", | ||
node: m, | ||
}; | ||
} | ||
})); | ||
subscriber(Array.from(storageUpdates.values())); | ||
} | ||
@@ -294,3 +275,6 @@ } | ||
reverse: [], | ||
updates: { nodes: new Set(), presence: false }, | ||
updates: { | ||
storageUpdates: new Map(), | ||
presence: false, | ||
}, | ||
}; | ||
@@ -325,3 +309,3 @@ for (const op of item) { | ||
if (applyOpResult.modified) { | ||
result.updates.nodes.add(applyOpResult.modified); | ||
result.updates.storageUpdates.set(applyOpResult.modified.node._id, (0, utils_1.mergeStorageUpdates)(result.updates.storageUpdates.get(applyOpResult.modified.node._id), applyOpResult.modified)); | ||
result.reverse.unshift(...applyOpResult.reverse); | ||
@@ -354,13 +338,8 @@ } | ||
const previousKey = item._parentKey; | ||
item._parent._setChildKey(op.parentKey, item); | ||
return { | ||
reverse: [ | ||
{ | ||
type: live_1.OpType.SetParentKey, | ||
id: item._id, | ||
parentKey: previousKey, | ||
}, | ||
], | ||
modified: item._parent, | ||
}; | ||
if (previousKey === op.parentKey) { | ||
return { modified: false }; | ||
} | ||
else { | ||
return item._parent._setChildKey(op.parentKey, item, previousKey); | ||
} | ||
} | ||
@@ -588,3 +567,3 @@ return { modified: false }; | ||
const updates = { | ||
nodes: new Set(), | ||
storageUpdates: new Map(), | ||
others: [], | ||
@@ -625,5 +604,5 @@ }; | ||
const applyResult = apply(subMessage.ops, false); | ||
for (const node of applyResult.updates.nodes) { | ||
updates.nodes.add(node); | ||
} | ||
applyResult.updates.storageUpdates.forEach((value, key) => { | ||
updates.storageUpdates.set(key, (0, utils_1.mergeStorageUpdates)(updates.storageUpdates.get(key), value)); | ||
}); | ||
break; | ||
@@ -922,5 +901,8 @@ } | ||
} | ||
// Clear the redo stack because batch is always called from a local operation | ||
state.redoStack = []; | ||
if (state.batch.ops.length > 0) { | ||
// Only clear the redo stack if something has changed during a batch | ||
// Clear the redo stack because batch is always called from a local operation | ||
state.redoStack = []; | ||
} | ||
if (state.batch.ops.length > 0) { | ||
dispatch(state.batch.ops); | ||
@@ -934,3 +916,3 @@ } | ||
others: [], | ||
nodes: new Set(), | ||
storageUpdates: new Map(), | ||
presence: false, | ||
@@ -1048,3 +1030,7 @@ }, | ||
ops: [], | ||
updates: { nodes: new Set(), presence: false, others: [] }, | ||
updates: { | ||
storageUpdates: new Map(), | ||
presence: false, | ||
others: [], | ||
}, | ||
reverseOps: [], | ||
@@ -1051,0 +1037,0 @@ }, |
@@ -19,13 +19,33 @@ import type { LiveList } from "./LiveList"; | ||
}; | ||
export declare type UpdateDelta = { | ||
type: "update"; | ||
} | { | ||
type: "delete"; | ||
}; | ||
export declare type LiveMapUpdates<TKey extends string = string, TValue = any> = { | ||
type: "LiveMap"; | ||
node: LiveMap<TKey, TValue>; | ||
updates: Record<TKey, UpdateDelta>; | ||
}; | ||
export declare type LiveObjectUpdateDelta<T> = Partial<{ | ||
[Property in keyof T]: UpdateDelta; | ||
}>; | ||
export declare type LiveObjectUpdates<TData = any> = { | ||
type: "LiveObject"; | ||
node: LiveObject<TData>; | ||
updates: LiveObjectUpdateDelta<TData>; | ||
}; | ||
export declare type ListUpdateDelta = { | ||
type: "insert"; | ||
} | { | ||
type: "delete"; | ||
}; | ||
export declare type LiveListUpdateDelta = { | ||
index: number; | ||
type: "insert" | "delete"; | ||
}; | ||
export declare type LiveListUpdates<TItem = any> = { | ||
type: "LiveList"; | ||
node: LiveList<TItem>; | ||
updates: LiveListUpdateDelta[]; | ||
}; | ||
@@ -32,0 +52,0 @@ export declare type BroadcastOptions = { |
import { AbstractCrdt, Doc } from "./AbstractCrdt"; | ||
import { SerializedCrdtWithId, Op, SerializedCrdt } from "./live"; | ||
import { StorageUpdate } from "./types"; | ||
export declare function remove<T>(array: T[], item: T): void; | ||
@@ -10,1 +11,2 @@ export declare function isSameNodeOrChildOf(node: AbstractCrdt, parent: AbstractCrdt): boolean; | ||
export declare function getTreesDiffOperations(currentItems: Map<string, SerializedCrdt>, newItems: Map<string, SerializedCrdt>): Op[]; | ||
export declare function mergeStorageUpdates(first: StorageUpdate | undefined, second: StorageUpdate): StorageUpdate; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getTreesDiffOperations = exports.selfOrRegister = exports.selfOrRegisterValue = exports.isCrdt = exports.deserialize = exports.isSameNodeOrChildOf = exports.remove = void 0; | ||
exports.mergeStorageUpdates = exports.getTreesDiffOperations = exports.selfOrRegister = exports.selfOrRegisterValue = exports.isCrdt = exports.deserialize = exports.isSameNodeOrChildOf = exports.remove = void 0; | ||
const live_1 = require("./live"); | ||
@@ -151,1 +151,26 @@ const LiveList_1 = require("./LiveList"); | ||
exports.getTreesDiffOperations = getTreesDiffOperations; | ||
function mergeStorageUpdates(first, second) { | ||
if (!first) { | ||
return second; | ||
} | ||
if (second.type === "LiveObject") { | ||
const updates = first.updates; | ||
for (const [key, value] of Object.entries(second.updates)) { | ||
updates[key] = value; | ||
} | ||
return Object.assign(Object.assign({}, second), { updates: updates }); | ||
} | ||
else if (second.type === "LiveMap") { | ||
const updates = first.updates; | ||
for (const [key, value] of Object.entries(second.updates)) { | ||
updates[key] = value; | ||
} | ||
return Object.assign(Object.assign({}, second), { updates: updates }); | ||
} | ||
else if (second.type === "LiveList") { | ||
const updates = first.updates; | ||
return Object.assign(Object.assign({}, second), { updates: updates.concat(second.updates) }); | ||
} | ||
return second; | ||
} | ||
exports.mergeStorageUpdates = mergeStorageUpdates; |
import { Op, SerializedCrdt } from "./live"; | ||
import { StorageUpdate } from "./types"; | ||
export declare type ApplyResult = { | ||
reverse: Op[]; | ||
modified: AbstractCrdt; | ||
modified: StorageUpdate; | ||
} | { | ||
@@ -13,3 +14,3 @@ modified: false; | ||
deleteItem: (id: string) => void; | ||
dispatch: (ops: Op[], reverseOps: Op[], modified: AbstractCrdt[]) => void; | ||
dispatch: (ops: Op[], reverseOps: Op[], storageUpdates: Map<string, StorageUpdate>) => void; | ||
} | ||
@@ -57,3 +58,3 @@ export declare abstract class AbstractCrdt { | ||
*/ | ||
abstract _detachChild(crdt: AbstractCrdt): void; | ||
abstract _detachChild(crdt: AbstractCrdt): ApplyResult; | ||
/** | ||
@@ -67,2 +68,3 @@ * INTERNAL | ||
abstract _toSerializedCrdt(): SerializedCrdt; | ||
abstract _getType(): string; | ||
} |
@@ -52,6 +52,3 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (this._parent != null && this._parentKey != null) { | ||
const parent = this._parent; | ||
const reverse = this._serialize(this._parent._id, this._parentKey, __classPrivateFieldGet(this, _AbstractCrdt_doc, "f")); | ||
this._parent._detachChild(this); | ||
return { modified: parent, reverse }; | ||
return this._parent._detachChild(this); | ||
} | ||
@@ -58,0 +55,0 @@ return { modified: false }; |
@@ -6,1 +6,2 @@ export { LiveObject } from "./LiveObject"; | ||
export { createClient } from "./client"; | ||
export { liveObjectToJson, liveNodeToJson, patchLiveList, patchImmutableObject, patchLiveObject, patchLiveObjectKey, } from "./immutable"; |
@@ -5,1 +5,2 @@ export { LiveObject } from "./LiveObject"; | ||
export { createClient } from "./client"; | ||
export { liveObjectToJson, liveNodeToJson, patchLiveList, patchImmutableObject, patchLiveObject, patchLiveObjectKey, } from "./immutable"; |
@@ -17,2 +17,3 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
_serialize(parentId?: string, parentKey?: string, doc?: Doc): Op[]; | ||
_indexOfPosition(position: string): number; | ||
/** | ||
@@ -33,7 +34,7 @@ * INTERNAL | ||
*/ | ||
_detachChild(child: AbstractCrdt): void; | ||
_detachChild(child: AbstractCrdt): ApplyResult; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_setChildKey(key: string, child: AbstractCrdt): void; | ||
_setChildKey(key: string, child: AbstractCrdt, previousKey: string): ApplyResult; | ||
/** | ||
@@ -46,2 +47,6 @@ * INTERNAL | ||
*/ | ||
_getType(): string; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt(): SerializedCrdt; | ||
@@ -79,2 +84,3 @@ /** | ||
toArray(): T[]; | ||
toCrdtArray(): AbstractCrdt[]; | ||
/** | ||
@@ -81,0 +87,0 @@ * Tests whether all elements pass the test implemented by the provided function. |
@@ -75,2 +75,5 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
} | ||
_indexOfPosition(position) { | ||
return __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((item) => item[1] === position); | ||
} | ||
/** | ||
@@ -124,3 +127,11 @@ * INTERNAL | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1])); | ||
return { reverse: [{ type: OpType.DeleteCrdt, id }], modified: this }; | ||
const newIndex = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === newKey); | ||
return { | ||
reverse: [{ type: OpType.DeleteCrdt, id }], | ||
modified: { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: newIndex, type: "insert" }], | ||
}, | ||
}; | ||
} | ||
@@ -131,7 +142,15 @@ /** | ||
_detachChild(child) { | ||
const indexToDelete = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((item) => item[0] === child); | ||
__classPrivateFieldGet(this, _LiveList_items, "f").splice(indexToDelete, 1); | ||
if (child) { | ||
const reverse = this._serialize(this._id, child._parentKey, this._doc); | ||
const indexToDelete = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((item) => item[0] === child); | ||
__classPrivateFieldGet(this, _LiveList_items, "f").splice(indexToDelete, 1); | ||
child._detach(); | ||
const storageUpdate = { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: indexToDelete, type: "delete" }], | ||
}; | ||
return { modified: storageUpdate, reverse }; | ||
} | ||
return { modified: false }; | ||
} | ||
@@ -141,3 +160,3 @@ /** | ||
*/ | ||
_setChildKey(key, child) { | ||
_setChildKey(key, child, previousKey) { | ||
var _a; | ||
@@ -155,2 +174,17 @@ child._setParentLink(this, key); | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1])); | ||
const newIndex = this._indexOfPosition(key); | ||
return { | ||
modified: { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: newIndex, type: "insert" }], | ||
}, | ||
reverse: [ | ||
{ | ||
type: OpType.SetParentKey, | ||
id: item === null || item === void 0 ? void 0 : item[0]._id, | ||
parentKey: previousKey, | ||
}, | ||
], | ||
}; | ||
} | ||
@@ -166,2 +200,8 @@ /** | ||
*/ | ||
_getType() { | ||
return "LiveList"; | ||
} | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt() { | ||
@@ -204,6 +244,13 @@ var _a; | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1])); | ||
const newIndex = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === position); | ||
if (this._doc && this._id) { | ||
const id = this._doc.generateId(); | ||
value._attach(id, this._doc); | ||
this._doc.dispatch(value._serialize(this._id, position, this._doc), [{ type: OpType.DeleteCrdt, id }], [this]); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: newIndex, type: "insert" }], | ||
}); | ||
this._doc.dispatch(value._serialize(this._id, position, this._doc), [{ type: OpType.DeleteCrdt, id }], storageUpdates); | ||
} | ||
@@ -249,3 +296,13 @@ } | ||
__classPrivateFieldGet(this, _LiveList_items, "f").sort((itemA, itemB) => compare(itemA[1], itemB[1])); | ||
const newIndex = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === position); | ||
if (this._doc && this._id) { | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: [ | ||
{ index: index, type: "delete" }, | ||
{ index: newIndex, type: "insert" }, | ||
], | ||
}); | ||
this._doc.dispatch([ | ||
@@ -264,3 +321,3 @@ { | ||
}, | ||
], [this]); | ||
], storageUpdates); | ||
} | ||
@@ -282,2 +339,8 @@ } | ||
if (childRecordId) { | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: [{ index: index, type: "delete" }], | ||
}); | ||
this._doc.dispatch([ | ||
@@ -289,3 +352,3 @@ { | ||
}, | ||
], item[0]._serialize(this._id, item[1]), [this]); | ||
], item[0]._serialize(this._id, item[1]), storageUpdates); | ||
} | ||
@@ -298,2 +361,4 @@ } | ||
let reverseOps = []; | ||
let updateDelta = []; | ||
let i = 0; | ||
for (const item of __classPrivateFieldGet(this, _LiveList_items, "f")) { | ||
@@ -305,6 +370,14 @@ item[0]._detach(); | ||
reverseOps.push(...item[0]._serialize(this._id, item[1])); | ||
updateDelta.push({ index: i, type: "delete" }); | ||
} | ||
i++; | ||
} | ||
__classPrivateFieldSet(this, _LiveList_items, [], "f"); | ||
this._doc.dispatch(ops, reverseOps, [this]); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveList", | ||
updates: updateDelta, | ||
}); | ||
this._doc.dispatch(ops, reverseOps, storageUpdates); | ||
} | ||
@@ -324,2 +397,5 @@ else { | ||
} | ||
toCrdtArray() { | ||
return __classPrivateFieldGet(this, _LiveList_items, "f").map((entry) => entry[0]); | ||
} | ||
/** | ||
@@ -326,0 +402,0 @@ * Tests whether all elements pass the test implemented by the provided function. |
@@ -34,6 +34,10 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
*/ | ||
_detachChild(child: AbstractCrdt): void; | ||
_detachChild(child: AbstractCrdt): ApplyResult; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType(): string; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt(): SerializedCrdt; | ||
@@ -40,0 +44,0 @@ /** |
@@ -116,3 +116,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
__classPrivateFieldGet(this, _LiveMap_map, "f").set(key, child); | ||
return { modified: this, reverse }; | ||
return { | ||
modified: { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [key]: { type: "update" } }, | ||
}, | ||
reverse, | ||
}; | ||
} | ||
@@ -132,2 +139,3 @@ /** | ||
_detachChild(child) { | ||
const reverse = this._serialize(this._id, child._parentKey, this._doc); | ||
for (const [key, value] of __classPrivateFieldGet(this, _LiveMap_map, "f")) { | ||
@@ -139,2 +147,8 @@ if (value === child) { | ||
child._detach(); | ||
const storageUpdate = { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [child._parentKey]: { type: "delete" } }, | ||
}; | ||
return { modified: storageUpdate, reverse }; | ||
} | ||
@@ -144,2 +158,8 @@ /** | ||
*/ | ||
_getType() { | ||
return "LiveMap"; | ||
} | ||
/** | ||
* INTERNAL | ||
*/ | ||
_toSerializedCrdt() { | ||
@@ -181,5 +201,11 @@ var _a; | ||
item._attach(id, this._doc); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [key]: { type: "update" } }, | ||
}); | ||
this._doc.dispatch(item._serialize(this._id, key, this._doc), oldValue | ||
? oldValue._serialize(this._id, key) | ||
: [{ type: OpType.DeleteCrdt, id }], [this]); | ||
: [{ type: OpType.DeleteCrdt, id }], storageUpdates); | ||
} | ||
@@ -212,2 +238,8 @@ } | ||
if (this._doc && item._id) { | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveMap", | ||
updates: { [key]: { type: "delete" } }, | ||
}); | ||
this._doc.dispatch([ | ||
@@ -219,3 +251,3 @@ { | ||
}, | ||
], item._serialize(this._id, key), [this]); | ||
], item._serialize(this._id, key), storageUpdates); | ||
} | ||
@@ -222,0 +254,0 @@ __classPrivateFieldGet(this, _LiveMap_map, "f").delete(key); |
@@ -34,3 +34,3 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
*/ | ||
_detachChild(child: AbstractCrdt): void; | ||
_detachChild(child: AbstractCrdt): ApplyResult; | ||
/** | ||
@@ -53,2 +53,6 @@ * INTERNAL | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType(): string; | ||
/** | ||
* Transform the LiveObject into a javascript object | ||
@@ -55,0 +59,0 @@ */ |
@@ -133,3 +133,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
child._attach(id, this._doc); | ||
return { reverse, modified: this }; | ||
return { | ||
reverse, | ||
modified: { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { [key]: { type: "update" } }, | ||
}, | ||
}; | ||
} | ||
@@ -140,10 +147,20 @@ /** | ||
_detachChild(child) { | ||
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) { | ||
if (value === child) { | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key); | ||
if (child) { | ||
const reverse = this._serialize(this._id, child._parentKey, this._doc); | ||
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) { | ||
if (value === child) { | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key); | ||
} | ||
} | ||
} | ||
if (child) { | ||
child._detach(); | ||
const storageUpdate = { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { | ||
[child._parentKey]: { type: "delete" }, | ||
}, | ||
}; | ||
return { modified: storageUpdate, reverse }; | ||
} | ||
return { modified: false }; | ||
} | ||
@@ -195,2 +212,8 @@ /** | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType() { | ||
return "LiveObject"; | ||
} | ||
/** | ||
* Transform the LiveObject into a javascript object | ||
@@ -249,2 +272,8 @@ */ | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(keyAsString); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { [key]: { type: "delete" } }, | ||
}); | ||
this._doc.dispatch([ | ||
@@ -257,3 +286,3 @@ { | ||
}, | ||
], reverse, [this]); | ||
], reverse, storageUpdates); | ||
} | ||
@@ -288,2 +317,3 @@ /** | ||
}; | ||
const updateDelta = {}; | ||
for (const key in overrides) { | ||
@@ -312,2 +342,3 @@ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId); | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue); | ||
updateDelta[key] = { type: "update" }; | ||
} | ||
@@ -325,3 +356,9 @@ if (Object.keys(reverseUpdateOp.data).length !== 0) { | ||
} | ||
this._doc.dispatch(ops, reverseOps, [this]); | ||
const storageUpdates = new Map(); | ||
storageUpdates.set(this._id, { | ||
node: this, | ||
type: "LiveObject", | ||
updates: updateDelta, | ||
}); | ||
this._doc.dispatch(ops, reverseOps, storageUpdates); | ||
} | ||
@@ -351,2 +388,3 @@ } | ||
} | ||
let updateDelta = {}; | ||
for (const key in op.data) { | ||
@@ -374,2 +412,3 @@ if (isLocal) { | ||
isModified = true; | ||
updateDelta[key] = { type: "update" }; | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, op.data[key]); | ||
@@ -380,3 +419,12 @@ } | ||
} | ||
return isModified ? { modified: this, reverse } : { modified: false }; | ||
return isModified | ||
? { | ||
modified: { | ||
node: this, | ||
type: "LiveObject", | ||
updates: updateDelta, | ||
}, | ||
reverse, | ||
} | ||
: { modified: false }; | ||
}, _LiveObject_applyDeleteObjectKey = function _LiveObject_applyDeleteObjectKey(op) { | ||
@@ -404,3 +452,10 @@ const key = op.key; | ||
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key); | ||
return { modified: this, reverse }; | ||
return { | ||
modified: { | ||
node: this, | ||
type: "LiveObject", | ||
updates: { [op.key]: { type: "delete" } }, | ||
}, | ||
reverse, | ||
}; | ||
}; |
@@ -23,4 +23,8 @@ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt"; | ||
_attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult; | ||
_detachChild(crdt: AbstractCrdt): void; | ||
_detachChild(crdt: AbstractCrdt): ApplyResult; | ||
_apply(op: Op, isLocal: boolean): ApplyResult; | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType(): string; | ||
} |
@@ -77,3 +77,9 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
} | ||
/** | ||
* INTERNAL | ||
*/ | ||
_getType() { | ||
return "LiveRegister"; | ||
} | ||
} | ||
_LiveRegister_data = new WeakMap(); |
@@ -63,3 +63,3 @@ import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback, StorageCallback, StorageUpdate, BroadcastOptions } from "./types"; | ||
presence: boolean; | ||
nodes: Set<AbstractCrdt>; | ||
storageUpdates: Map<string, StorageUpdate>; | ||
}; | ||
@@ -66,0 +66,0 @@ }; |
@@ -10,3 +10,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
import { getTreesDiffOperations, isSameNodeOrChildOf, remove } from "./utils"; | ||
import { getTreesDiffOperations, isSameNodeOrChildOf, remove, mergeStorageUpdates, } from "./utils"; | ||
import auth, { parseToken } from "./authentication"; | ||
@@ -197,8 +197,8 @@ import { ClientMessageType, ServerMessageType, OpType, } from "./live"; | ||
} | ||
function storageDispatch(ops, reverse, modified) { | ||
function storageDispatch(ops, reverse, storageUpdates) { | ||
if (state.isBatching) { | ||
state.batch.ops.push(...ops); | ||
for (const item of modified) { | ||
state.batch.updates.nodes.add(item); | ||
} | ||
storageUpdates.forEach((value, key) => { | ||
state.batch.updates.storageUpdates.set(key, mergeStorageUpdates(state.batch.updates.storageUpdates.get(key), value)); | ||
}); | ||
state.batch.reverseOps.push(...reverse); | ||
@@ -210,6 +210,6 @@ } | ||
dispatch(ops); | ||
notify({ nodes: new Set(modified) }); | ||
notify({ storageUpdates: storageUpdates }); | ||
} | ||
} | ||
function notify({ nodes = new Set(), presence = false, others = [], }) { | ||
function notify({ storageUpdates = new Map(), presence = false, others = [], }) { | ||
if (others.length > 0) { | ||
@@ -228,24 +228,5 @@ state.others = makeOthers(state.users); | ||
} | ||
if (nodes.size > 0) { | ||
if (storageUpdates.size > 0) { | ||
for (const subscriber of state.listeners.storage) { | ||
subscriber(Array.from(nodes).map((m) => { | ||
if (m instanceof LiveObject) { | ||
return { | ||
type: "LiveObject", | ||
node: m, | ||
}; | ||
} | ||
else if (m instanceof LiveList) { | ||
return { | ||
type: "LiveList", | ||
node: m, | ||
}; | ||
} | ||
else { | ||
return { | ||
type: "LiveMap", | ||
node: m, | ||
}; | ||
} | ||
})); | ||
subscriber(Array.from(storageUpdates.values())); | ||
} | ||
@@ -273,3 +254,6 @@ } | ||
reverse: [], | ||
updates: { nodes: new Set(), presence: false }, | ||
updates: { | ||
storageUpdates: new Map(), | ||
presence: false, | ||
}, | ||
}; | ||
@@ -304,3 +288,3 @@ for (const op of item) { | ||
if (applyOpResult.modified) { | ||
result.updates.nodes.add(applyOpResult.modified); | ||
result.updates.storageUpdates.set(applyOpResult.modified.node._id, mergeStorageUpdates(result.updates.storageUpdates.get(applyOpResult.modified.node._id), applyOpResult.modified)); | ||
result.reverse.unshift(...applyOpResult.reverse); | ||
@@ -333,13 +317,8 @@ } | ||
const previousKey = item._parentKey; | ||
item._parent._setChildKey(op.parentKey, item); | ||
return { | ||
reverse: [ | ||
{ | ||
type: OpType.SetParentKey, | ||
id: item._id, | ||
parentKey: previousKey, | ||
}, | ||
], | ||
modified: item._parent, | ||
}; | ||
if (previousKey === op.parentKey) { | ||
return { modified: false }; | ||
} | ||
else { | ||
return item._parent._setChildKey(op.parentKey, item, previousKey); | ||
} | ||
} | ||
@@ -567,3 +546,3 @@ return { modified: false }; | ||
const updates = { | ||
nodes: new Set(), | ||
storageUpdates: new Map(), | ||
others: [], | ||
@@ -604,5 +583,5 @@ }; | ||
const applyResult = apply(subMessage.ops, false); | ||
for (const node of applyResult.updates.nodes) { | ||
updates.nodes.add(node); | ||
} | ||
applyResult.updates.storageUpdates.forEach((value, key) => { | ||
updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value)); | ||
}); | ||
break; | ||
@@ -901,5 +880,8 @@ } | ||
} | ||
// Clear the redo stack because batch is always called from a local operation | ||
state.redoStack = []; | ||
if (state.batch.ops.length > 0) { | ||
// Only clear the redo stack if something has changed during a batch | ||
// Clear the redo stack because batch is always called from a local operation | ||
state.redoStack = []; | ||
} | ||
if (state.batch.ops.length > 0) { | ||
dispatch(state.batch.ops); | ||
@@ -913,3 +895,3 @@ } | ||
others: [], | ||
nodes: new Set(), | ||
storageUpdates: new Map(), | ||
presence: false, | ||
@@ -1026,3 +1008,7 @@ }, | ||
ops: [], | ||
updates: { nodes: new Set(), presence: false, others: [] }, | ||
updates: { | ||
storageUpdates: new Map(), | ||
presence: false, | ||
others: [], | ||
}, | ||
reverseOps: [], | ||
@@ -1029,0 +1015,0 @@ }, |
@@ -19,13 +19,33 @@ import type { LiveList } from "./LiveList"; | ||
}; | ||
export declare type UpdateDelta = { | ||
type: "update"; | ||
} | { | ||
type: "delete"; | ||
}; | ||
export declare type LiveMapUpdates<TKey extends string = string, TValue = any> = { | ||
type: "LiveMap"; | ||
node: LiveMap<TKey, TValue>; | ||
updates: Record<TKey, UpdateDelta>; | ||
}; | ||
export declare type LiveObjectUpdateDelta<T> = Partial<{ | ||
[Property in keyof T]: UpdateDelta; | ||
}>; | ||
export declare type LiveObjectUpdates<TData = any> = { | ||
type: "LiveObject"; | ||
node: LiveObject<TData>; | ||
updates: LiveObjectUpdateDelta<TData>; | ||
}; | ||
export declare type ListUpdateDelta = { | ||
type: "insert"; | ||
} | { | ||
type: "delete"; | ||
}; | ||
export declare type LiveListUpdateDelta = { | ||
index: number; | ||
type: "insert" | "delete"; | ||
}; | ||
export declare type LiveListUpdates<TItem = any> = { | ||
type: "LiveList"; | ||
node: LiveList<TItem>; | ||
updates: LiveListUpdateDelta[]; | ||
}; | ||
@@ -32,0 +52,0 @@ export declare type BroadcastOptions = { |
import { AbstractCrdt, Doc } from "./AbstractCrdt"; | ||
import { SerializedCrdtWithId, Op, SerializedCrdt } from "./live"; | ||
import { StorageUpdate } from "./types"; | ||
export declare function remove<T>(array: T[], item: T): void; | ||
@@ -10,1 +11,2 @@ export declare function isSameNodeOrChildOf(node: AbstractCrdt, parent: AbstractCrdt): boolean; | ||
export declare function getTreesDiffOperations(currentItems: Map<string, SerializedCrdt>, newItems: Map<string, SerializedCrdt>): Op[]; | ||
export declare function mergeStorageUpdates(first: StorageUpdate | undefined, second: StorageUpdate): StorageUpdate; |
@@ -141,1 +141,25 @@ import { CrdtType, OpType, } from "./live"; | ||
} | ||
export function mergeStorageUpdates(first, second) { | ||
if (!first) { | ||
return second; | ||
} | ||
if (second.type === "LiveObject") { | ||
const updates = first.updates; | ||
for (const [key, value] of Object.entries(second.updates)) { | ||
updates[key] = value; | ||
} | ||
return Object.assign(Object.assign({}, second), { updates: updates }); | ||
} | ||
else if (second.type === "LiveMap") { | ||
const updates = first.updates; | ||
for (const [key, value] of Object.entries(second.updates)) { | ||
updates[key] = value; | ||
} | ||
return Object.assign(Object.assign({}, second), { updates: updates }); | ||
} | ||
else if (second.type === "LiveList") { | ||
const updates = first.updates; | ||
return Object.assign(Object.assign({}, second), { updates: updates.concat(second.updates) }); | ||
} | ||
return second; | ||
} |
{ | ||
"name": "@liveblocks/client", | ||
"version": "0.14.0", | ||
"version": "0.15.0-alpha.1", | ||
"description": "", | ||
@@ -41,2 +41,2 @@ "main": "./lib/cjs/index.js", | ||
} | ||
} | ||
} |
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
340642
58
9158