Socket
Socket
Sign inDemoInstall

@liveblocks/client

Package Overview
Dependencies
Maintainers
2
Versions
379
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@liveblocks/client - npm Package Compare versions

Comparing version 0.12.0-beta.4 to 0.12.0-beta.6

141

lib/cjs/doc.d.ts
import { Op, SerializedCrdtWithId, SerializedList } from "./live";
declare const INTERNAL: unique symbol;
declare type Dispatch = (ops: Op[]) => void;
interface ICrdt {
readonly [INTERNAL]: {
getId(): string | undefined;
getParentId(): string | undefined;
attach(id: string, doc: Doc, parentId?: string, parentKey?: string): Op[];
attachChild(key: any, child: ICrdt): void;
detach(): void;
detachChild(child: ICrdt): void;
};
}
export declare class Doc<T extends Record<string, any> = Record<string, any>> {

@@ -24,4 +13,5 @@ private _root;

dispatch(ops: Op[]): void;
addItem(id: string, item: ICrdt): void;
addItem(id: string, item: AbstractCrdt): void;
deleteItem(id: string): void;
getItem(id: string): AbstractCrdt | undefined;
apply(op: Op): void;

@@ -40,67 +30,54 @@ private applyCreateRegister;

}
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> {
declare class AbstractCrdt {
#private;
private _listeners;
private _deepListeners;
protected get doc(): Doc<Record<string, any>> | undefined;
get id(): string | undefined;
get parent(): AbstractCrdt | undefined;
setParent(parent: AbstractCrdt): void;
attach(id: string, doc: Doc): void;
attachChild(id: string, key: string, crdt: AbstractCrdt): void;
detach(): void;
detachChild(crdt: AbstractCrdt): void;
subscribe(listener: () => void): void;
subscribeDeep(listener: () => void): void;
unsubscribe(listener: () => void): void;
unsubscribeDeep(listener: () => void): void;
notify(onlyDeep?: boolean): void;
serialize(parentId: string, parentKey: string): Op[];
}
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> extends AbstractCrdt {
private _map;
private _listeners;
private _ctx?;
constructor(object?: T);
/**
* INTERNAL
*/
serialize(parentId?: string, parentKey?: string): Op[];
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<{
[key: string]: any;
}>;
get [INTERNAL](): {
ctx: {
id: string;
doc: Doc<Record<string, any>>;
parentId?: string | undefined;
} | undefined;
attachChild: (key: keyof T, child: ICrdt) => void;
detachChild: (child: ICrdt) => void;
detach: () => void;
attach: (id: string, doc: Doc<Record<string, any>>, parentId?: string | undefined, parentKey?: string | undefined) => Op[];
apply: (op: Op) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private attach;
private attachChild;
private detachChild;
private detach;
private apply;
private notify;
attach(id: string, doc: Doc): void;
attachChild(id: string, key: keyof T, child: AbstractCrdt): void;
detachChild(child: AbstractCrdt): void;
detach(): void;
/**
* INTERNAL
*/
apply(op: Op): void;
toObject(): T;
set<TKey extends keyof T>(key: TKey, value: T[TKey]): void;
get<TKey extends keyof T>(key: TKey): T[TKey];
delete<TKey extends keyof T>(key: TKey): void;
update(overrides: Partial<T>): void;
subscribe(listener: () => void): void;
unsubscribe(listener: () => void): void;
}
export declare class LiveMap<TKey extends string, TValue> implements ICrdt {
private _listeners;
export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
private _map;
private _ctx?;
constructor(entries?: readonly (readonly [TKey, TValue])[] | null | undefined);
serialize(parentId?: string, parentKey?: string): Op[];
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveMap<string, unknown>;
get [INTERNAL](): {
ctx: {
id: string;
doc: Doc<Record<string, any>>;
parentId?: string | undefined;
} | undefined;
apply: (op: Op) => void;
attachChild: (key: TKey, child: ICrdt) => void;
attach: (id: string, doc: Doc<Record<string, any>>, parentId: string, parentKey: string) => Op[];
detach: () => void;
detachChild: (child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private apply;
private attach;
private attachChild;
private detach;
private detachChild;
attach(id: string, doc: Doc): void;
attachChild(id: string, key: TKey, child: AbstractCrdt): void;
detach(): void;
detachChild(child: AbstractCrdt): void;
get(key: TKey): TValue | undefined;

@@ -116,36 +93,14 @@ set(key: TKey, value: TValue): void;

forEach(callback: (value: TValue, key: TKey, map: LiveMap<TKey, TValue>) => void): void;
subscribe(listener: () => void): void;
unsubscribe(listener: () => void): void;
private notify;
}
export declare class LiveList<T> implements ICrdt {
private _listeners;
private _ctx?;
export declare class LiveList<T> extends AbstractCrdt {
private _items;
constructor(items?: T[]);
static deserialize([id, item]: [id: string, item: SerializedList], parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveList<never>;
get [INTERNAL](): {
ctx: {
id: string;
parentId: string;
doc: Doc<Record<string, any>>;
} | undefined;
attachChild: (key: string, child: ICrdt) => void;
detachChild: (child: ICrdt) => void;
attach: (id: string, doc: Doc<Record<string, any>>, parentId: string, parentKey: string) => Op[];
detach: () => void;
apply: (op: Op) => void;
setChildKey: (key: string, child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private attach;
private detach;
private attachChild;
private detachChild;
private setChildKey;
serialize(parentId?: string, parentKey?: string): Op[];
attach(id: string, doc: Doc): void;
detach(): void;
attachChild(id: string, key: string, child: AbstractCrdt): void;
detachChild(child: AbstractCrdt): void;
setChildKey(key: string, child: AbstractCrdt): void;
private apply;
private notify;
push(item: T): void;

@@ -157,5 +112,3 @@ insert(item: T, index: number): void;

get(index: number): T;
subscribe(listener: () => void): void;
unsubscribe(listener: () => void): void;
}
export {};
"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
};
var _parent, _doc, _id;
Object.defineProperty(exports, "__esModule", { value: true });

@@ -20,4 +34,4 @@ exports.LiveList = exports.LiveMap = exports.LiveObject = exports.Doc = void 0;

const storage = new Doc(rootRecord, actor, dispatch);
const ops = rootRecord[INTERNAL].attach(storage.generateId(), storage);
storage.dispatch(ops);
rootRecord.attach(storage.generateId(), storage);
storage.dispatch(rootRecord.serialize());
return storage;

@@ -62,2 +76,5 @@ }

}
getItem(id) {
return this._items.get(id);
}
apply(op) {

@@ -100,4 +117,2 @@ switch (op.type) {

applyCreateRegister(op) {
const newRegister = new LiveRegister(op.data);
newRegister[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
const parent = this._items.get(op.parentId);

@@ -110,3 +125,4 @@ if (parent == null) {

}
parent[INTERNAL].attachChild(op.parentKey, newRegister);
const newRegister = new LiveRegister(op.data);
parent.attachChild(op.id, op.parentKey, newRegister);
}

@@ -116,3 +132,3 @@ applyDeleteRecordKey(op) {

if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);
item.apply(op);
}

@@ -123,3 +139,3 @@ }

if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);
item.apply(op);
}

@@ -133,4 +149,3 @@ }

const newMap = new LiveMap();
newMap[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
parent[INTERNAL].attachChild(op.parentKey, newMap);
parent.attachChild(op.id, op.parentKey, newMap);
}

@@ -142,9 +157,6 @@ applyCreateList(op) {

}
const newMap = new LiveList();
newMap[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
parent[INTERNAL].attachChild(op.parentKey, newMap);
const list = new LiveList();
parent.attachChild(op.id, op.parentKey, list);
}
applyCreateObject(op) {
const newObj = new LiveObject(op.data);
newObj[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
if (op.parentId && op.parentKey) {

@@ -155,3 +167,4 @@ const parent = this._items.get(op.parentId);

}
parent[INTERNAL].attachChild(op.parentKey, newObj);
const newObj = new LiveObject(op.data);
parent.attachChild(op.id, op.parentKey, newObj);
}

@@ -164,9 +177,8 @@ }

}
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {
const parent = item.parent;
if (parent == null) {
return;
}
const parent = this._items.get(parentId);
if (parent) {
parent[INTERNAL].detachChild(item);
parent.detachChild(item);
}

@@ -179,9 +191,7 @@ }

}
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {
if (item.parent == null) {
return;
}
const parent = this._items.get(parentId);
if (parent && parent instanceof LiveList) {
parent[INTERNAL].setChildKey(op.parentKey, item);
if (item.parent instanceof LiveList) {
item.parent.setChildKey(op.parentKey, item);
}

@@ -200,72 +210,109 @@ }

exports.Doc = Doc;
class LiveObject {
constructor(object = {}) {
class AbstractCrdt {
constructor() {
this._listeners = [];
this._map = new Map(Object.entries(object));
this._deepListeners = [];
_parent.set(this, void 0);
_doc.set(this, void 0);
_id.set(this, void 0);
}
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== live_1.CrdtType.Object) {
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
get doc() {
return __classPrivateFieldGet(this, _doc);
}
get id() {
return __classPrivateFieldGet(this, _id);
}
get parent() {
return __classPrivateFieldGet(this, _parent);
}
setParent(parent) {
if (__classPrivateFieldGet(this, _parent)) {
throw new Error("Cannot attach parent if it already exist");
}
const record = new LiveObject(item.data);
record.attach(id, doc, item.parentId, item.parentKey);
const children = parentToChildren.get(id);
if (children == null) {
return record;
__classPrivateFieldSet(this, _parent, parent);
}
attach(id, doc) {
if (__classPrivateFieldGet(this, _id) || __classPrivateFieldGet(this, _doc)) {
throw new Error("Cannot attach if CRDT is already attached");
}
for (const entry of children) {
const crdt = entry[1];
if (crdt.parentKey == null) {
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
}
const child = deserialize(entry, parentToChildren, doc);
record._map.set(crdt.parentKey, child);
doc.addItem(id, this);
__classPrivateFieldSet(this, _id, id);
__classPrivateFieldSet(this, _doc, doc);
}
attachChild(id, key, crdt) {
throw new Error("attachChild should be implement by a non abstract CRDT");
}
detach() {
if (__classPrivateFieldGet(this, _doc) && __classPrivateFieldGet(this, _id)) {
__classPrivateFieldGet(this, _doc).deleteItem(__classPrivateFieldGet(this, _id));
}
return record;
__classPrivateFieldSet(this, _parent, undefined);
__classPrivateFieldSet(this, _doc, undefined);
}
get [INTERNAL]() {
return {
ctx: this._ctx,
attachChild: this.attachChild.bind(this),
detachChild: this.detachChild.bind(this),
detach: this.detach.bind(this),
attach: this.attach.bind(this),
apply: this.apply.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
detachChild(crdt) {
throw new Error("detach child should be implement by a non abstract CRDT");
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
subscribe(listener) {
this._listeners.push(listener);
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
subscribeDeep(listener) {
this._deepListeners.push(listener);
}
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveObject is already part of the storage");
unsubscribe(listener) {
utils_1.remove(this._listeners, listener);
}
unsubscribeDeep(listener) {
utils_1.remove(this._deepListeners, listener);
}
notify(onlyDeep = false) {
if (onlyDeep === false) {
for (const listener of this._listeners) {
listener();
}
}
doc.addItem(id, this);
this._ctx = {
id,
doc: doc,
parentId,
};
for (const listener of this._deepListeners) {
listener();
}
if (this.parent) {
this.parent.notify(true);
}
}
serialize(parentId, parentKey) {
throw new Error("serialize should be implement by a non abstract CRDT");
}
}
_parent = new WeakMap(), _doc = new WeakMap(), _id = new WeakMap();
class LiveObject extends AbstractCrdt {
constructor(object = {}) {
super();
for (const key in object) {
const value = object[key];
if (value instanceof AbstractCrdt) {
value.setParent(this);
}
}
this._map = new Map(Object.entries(object));
}
/**
* INTERNAL
*/
serialize(parentId, parentKey) {
if (this.id == null) {
throw new Error("Cannot serialize item is not attached");
}
const ops = [];
const createOp = {
id: this._ctx.id,
const op = {
id: this.id,
type: live_1.OpType.CreateObject,
parentId,
parentKey,
data: {},
data: {}
};
ops.push(createOp);
ops.push(op);
for (const [key, value] of this._map) {
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
if (value instanceof AbstractCrdt) {
ops.push(...value.serialize(this.id, key));
}
else {
createOp.data[key] = value;
op.data[key] = value;
}

@@ -275,8 +322,42 @@ }

}
attachChild(key, child) {
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== live_1.CrdtType.Object) {
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
}
const object = new LiveObject(item.data);
object.attach(id, doc);
const children = parentToChildren.get(id);
if (children == null) {
return object;
}
for (const entry of children) {
const crdt = entry[1];
if (crdt.parentKey == null) {
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
}
const child = deserialize(entry, parentToChildren, doc);
child.setParent(object);
object._map.set(crdt.parentKey, child);
}
return object;
}
attach(id, doc) {
super.attach(id, doc);
for (const [key, value] of this._map) {
if (value instanceof AbstractCrdt) {
value.attach(doc.generateId(), doc);
}
}
}
attachChild(id, key, child) {
if (this.doc == null) {
throw new Error("Can't attach child if doc is not present");
}
const previousValue = this._map.get(key);
if (isCrdt(previousValue)) {
previousValue[INTERNAL].detach();
previousValue.detach();
}
this._map.set(key, child);
child.setParent(this);
child.attach(id, this.doc);
this.notify();

@@ -291,3 +372,3 @@ }

if (child) {
child[INTERNAL].detach();
child.detach();
}

@@ -297,12 +378,12 @@ this.notify();

detach() {
if (this._ctx == null) {
return;
}
this._ctx.doc.deleteItem(this._ctx.id);
super.detach();
for (const value of this._map.values()) {
if (isCrdt(value)) {
value[INTERNAL].detach();
value.detach();
}
}
}
/**
* INTERNAL
*/
apply(op) {

@@ -313,3 +394,3 @@ if (op.type === live_1.OpType.UpdateObject) {

if (isCrdt(oldValue)) {
oldValue[INTERNAL].detach();
oldValue.detach();
}

@@ -325,3 +406,3 @@ const value = op.data[key];

if (isCrdt(oldValue)) {
oldValue[INTERNAL].detach();
oldValue.detach();
}

@@ -332,7 +413,2 @@ this._map.delete(key);

}
notify() {
for (const listener of this._listeners) {
listener();
}
}
toObject() {

@@ -348,63 +424,70 @@ return Object.fromEntries(this._map);

}
delete(key) {
if (this._ctx) {
const ops = [];
const item = this._map.get(key);
if (isCrdt(item)) {
item[INTERNAL].detach();
}
this._ctx.doc.dispatch([
{ type: live_1.OpType.DeleteObjectKey, id: this._ctx.id, key: key },
]);
}
this._map.delete(key);
this.notify();
}
// delete<TKey extends keyof T>(key: TKey) {
// if (this.doc && this.id) {
// const item = this._map.get(key as string);
// if (isCrdt(item)) {
// item.detach();
// }
// this.doc.dispatch([
// { type: OpType.DeleteObjectKey, id: this.id, key: key as string },
// ]);
// }
// this._map.delete(key as string);
// this.notify();
// }
update(overrides) {
if (this._ctx) {
if (this.doc && this.id) {
const ops = [];
const updateOperation = {
id: this._ctx.id,
const updateOp = {
id: this.id,
type: live_1.OpType.UpdateObject,
data: {},
data: {}
};
ops.push(updateOperation);
ops.push(updateOp);
for (const key in overrides) {
const oldValue = this._map.get(key);
if (isCrdt(oldValue)) {
oldValue[INTERNAL].detach();
if (oldValue instanceof LiveObject) {
oldValue.detach();
}
const value = overrides[key];
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
const newValue = overrides[key];
if (newValue instanceof AbstractCrdt) {
newValue.setParent(this);
newValue.attach(this.doc.generateId(), this.doc);
ops.push(...newValue.serialize(this.id, key));
}
else {
updateOperation.data[key] = value;
updateOp.data[key] = newValue;
}
this._map.set(key, value);
this._map.set(key, newValue);
}
this._ctx.doc.dispatch(ops);
this.doc.dispatch(ops);
this.notify();
return;
}
else {
for (const key in overrides) {
const value = overrides[key];
this._map.set(key, value);
for (const key in overrides) {
const oldValue = this._map.get(key);
if (oldValue instanceof AbstractCrdt) {
oldValue.detach();
}
this.notify();
const newValue = overrides[key];
if (newValue instanceof AbstractCrdt) {
newValue.setParent(this);
}
this._map.set(key, newValue);
}
this.notify();
}
subscribe(listener) {
this._listeners.push(listener);
}
unsubscribe(listener) {
utils_1.remove(this._listeners, listener);
}
}
exports.LiveObject = LiveObject;
class LiveMap {
class LiveMap extends AbstractCrdt {
constructor(entries) {
this._listeners = [];
super();
if (entries) {
this._map = new Map(entries.map((entry) => [entry[0], selfOrRegister(entry[1])]));
const mappedEntries = [];
for (const entry of entries) {
const value = selfOrRegister(entry[1]);
value.setParent(this);
mappedEntries.push([entry[0], value]);
}
this._map = new Map(mappedEntries);
}

@@ -415,2 +498,22 @@ else {

}
serialize(parentId, parentKey) {
if (this.id == null) {
throw new Error("Cannot serialize item is not attached");
}
if (parentId == null || parentKey == null) {
throw new Error("Cannot serialize map if parentId or parentKey is undefined");
}
const ops = [];
const op = {
id: this.id,
type: live_1.OpType.CreateMap,
parentId,
parentKey,
};
ops.push(op);
for (const [key, value] of this._map) {
ops.push(...value.serialize(this.id, key));
}
return ops;
}
static deserialize([id, item], parentToChildren, doc) {

@@ -421,3 +524,3 @@ if (item.type !== live_1.CrdtType.Map) {

const map = new LiveMap();
map.attach(id, doc, item.parentId, item.parentKey);
map.attach(id, doc);
const children = parentToChildren.get(id);

@@ -433,2 +536,3 @@ if (children == null) {

const child = deserialize(entry, parentToChildren, doc);
child.setParent(map);
map._map.set(crdt.parentKey, child);

@@ -438,53 +542,21 @@ }

}
get [INTERNAL]() {
return {
ctx: this._ctx,
apply: this.apply.bind(this),
attachChild: this.attachChild.bind(this),
attach: this.attach.bind(this),
detach: this.detach.bind(this),
detachChild: this.detachChild.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
}
apply(op) { }
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveMap is already part of the storage");
}
doc.addItem(id, this);
this._ctx = {
id,
doc: doc,
parentId,
};
const ops = [];
const createOp = {
id: this._ctx.id,
type: live_1.OpType.CreateMap,
parentId,
parentKey,
};
ops.push(createOp);
attach(id, doc) {
super.attach(id, doc);
for (const [key, value] of this._map) {
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
value.attach(doc.generateId(), doc);
}
}
return ops;
}
attachChild(key, child) {
attachChild(id, key, child) {
if (this.doc == null) {
throw new Error("Can't attach child if doc is not present");
}
const previousValue = this._map.get(key);
if (previousValue) {
previousValue[INTERNAL].detach();
previousValue.detach();
}
child.setParent(this);
child.attach(id, this.doc);
this._map.set(key, child);

@@ -494,9 +566,6 @@ this.notify();

detach() {
if (this._ctx == null) {
return;
}
super.detach();
for (const item of this._map.values()) {
item[INTERNAL].detach();
item.detach();
}
this._ctx.doc.deleteItem(this._ctx.id);
}

@@ -509,3 +578,3 @@ detachChild(child) {

}
child[INTERNAL].detach();
child.detach();
this.notify();

@@ -521,19 +590,15 @@ }

set(key, value) {
if (this._ctx) {
const ops = [];
const oldValue = this._map.get(key);
if (oldValue) {
oldValue[INTERNAL].detach();
}
const item = selfOrRegister(value);
ops.push(...item[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
this._map.set(key, item);
this._ctx.doc.dispatch(ops);
this.notify();
const oldValue = this._map.get(key);
if (oldValue) {
oldValue.detach();
}
else {
const item = selfOrRegister(value);
this._map.set(key, item);
this.notify();
const item = selfOrRegister(value);
item.setParent(this);
this._map.set(key, item);
if (this.doc && this.id) {
item.attach(this.doc.generateId(), this.doc);
const ops = item.serialize(this.id, key);
this.doc.dispatch(ops);
}
this.notify();
}

@@ -547,17 +612,13 @@ get size() {

delete(key) {
if (this._ctx) {
const item = this._map.get(key);
if (item) {
const itemId = item[INTERNAL].getId();
if (itemId != null) {
item[INTERNAL].detach();
this._ctx.doc.dispatch([{ type: live_1.OpType.DeleteCrdt, id: itemId }]);
}
}
const item = this._map.get(key);
if (item == null) {
return false;
}
const isDeleted = this._map.delete(key);
if (isDeleted) {
this.notify();
item.detach();
if (this.doc && item.id) {
this.doc.dispatch([{ type: live_1.OpType.DeleteCrdt, id: item.id }]);
}
return isDeleted;
this._map.delete(key);
this.notify();
return true;
}

@@ -616,36 +677,7 @@ entries() {

}
subscribe(listener) {
this._listeners.push(listener);
}
unsubscribe(listener) {
utils_1.remove(this._listeners, listener);
}
notify() {
for (const listener of this._listeners) {
listener();
}
}
}
exports.LiveMap = LiveMap;
function selfOrRegisterValue(obj) {
if (obj instanceof LiveRegister) {
return obj.data;
}
return obj;
}
function selfOrRegister(obj) {
if (obj instanceof LiveObject ||
obj instanceof LiveMap ||
obj instanceof LiveList) {
return obj;
}
else if (obj instanceof LiveRegister) {
throw new Error("Internal error. LiveRegister should not be created from LiveRegister");
}
else {
return new LiveRegister(obj);
}
}
class LiveRegister {
class LiveRegister extends AbstractCrdt {
constructor(data) {
super();
this._data = data;

@@ -661,60 +693,21 @@ }

const register = new LiveRegister(item.data);
register.attach(id, doc, item.parentId, item.parentKey);
register.attach(id, doc);
return register;
}
get [INTERNAL]() {
return {
ctx: this._ctx,
attach: this.attach.bind(this),
detach: this.detach.bind(this),
attachChild: this.attachChild.bind(this),
detachChild: this.detachChild.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
}
detachChild(crdt) {
throw new Error("Internal error: cannot detach CRDT on register");
}
detach() {
if (this._ctx) {
this._ctx.doc.deleteItem(this._ctx.id);
serialize(parentId, parentKey) {
if (this.id == null || parentId == null || parentKey == null) {
throw new Error("Cannot serialize register if parentId or parentKey is undefined");
}
return [{
type: live_1.OpType.CreateRegister,
id: this.id,
parentId,
parentKey,
data: this.data
}];
}
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveRegister is already part of the storage");
}
doc.addItem(id, this);
this._ctx = {
id,
doc: doc,
parentId,
};
const ops = [];
const createOp = {
id,
type: live_1.OpType.CreateRegister,
parentId,
parentKey,
data: this._data,
};
ops.push(createOp);
return ops;
}
attachChild(key, child) {
throw new Error("Cannot attach child to register");
}
}
class LiveList {
class LiveList extends AbstractCrdt {
constructor(items = []) {
this._listeners = [];
super();
// TODO: Naive array at first, find a better data structure

@@ -732,3 +725,3 @@ this._items = [];

const list = new LiveList([]);
list.attach(id, doc, item.parentId, item.parentKey);
list.attach(id, doc);
const children = parentToChildren.get(id);

@@ -740,40 +733,18 @@ if (children == null) {

const child = deserialize(entry, parentToChildren, doc);
list.attachChild(entry[1].parentKey, child);
child.setParent(list);
list._items.push([child, entry[1].parentKey]);
list._items.sort((itemA, itemB) => position_1.compare({ position: itemA[1] }, { position: itemB[1] }));
}
return list;
}
get [INTERNAL]() {
return {
ctx: this._ctx,
attachChild: this.attachChild.bind(this),
detachChild: this.detachChild.bind(this),
attach: this.attach.bind(this),
detach: this.detach.bind(this),
apply: this.apply.bind(this),
setChildKey: this.setChildKey.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
}
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveList is already part of the storage");
serialize(parentId, parentKey) {
if (this.id == null) {
throw new Error("Cannot serialize item is not attached");
}
doc.addItem(id, this);
this._ctx = {
doc: doc,
id: id,
parentId: parentId,
};
if (parentId == null || parentKey == null) {
throw new Error("Cannot serialize list if parentId or parentKey is undefined");
}
const ops = [];
const createOp = {
id: this._ctx.id,
const op = {
id: this.id,
type: live_1.OpType.CreateList,

@@ -783,18 +754,26 @@ parentId,

};
ops.push(createOp);
for (const [item, position] of this._items) {
ops.push(...item[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, position));
ops.push(op);
for (const [value, key] of this._items) {
ops.push(...value.serialize(this.id, key));
}
return ops;
}
attach(id, doc) {
super.attach(id, doc);
for (const [item, position] of this._items) {
item.attach(doc.generateId(), doc);
}
}
detach() {
if (this._ctx == null) {
return;
}
super.detach();
for (const [value] of this._items) {
value[INTERNAL].detach();
value.detach();
}
this._ctx.doc.deleteItem(this._ctx.id);
}
attachChild(key, child) {
attachChild(id, key, child) {
if (this.doc == null) {
throw new Error("Can't attach child if doc is not present");
}
child.attach(id, this.doc);
child.setParent(this);
// TODO: Handle list conflict

@@ -809,3 +788,3 @@ this._items.push([child, key]);

if (child) {
child[INTERNAL].detach();
child.detach();
}

@@ -823,7 +802,2 @@ this.notify();

apply(op) { }
notify() {
for (const listener of this._listeners) {
listener();
}
}
push(item) {

@@ -834,7 +808,8 @@ const position = this._items.length === 0

const value = selfOrRegister(item);
value.setParent(this);
this._items.push([value, position]);
this.notify();
if (this._ctx) {
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);
if (this.doc && this.id) {
value.attach(this.doc.generateId(), this.doc);
this.doc.dispatch(value.serialize(this.id, position));
}

@@ -850,8 +825,9 @@ }

const value = selfOrRegister(item);
value.setParent(this);
this._items.push([value, position]);
this._items.sort((itemA, itemB) => position_1.compare({ position: itemA[1] }, { position: itemB[1] }));
this.notify();
if (this._ctx) {
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);
if (this.doc && this.id) {
value.attach(this.doc.generateId(), this.doc);
this.doc.dispatch(value.serialize(this.id, position));
}

@@ -891,14 +867,8 @@ }

this.notify();
if (this._ctx) {
const id = item[0][INTERNAL].getId();
if (id == null) {
throw new Error("Internal error. Cannot set parent key from ");
}
this._ctx.doc.dispatch([
{
if (this.doc && this.id) {
this.doc.dispatch([{
type: live_1.OpType.SetParentKey,
id: id,
id: item[0].id,
parentKey: position,
},
]);
},]);
}

@@ -911,12 +881,14 @@ }

const item = this._items[index];
item[0].detach();
this._items.splice(index, 1);
if (this._ctx) {
const childRecord = item[0];
this._ctx.doc.dispatch([
{
id: childRecord[INTERNAL].ctx.id,
type: live_1.OpType.DeleteCrdt,
},
]);
childRecord[INTERNAL].detach();
if (this.doc) {
const childRecordId = item[0].id;
if (childRecordId) {
this.doc.dispatch([
{
id: childRecordId,
type: live_1.OpType.DeleteCrdt,
},
]);
}
}

@@ -931,8 +903,2 @@ this.notify();

}
subscribe(listener) {
this._listeners.push(listener);
}
unsubscribe(listener) {
utils_1.remove(this._listeners, listener);
}
}

@@ -965,1 +931,20 @@ exports.LiveList = LiveList;

}
function selfOrRegisterValue(obj) {
if (obj instanceof LiveRegister) {
return obj.data;
}
return obj;
}
function selfOrRegister(obj) {
if (obj instanceof LiveObject ||
obj instanceof LiveMap ||
obj instanceof LiveList) {
return obj;
}
else if (obj instanceof LiveRegister) {
throw new Error("Internal error. LiveRegister should not be created from selfOrRegister");
}
else {
return new LiveRegister(obj);
}
}
import { Op, SerializedCrdtWithId, SerializedList } from "./live";
declare const INTERNAL: unique symbol;
declare type Dispatch = (ops: Op[]) => void;
interface ICrdt {
readonly [INTERNAL]: {
getId(): string | undefined;
getParentId(): string | undefined;
attach(id: string, doc: Doc, parentId?: string, parentKey?: string): Op[];
attachChild(key: any, child: ICrdt): void;
detach(): void;
detachChild(child: ICrdt): void;
};
}
export declare class Doc<T extends Record<string, any> = Record<string, any>> {

@@ -24,4 +13,5 @@ private _root;

dispatch(ops: Op[]): void;
addItem(id: string, item: ICrdt): void;
addItem(id: string, item: AbstractCrdt): void;
deleteItem(id: string): void;
getItem(id: string): AbstractCrdt | undefined;
apply(op: Op): void;

@@ -40,67 +30,54 @@ private applyCreateRegister;

}
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> {
declare class AbstractCrdt {
#private;
private _listeners;
private _deepListeners;
protected get doc(): Doc<Record<string, any>> | undefined;
get id(): string | undefined;
get parent(): AbstractCrdt | undefined;
setParent(parent: AbstractCrdt): void;
attach(id: string, doc: Doc): void;
attachChild(id: string, key: string, crdt: AbstractCrdt): void;
detach(): void;
detachChild(crdt: AbstractCrdt): void;
subscribe(listener: () => void): void;
subscribeDeep(listener: () => void): void;
unsubscribe(listener: () => void): void;
unsubscribeDeep(listener: () => void): void;
notify(onlyDeep?: boolean): void;
serialize(parentId: string, parentKey: string): Op[];
}
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> extends AbstractCrdt {
private _map;
private _listeners;
private _ctx?;
constructor(object?: T);
/**
* INTERNAL
*/
serialize(parentId?: string, parentKey?: string): Op[];
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<{
[key: string]: any;
}>;
get [INTERNAL](): {
ctx: {
id: string;
doc: Doc<Record<string, any>>;
parentId?: string | undefined;
} | undefined;
attachChild: (key: keyof T, child: ICrdt) => void;
detachChild: (child: ICrdt) => void;
detach: () => void;
attach: (id: string, doc: Doc<Record<string, any>>, parentId?: string | undefined, parentKey?: string | undefined) => Op[];
apply: (op: Op) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private attach;
private attachChild;
private detachChild;
private detach;
private apply;
private notify;
attach(id: string, doc: Doc): void;
attachChild(id: string, key: keyof T, child: AbstractCrdt): void;
detachChild(child: AbstractCrdt): void;
detach(): void;
/**
* INTERNAL
*/
apply(op: Op): void;
toObject(): T;
set<TKey extends keyof T>(key: TKey, value: T[TKey]): void;
get<TKey extends keyof T>(key: TKey): T[TKey];
delete<TKey extends keyof T>(key: TKey): void;
update(overrides: Partial<T>): void;
subscribe(listener: () => void): void;
unsubscribe(listener: () => void): void;
}
export declare class LiveMap<TKey extends string, TValue> implements ICrdt {
private _listeners;
export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
private _map;
private _ctx?;
constructor(entries?: readonly (readonly [TKey, TValue])[] | null | undefined);
serialize(parentId?: string, parentKey?: string): Op[];
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveMap<string, unknown>;
get [INTERNAL](): {
ctx: {
id: string;
doc: Doc<Record<string, any>>;
parentId?: string | undefined;
} | undefined;
apply: (op: Op) => void;
attachChild: (key: TKey, child: ICrdt) => void;
attach: (id: string, doc: Doc<Record<string, any>>, parentId: string, parentKey: string) => Op[];
detach: () => void;
detachChild: (child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private apply;
private attach;
private attachChild;
private detach;
private detachChild;
attach(id: string, doc: Doc): void;
attachChild(id: string, key: TKey, child: AbstractCrdt): void;
detach(): void;
detachChild(child: AbstractCrdt): void;
get(key: TKey): TValue | undefined;

@@ -116,36 +93,14 @@ set(key: TKey, value: TValue): void;

forEach(callback: (value: TValue, key: TKey, map: LiveMap<TKey, TValue>) => void): void;
subscribe(listener: () => void): void;
unsubscribe(listener: () => void): void;
private notify;
}
export declare class LiveList<T> implements ICrdt {
private _listeners;
private _ctx?;
export declare class LiveList<T> extends AbstractCrdt {
private _items;
constructor(items?: T[]);
static deserialize([id, item]: [id: string, item: SerializedList], parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveList<never>;
get [INTERNAL](): {
ctx: {
id: string;
parentId: string;
doc: Doc<Record<string, any>>;
} | undefined;
attachChild: (key: string, child: ICrdt) => void;
detachChild: (child: ICrdt) => void;
attach: (id: string, doc: Doc<Record<string, any>>, parentId: string, parentKey: string) => Op[];
detach: () => void;
apply: (op: Op) => void;
setChildKey: (key: string, child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private attach;
private detach;
private attachChild;
private detachChild;
private setChildKey;
serialize(parentId?: string, parentKey?: string): Op[];
attach(id: string, doc: Doc): void;
detach(): void;
attachChild(id: string, key: string, child: AbstractCrdt): void;
detachChild(child: AbstractCrdt): void;
setChildKey(key: string, child: AbstractCrdt): void;
private apply;
private notify;
push(item: T): void;

@@ -157,5 +112,3 @@ insert(item: T, index: number): void;

get(index: number): T;
subscribe(listener: () => void): void;
unsubscribe(listener: () => void): void;
}
export {};

@@ -0,1 +1,15 @@

var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
};
var _parent, _doc, _id;
import { remove } from "./utils";

@@ -17,4 +31,4 @@ import { CrdtType, OpType, } from "./live";

const storage = new Doc(rootRecord, actor, dispatch);
const ops = rootRecord[INTERNAL].attach(storage.generateId(), storage);
storage.dispatch(ops);
rootRecord.attach(storage.generateId(), storage);
storage.dispatch(rootRecord.serialize());
return storage;

@@ -59,2 +73,5 @@ }

}
getItem(id) {
return this._items.get(id);
}
apply(op) {

@@ -97,4 +114,2 @@ switch (op.type) {

applyCreateRegister(op) {
const newRegister = new LiveRegister(op.data);
newRegister[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
const parent = this._items.get(op.parentId);

@@ -107,3 +122,4 @@ if (parent == null) {

}
parent[INTERNAL].attachChild(op.parentKey, newRegister);
const newRegister = new LiveRegister(op.data);
parent.attachChild(op.id, op.parentKey, newRegister);
}

@@ -113,3 +129,3 @@ applyDeleteRecordKey(op) {

if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);
item.apply(op);
}

@@ -120,3 +136,3 @@ }

if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);
item.apply(op);
}

@@ -130,4 +146,3 @@ }

const newMap = new LiveMap();
newMap[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
parent[INTERNAL].attachChild(op.parentKey, newMap);
parent.attachChild(op.id, op.parentKey, newMap);
}

@@ -139,9 +154,6 @@ applyCreateList(op) {

}
const newMap = new LiveList();
newMap[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
parent[INTERNAL].attachChild(op.parentKey, newMap);
const list = new LiveList();
parent.attachChild(op.id, op.parentKey, list);
}
applyCreateObject(op) {
const newObj = new LiveObject(op.data);
newObj[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
if (op.parentId && op.parentKey) {

@@ -152,3 +164,4 @@ const parent = this._items.get(op.parentId);

}
parent[INTERNAL].attachChild(op.parentKey, newObj);
const newObj = new LiveObject(op.data);
parent.attachChild(op.id, op.parentKey, newObj);
}

@@ -161,9 +174,8 @@ }

}
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {
const parent = item.parent;
if (parent == null) {
return;
}
const parent = this._items.get(parentId);
if (parent) {
parent[INTERNAL].detachChild(item);
parent.detachChild(item);
}

@@ -176,9 +188,7 @@ }

}
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {
if (item.parent == null) {
return;
}
const parent = this._items.get(parentId);
if (parent && parent instanceof LiveList) {
parent[INTERNAL].setChildKey(op.parentKey, item);
if (item.parent instanceof LiveList) {
item.parent.setChildKey(op.parentKey, item);
}

@@ -196,72 +206,109 @@ }

}
export class LiveObject {
constructor(object = {}) {
class AbstractCrdt {
constructor() {
this._listeners = [];
this._map = new Map(Object.entries(object));
this._deepListeners = [];
_parent.set(this, void 0);
_doc.set(this, void 0);
_id.set(this, void 0);
}
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== CrdtType.Object) {
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
get doc() {
return __classPrivateFieldGet(this, _doc);
}
get id() {
return __classPrivateFieldGet(this, _id);
}
get parent() {
return __classPrivateFieldGet(this, _parent);
}
setParent(parent) {
if (__classPrivateFieldGet(this, _parent)) {
throw new Error("Cannot attach parent if it already exist");
}
const record = new LiveObject(item.data);
record.attach(id, doc, item.parentId, item.parentKey);
const children = parentToChildren.get(id);
if (children == null) {
return record;
__classPrivateFieldSet(this, _parent, parent);
}
attach(id, doc) {
if (__classPrivateFieldGet(this, _id) || __classPrivateFieldGet(this, _doc)) {
throw new Error("Cannot attach if CRDT is already attached");
}
for (const entry of children) {
const crdt = entry[1];
if (crdt.parentKey == null) {
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
}
const child = deserialize(entry, parentToChildren, doc);
record._map.set(crdt.parentKey, child);
doc.addItem(id, this);
__classPrivateFieldSet(this, _id, id);
__classPrivateFieldSet(this, _doc, doc);
}
attachChild(id, key, crdt) {
throw new Error("attachChild should be implement by a non abstract CRDT");
}
detach() {
if (__classPrivateFieldGet(this, _doc) && __classPrivateFieldGet(this, _id)) {
__classPrivateFieldGet(this, _doc).deleteItem(__classPrivateFieldGet(this, _id));
}
return record;
__classPrivateFieldSet(this, _parent, undefined);
__classPrivateFieldSet(this, _doc, undefined);
}
get [INTERNAL]() {
return {
ctx: this._ctx,
attachChild: this.attachChild.bind(this),
detachChild: this.detachChild.bind(this),
detach: this.detach.bind(this),
attach: this.attach.bind(this),
apply: this.apply.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
detachChild(crdt) {
throw new Error("detach child should be implement by a non abstract CRDT");
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
subscribe(listener) {
this._listeners.push(listener);
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
subscribeDeep(listener) {
this._deepListeners.push(listener);
}
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveObject is already part of the storage");
unsubscribe(listener) {
remove(this._listeners, listener);
}
unsubscribeDeep(listener) {
remove(this._deepListeners, listener);
}
notify(onlyDeep = false) {
if (onlyDeep === false) {
for (const listener of this._listeners) {
listener();
}
}
doc.addItem(id, this);
this._ctx = {
id,
doc: doc,
parentId,
};
for (const listener of this._deepListeners) {
listener();
}
if (this.parent) {
this.parent.notify(true);
}
}
serialize(parentId, parentKey) {
throw new Error("serialize should be implement by a non abstract CRDT");
}
}
_parent = new WeakMap(), _doc = new WeakMap(), _id = new WeakMap();
export class LiveObject extends AbstractCrdt {
constructor(object = {}) {
super();
for (const key in object) {
const value = object[key];
if (value instanceof AbstractCrdt) {
value.setParent(this);
}
}
this._map = new Map(Object.entries(object));
}
/**
* INTERNAL
*/
serialize(parentId, parentKey) {
if (this.id == null) {
throw new Error("Cannot serialize item is not attached");
}
const ops = [];
const createOp = {
id: this._ctx.id,
const op = {
id: this.id,
type: OpType.CreateObject,
parentId,
parentKey,
data: {},
data: {}
};
ops.push(createOp);
ops.push(op);
for (const [key, value] of this._map) {
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
if (value instanceof AbstractCrdt) {
ops.push(...value.serialize(this.id, key));
}
else {
createOp.data[key] = value;
op.data[key] = value;
}

@@ -271,8 +318,42 @@ }

}
attachChild(key, child) {
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== CrdtType.Object) {
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
}
const object = new LiveObject(item.data);
object.attach(id, doc);
const children = parentToChildren.get(id);
if (children == null) {
return object;
}
for (const entry of children) {
const crdt = entry[1];
if (crdt.parentKey == null) {
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
}
const child = deserialize(entry, parentToChildren, doc);
child.setParent(object);
object._map.set(crdt.parentKey, child);
}
return object;
}
attach(id, doc) {
super.attach(id, doc);
for (const [key, value] of this._map) {
if (value instanceof AbstractCrdt) {
value.attach(doc.generateId(), doc);
}
}
}
attachChild(id, key, child) {
if (this.doc == null) {
throw new Error("Can't attach child if doc is not present");
}
const previousValue = this._map.get(key);
if (isCrdt(previousValue)) {
previousValue[INTERNAL].detach();
previousValue.detach();
}
this._map.set(key, child);
child.setParent(this);
child.attach(id, this.doc);
this.notify();

@@ -287,3 +368,3 @@ }

if (child) {
child[INTERNAL].detach();
child.detach();
}

@@ -293,12 +374,12 @@ this.notify();

detach() {
if (this._ctx == null) {
return;
}
this._ctx.doc.deleteItem(this._ctx.id);
super.detach();
for (const value of this._map.values()) {
if (isCrdt(value)) {
value[INTERNAL].detach();
value.detach();
}
}
}
/**
* INTERNAL
*/
apply(op) {

@@ -309,3 +390,3 @@ if (op.type === OpType.UpdateObject) {

if (isCrdt(oldValue)) {
oldValue[INTERNAL].detach();
oldValue.detach();
}

@@ -321,3 +402,3 @@ const value = op.data[key];

if (isCrdt(oldValue)) {
oldValue[INTERNAL].detach();
oldValue.detach();
}

@@ -328,7 +409,2 @@ this._map.delete(key);

}
notify() {
for (const listener of this._listeners) {
listener();
}
}
toObject() {

@@ -344,62 +420,69 @@ return Object.fromEntries(this._map);

}
delete(key) {
if (this._ctx) {
const ops = [];
const item = this._map.get(key);
if (isCrdt(item)) {
item[INTERNAL].detach();
}
this._ctx.doc.dispatch([
{ type: OpType.DeleteObjectKey, id: this._ctx.id, key: key },
]);
}
this._map.delete(key);
this.notify();
}
// delete<TKey extends keyof T>(key: TKey) {
// if (this.doc && this.id) {
// const item = this._map.get(key as string);
// if (isCrdt(item)) {
// item.detach();
// }
// this.doc.dispatch([
// { type: OpType.DeleteObjectKey, id: this.id, key: key as string },
// ]);
// }
// this._map.delete(key as string);
// this.notify();
// }
update(overrides) {
if (this._ctx) {
if (this.doc && this.id) {
const ops = [];
const updateOperation = {
id: this._ctx.id,
const updateOp = {
id: this.id,
type: OpType.UpdateObject,
data: {},
data: {}
};
ops.push(updateOperation);
ops.push(updateOp);
for (const key in overrides) {
const oldValue = this._map.get(key);
if (isCrdt(oldValue)) {
oldValue[INTERNAL].detach();
if (oldValue instanceof LiveObject) {
oldValue.detach();
}
const value = overrides[key];
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
const newValue = overrides[key];
if (newValue instanceof AbstractCrdt) {
newValue.setParent(this);
newValue.attach(this.doc.generateId(), this.doc);
ops.push(...newValue.serialize(this.id, key));
}
else {
updateOperation.data[key] = value;
updateOp.data[key] = newValue;
}
this._map.set(key, value);
this._map.set(key, newValue);
}
this._ctx.doc.dispatch(ops);
this.doc.dispatch(ops);
this.notify();
return;
}
else {
for (const key in overrides) {
const value = overrides[key];
this._map.set(key, value);
for (const key in overrides) {
const oldValue = this._map.get(key);
if (oldValue instanceof AbstractCrdt) {
oldValue.detach();
}
this.notify();
const newValue = overrides[key];
if (newValue instanceof AbstractCrdt) {
newValue.setParent(this);
}
this._map.set(key, newValue);
}
this.notify();
}
subscribe(listener) {
this._listeners.push(listener);
}
unsubscribe(listener) {
remove(this._listeners, listener);
}
}
export class LiveMap {
export class LiveMap extends AbstractCrdt {
constructor(entries) {
this._listeners = [];
super();
if (entries) {
this._map = new Map(entries.map((entry) => [entry[0], selfOrRegister(entry[1])]));
const mappedEntries = [];
for (const entry of entries) {
const value = selfOrRegister(entry[1]);
value.setParent(this);
mappedEntries.push([entry[0], value]);
}
this._map = new Map(mappedEntries);
}

@@ -410,2 +493,22 @@ else {

}
serialize(parentId, parentKey) {
if (this.id == null) {
throw new Error("Cannot serialize item is not attached");
}
if (parentId == null || parentKey == null) {
throw new Error("Cannot serialize map if parentId or parentKey is undefined");
}
const ops = [];
const op = {
id: this.id,
type: OpType.CreateMap,
parentId,
parentKey,
};
ops.push(op);
for (const [key, value] of this._map) {
ops.push(...value.serialize(this.id, key));
}
return ops;
}
static deserialize([id, item], parentToChildren, doc) {

@@ -416,3 +519,3 @@ if (item.type !== CrdtType.Map) {

const map = new LiveMap();
map.attach(id, doc, item.parentId, item.parentKey);
map.attach(id, doc);
const children = parentToChildren.get(id);

@@ -428,2 +531,3 @@ if (children == null) {

const child = deserialize(entry, parentToChildren, doc);
child.setParent(map);
map._map.set(crdt.parentKey, child);

@@ -433,53 +537,21 @@ }

}
get [INTERNAL]() {
return {
ctx: this._ctx,
apply: this.apply.bind(this),
attachChild: this.attachChild.bind(this),
attach: this.attach.bind(this),
detach: this.detach.bind(this),
detachChild: this.detachChild.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
}
apply(op) { }
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveMap is already part of the storage");
}
doc.addItem(id, this);
this._ctx = {
id,
doc: doc,
parentId,
};
const ops = [];
const createOp = {
id: this._ctx.id,
type: OpType.CreateMap,
parentId,
parentKey,
};
ops.push(createOp);
attach(id, doc) {
super.attach(id, doc);
for (const [key, value] of this._map) {
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
value.attach(doc.generateId(), doc);
}
}
return ops;
}
attachChild(key, child) {
attachChild(id, key, child) {
if (this.doc == null) {
throw new Error("Can't attach child if doc is not present");
}
const previousValue = this._map.get(key);
if (previousValue) {
previousValue[INTERNAL].detach();
previousValue.detach();
}
child.setParent(this);
child.attach(id, this.doc);
this._map.set(key, child);

@@ -489,9 +561,6 @@ this.notify();

detach() {
if (this._ctx == null) {
return;
}
super.detach();
for (const item of this._map.values()) {
item[INTERNAL].detach();
item.detach();
}
this._ctx.doc.deleteItem(this._ctx.id);
}

@@ -504,3 +573,3 @@ detachChild(child) {

}
child[INTERNAL].detach();
child.detach();
this.notify();

@@ -516,19 +585,15 @@ }

set(key, value) {
if (this._ctx) {
const ops = [];
const oldValue = this._map.get(key);
if (oldValue) {
oldValue[INTERNAL].detach();
}
const item = selfOrRegister(value);
ops.push(...item[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
this._map.set(key, item);
this._ctx.doc.dispatch(ops);
this.notify();
const oldValue = this._map.get(key);
if (oldValue) {
oldValue.detach();
}
else {
const item = selfOrRegister(value);
this._map.set(key, item);
this.notify();
const item = selfOrRegister(value);
item.setParent(this);
this._map.set(key, item);
if (this.doc && this.id) {
item.attach(this.doc.generateId(), this.doc);
const ops = item.serialize(this.id, key);
this.doc.dispatch(ops);
}
this.notify();
}

@@ -542,17 +607,13 @@ get size() {

delete(key) {
if (this._ctx) {
const item = this._map.get(key);
if (item) {
const itemId = item[INTERNAL].getId();
if (itemId != null) {
item[INTERNAL].detach();
this._ctx.doc.dispatch([{ type: OpType.DeleteCrdt, id: itemId }]);
}
}
const item = this._map.get(key);
if (item == null) {
return false;
}
const isDeleted = this._map.delete(key);
if (isDeleted) {
this.notify();
item.detach();
if (this.doc && item.id) {
this.doc.dispatch([{ type: OpType.DeleteCrdt, id: item.id }]);
}
return isDeleted;
this._map.delete(key);
this.notify();
return true;
}

@@ -611,35 +672,6 @@ entries() {

}
subscribe(listener) {
this._listeners.push(listener);
}
unsubscribe(listener) {
remove(this._listeners, listener);
}
notify() {
for (const listener of this._listeners) {
listener();
}
}
}
function selfOrRegisterValue(obj) {
if (obj instanceof LiveRegister) {
return obj.data;
}
return obj;
}
function selfOrRegister(obj) {
if (obj instanceof LiveObject ||
obj instanceof LiveMap ||
obj instanceof LiveList) {
return obj;
}
else if (obj instanceof LiveRegister) {
throw new Error("Internal error. LiveRegister should not be created from LiveRegister");
}
else {
return new LiveRegister(obj);
}
}
class LiveRegister {
class LiveRegister extends AbstractCrdt {
constructor(data) {
super();
this._data = data;

@@ -655,60 +687,21 @@ }

const register = new LiveRegister(item.data);
register.attach(id, doc, item.parentId, item.parentKey);
register.attach(id, doc);
return register;
}
get [INTERNAL]() {
return {
ctx: this._ctx,
attach: this.attach.bind(this),
detach: this.detach.bind(this),
attachChild: this.attachChild.bind(this),
detachChild: this.detachChild.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
}
detachChild(crdt) {
throw new Error("Internal error: cannot detach CRDT on register");
}
detach() {
if (this._ctx) {
this._ctx.doc.deleteItem(this._ctx.id);
serialize(parentId, parentKey) {
if (this.id == null || parentId == null || parentKey == null) {
throw new Error("Cannot serialize register if parentId or parentKey is undefined");
}
return [{
type: OpType.CreateRegister,
id: this.id,
parentId,
parentKey,
data: this.data
}];
}
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveRegister is already part of the storage");
}
doc.addItem(id, this);
this._ctx = {
id,
doc: doc,
parentId,
};
const ops = [];
const createOp = {
id,
type: OpType.CreateRegister,
parentId,
parentKey,
data: this._data,
};
ops.push(createOp);
return ops;
}
attachChild(key, child) {
throw new Error("Cannot attach child to register");
}
}
export class LiveList {
export class LiveList extends AbstractCrdt {
constructor(items = []) {
this._listeners = [];
super();
// TODO: Naive array at first, find a better data structure

@@ -726,3 +719,3 @@ this._items = [];

const list = new LiveList([]);
list.attach(id, doc, item.parentId, item.parentKey);
list.attach(id, doc);
const children = parentToChildren.get(id);

@@ -734,40 +727,18 @@ if (children == null) {

const child = deserialize(entry, parentToChildren, doc);
list.attachChild(entry[1].parentKey, child);
child.setParent(list);
list._items.push([child, entry[1].parentKey]);
list._items.sort((itemA, itemB) => compare({ position: itemA[1] }, { position: itemB[1] }));
}
return list;
}
get [INTERNAL]() {
return {
ctx: this._ctx,
attachChild: this.attachChild.bind(this),
detachChild: this.detachChild.bind(this),
attach: this.attach.bind(this),
detach: this.detach.bind(this),
apply: this.apply.bind(this),
setChildKey: this.setChildKey.bind(this),
getParentId: this._getParentId.bind(this),
getId: this._getId.bind(this),
};
}
_getParentId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.parentId;
}
_getId() {
var _a;
return (_a = this._ctx) === null || _a === void 0 ? void 0 : _a.id;
}
attach(id, doc, parentId, parentKey) {
if (this._ctx) {
throw new Error("LiveList is already part of the storage");
serialize(parentId, parentKey) {
if (this.id == null) {
throw new Error("Cannot serialize item is not attached");
}
doc.addItem(id, this);
this._ctx = {
doc: doc,
id: id,
parentId: parentId,
};
if (parentId == null || parentKey == null) {
throw new Error("Cannot serialize list if parentId or parentKey is undefined");
}
const ops = [];
const createOp = {
id: this._ctx.id,
const op = {
id: this.id,
type: OpType.CreateList,

@@ -777,18 +748,26 @@ parentId,

};
ops.push(createOp);
for (const [item, position] of this._items) {
ops.push(...item[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, position));
ops.push(op);
for (const [value, key] of this._items) {
ops.push(...value.serialize(this.id, key));
}
return ops;
}
attach(id, doc) {
super.attach(id, doc);
for (const [item, position] of this._items) {
item.attach(doc.generateId(), doc);
}
}
detach() {
if (this._ctx == null) {
return;
}
super.detach();
for (const [value] of this._items) {
value[INTERNAL].detach();
value.detach();
}
this._ctx.doc.deleteItem(this._ctx.id);
}
attachChild(key, child) {
attachChild(id, key, child) {
if (this.doc == null) {
throw new Error("Can't attach child if doc is not present");
}
child.attach(id, this.doc);
child.setParent(this);
// TODO: Handle list conflict

@@ -803,3 +782,3 @@ this._items.push([child, key]);

if (child) {
child[INTERNAL].detach();
child.detach();
}

@@ -817,7 +796,2 @@ this.notify();

apply(op) { }
notify() {
for (const listener of this._listeners) {
listener();
}
}
push(item) {

@@ -828,7 +802,8 @@ const position = this._items.length === 0

const value = selfOrRegister(item);
value.setParent(this);
this._items.push([value, position]);
this.notify();
if (this._ctx) {
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);
if (this.doc && this.id) {
value.attach(this.doc.generateId(), this.doc);
this.doc.dispatch(value.serialize(this.id, position));
}

@@ -844,8 +819,9 @@ }

const value = selfOrRegister(item);
value.setParent(this);
this._items.push([value, position]);
this._items.sort((itemA, itemB) => compare({ position: itemA[1] }, { position: itemB[1] }));
this.notify();
if (this._ctx) {
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);
if (this.doc && this.id) {
value.attach(this.doc.generateId(), this.doc);
this.doc.dispatch(value.serialize(this.id, position));
}

@@ -885,14 +861,8 @@ }

this.notify();
if (this._ctx) {
const id = item[0][INTERNAL].getId();
if (id == null) {
throw new Error("Internal error. Cannot set parent key from ");
}
this._ctx.doc.dispatch([
{
if (this.doc && this.id) {
this.doc.dispatch([{
type: OpType.SetParentKey,
id: id,
id: item[0].id,
parentKey: position,
},
]);
},]);
}

@@ -905,12 +875,14 @@ }

const item = this._items[index];
item[0].detach();
this._items.splice(index, 1);
if (this._ctx) {
const childRecord = item[0];
this._ctx.doc.dispatch([
{
id: childRecord[INTERNAL].ctx.id,
type: OpType.DeleteCrdt,
},
]);
childRecord[INTERNAL].detach();
if (this.doc) {
const childRecordId = item[0].id;
if (childRecordId) {
this.doc.dispatch([
{
id: childRecordId,
type: OpType.DeleteCrdt,
},
]);
}
}

@@ -925,8 +897,2 @@ this.notify();

}
subscribe(listener) {
this._listeners.push(listener);
}
unsubscribe(listener) {
remove(this._listeners, listener);
}
}

@@ -958,1 +924,20 @@ function deserialize(entry, parentToChildren, doc) {

}
function selfOrRegisterValue(obj) {
if (obj instanceof LiveRegister) {
return obj.data;
}
return obj;
}
function selfOrRegister(obj) {
if (obj instanceof LiveObject ||
obj instanceof LiveMap ||
obj instanceof LiveList) {
return obj;
}
else if (obj instanceof LiveRegister) {
throw new Error("Internal error. LiveRegister should not be created from selfOrRegister");
}
else {
return new LiveRegister(obj);
}
}
{
"name": "@liveblocks/client",
"version": "0.12.0-beta.4",
"version": "0.12.0-beta.6",
"description": "",

@@ -5,0 +5,0 @@ "main": "./lib/cjs/index.js",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc