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.1 to 0.12.0-beta.2

84

lib/cjs/doc.d.ts
import { Op, SerializedCrdtWithId, SerializedList } from "./live";
declare const INTERNAL: unique symbol;
declare type Dispatch = (ops: Op[]) => void;
declare type Crdt = LiveRecord | LiveList;
export declare type RecordData = Record<string, any>;
export declare class Doc<T extends RecordData = RecordData> {
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;
detachChild(child: ICrdt): void;
};
}
export declare class Doc<T extends Record<string, any> = Record<string, any>> {
private _root;

@@ -16,15 +23,17 @@ private actor;

dispatch(ops: Op[]): void;
addItem(id: string, item: Crdt): void;
addItem(id: string, item: ICrdt): void;
deleteItem(id: string): void;
apply(op: Op): void;
private applyCreateRegister;
private applyDeleteRecordKey;
private applyUpdateRecord;
private applyCreateRecord;
private applyCreateMap;
private applyCreateObject;
private applyDeleteRecord;
private applySetParentKey;
get root(): LiveRecord<T>;
get root(): LiveObject<T>;
count(): number;
generateId(): string;
}
export declare class LiveRecord<T extends RecordData = RecordData> {
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> {
private _map;

@@ -34,3 +43,3 @@ private _listeners;

constructor(object?: T);
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveRecord<{
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<{
[key: string]: any;

@@ -44,8 +53,12 @@ }>;

} | undefined;
attachChild: (key: keyof T, child: Crdt) => void;
detachChild: (child: Crdt) => void;
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;

@@ -65,5 +78,44 @@ private attachChild;

}
export declare class LiveList<T extends LiveRecord = LiveRecord> {
export declare class LiveMap<TKey extends string = string, TValue = any> implements ICrdt {
private _listeners;
private _map;
private _ctx?;
constructor(entries?: readonly (readonly [TKey, TValue])[] | null | undefined);
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveMap<string, any>;
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[];
detachChild: (child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private apply;
private attach;
private attachChild;
private detachChild;
get(key: TKey): TValue | undefined;
set(key: TKey, value: TValue): void;
get size(): number;
has(key: TKey): boolean;
delete(key: TKey): boolean;
entries(): IterableIterator<[string, TValue]>;
[Symbol.iterator](): IterableIterator<[string, TValue]>;
keys(): IterableIterator<TKey>;
values(): IterableIterator<TValue>;
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?;
private _items;

@@ -78,9 +130,13 @@ constructor(items?: T[]);

} | undefined;
attachChild: (key: string, child: LiveRecord<Record<string, any>>) => void;
detachChild: (child: Crdt) => void;
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: Crdt) => void;
setChildKey: (key: string, child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private attach;

@@ -87,0 +143,0 @@ private detach;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LiveList = exports.LiveRecord = exports.Doc = void 0;
exports.LiveList = exports.LiveMap = exports.LiveObject = exports.Doc = void 0;
const utils_1 = require("./utils");

@@ -18,3 +18,3 @@ const live_1 = require("./live");

static from(root, actor = 0, dispatch = noOp) {
const rootRecord = new LiveRecord(root);
const rootRecord = new LiveObject(root);
const storage = new Doc(rootRecord, actor, dispatch);

@@ -50,3 +50,3 @@ const ops = rootRecord[INTERNAL].attach(storage.generateId(), storage);

const doc = new Doc(null, actor, dispatch);
doc._root = LiveRecord.deserialize(root, parentToChildren, doc);
doc._root = LiveObject.deserialize(root, parentToChildren, doc);
return doc;

@@ -65,11 +65,15 @@ }

switch (op.type) {
case live_1.OpType.UpdateRecord: {
case live_1.OpType.UpdateObject: {
this.applyUpdateRecord(op);
break;
}
case live_1.OpType.CreateRecord: {
this.applyCreateRecord(op);
case live_1.OpType.CreateObject: {
this.applyCreateObject(op);
break;
}
case live_1.OpType.DeleteRecord: {
case live_1.OpType.CreateMap: {
this.applyCreateMap(op);
break;
}
case live_1.OpType.DeleteObject: {
this.applyDeleteRecord(op);

@@ -82,11 +86,27 @@ break;

}
case live_1.OpType.DeleteRecordKey: {
case live_1.OpType.DeleteObjectKey: {
this.applyDeleteRecordKey(op);
break;
}
case live_1.OpType.CreateRegister: {
this.applyCreateRegister(op);
break;
}
}
}
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);
if (parent == null) {
return;
}
if (!(parent instanceof LiveMap) && !(parent instanceof LiveList)) {
throw new Error("LiveRegister can only be attached to a LiveMap or LiveList");
}
parent[INTERNAL].attachChild(op.parentKey, newRegister);
}
applyDeleteRecordKey(op) {
const item = this._items.get(op.id);
if (item) {
if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);

@@ -97,9 +117,9 @@ }

const item = this._items.get(op.id);
if (item) {
if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);
}
}
applyCreateRecord(op) {
const newRecord = new LiveRecord(op.data);
newRecord[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
applyCreateMap(op) {
const newMap = new LiveMap();
newMap[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
if (op.parentId && op.parentKey) {

@@ -110,5 +130,16 @@ const parent = this._items.get(op.parentId);

}
parent[INTERNAL].attachChild(op.parentKey, newRecord);
parent[INTERNAL].attachChild(op.parentKey, newMap);
}
}
applyCreateObject(op) {
const newObj = new LiveObject(op.data);
newObj[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
if (op.parentId && op.parentKey) {
const parent = this._items.get(op.parentId);
if (parent == null) {
throw new Error("Parent is missing");
}
parent[INTERNAL].attachChild(op.parentKey, newObj);
}
}
applyDeleteRecord(op) {

@@ -119,3 +150,3 @@ const item = this._items.get(op.id);

}
const parentId = item[INTERNAL].ctx.parentId;
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {

@@ -134,3 +165,3 @@ return;

}
const parentId = item[INTERNAL].ctx.parentId;
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {

@@ -155,3 +186,3 @@ return;

exports.Doc = Doc;
class LiveRecord {
class LiveObject {
constructor(object = {}) {

@@ -162,6 +193,6 @@ this._listeners = [];

static deserialize([id, item], parentToChildren, doc) {
if (item.type !== live_1.CrdtType.Record) {
if (item.type !== live_1.CrdtType.Object) {
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
}
const record = new LiveRecord(item.data);
const record = new LiveObject(item.data);
record.attach(id, doc, item.parentId, item.parentKey);

@@ -190,7 +221,17 @@ const children = parentToChildren.get(id);

apply: this.apply.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("LiveRecord is already part of the storage!");
throw new Error("LiveObject is already part of the storage");
}

@@ -206,3 +247,3 @@ doc.addItem(id, this);

id: this._ctx.id,
type: live_1.OpType.CreateRecord,
type: live_1.OpType.CreateObject,
parentId,

@@ -214,5 +255,8 @@ parentKey,

for (const [key, value] of this._map) {
if (value instanceof LiveRecord) {
if (value instanceof LiveObject) {
ops.push(...value.attach(doc.generateId(), doc, this._ctx.id, key));
}
else if (value instanceof LiveMap) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
}
else if (value instanceof LiveList) {

@@ -228,2 +272,6 @@ ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));

attachChild(key, child) {
const previousValue = this._map.get(key);
if (previousValue instanceof LiveObject) {
previousValue.detach();
}
this._map.set(key, child);

@@ -238,3 +286,3 @@ this.notify();

}
if (child instanceof LiveRecord) {
if (child instanceof LiveObject) {
child.detach();

@@ -250,3 +298,3 @@ }

for (const [, value] of this._map) {
if (value instanceof LiveRecord) {
if (value instanceof LiveObject) {
value.detach();

@@ -257,6 +305,6 @@ }

apply(op) {
if (op.type === live_1.OpType.UpdateRecord) {
if (op.type === live_1.OpType.UpdateObject) {
for (const key in op.data) {
const oldValue = this._map.get(key);
if (oldValue instanceof LiveRecord) {
if (oldValue instanceof LiveObject) {
oldValue.detach();

@@ -269,6 +317,6 @@ }

}
else if (op.type === live_1.OpType.DeleteRecordKey) {
else if (op.type === live_1.OpType.DeleteObjectKey) {
const key = op.key;
const oldValue = this._map.get(key);
if (oldValue instanceof LiveRecord) {
if (oldValue instanceof LiveObject) {
oldValue.detach();

@@ -299,7 +347,7 @@ }

const item = this._map.get(key);
if (item instanceof LiveRecord) {
if (item instanceof LiveObject) {
item.detach();
}
this._ctx.doc.dispatch([
{ type: live_1.OpType.DeleteRecordKey, id: this._ctx.id, key: key },
{ type: live_1.OpType.DeleteObjectKey, id: this._ctx.id, key: key },
]);

@@ -315,3 +363,3 @@ }

id: this._ctx.id,
type: live_1.OpType.UpdateRecord,
type: live_1.OpType.UpdateObject,
data: {},

@@ -322,8 +370,8 @@ };

const oldValue = this._map.get(key);
if (oldValue instanceof LiveRecord) {
if (oldValue instanceof LiveObject) {
oldValue.detach();
}
const value = overrides[key];
if (value instanceof LiveRecord) {
ops.push(...value.attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
}

@@ -353,3 +401,325 @@ else {

}
exports.LiveRecord = LiveRecord;
exports.LiveObject = LiveObject;
// TODO: Consider removing default parameter
class LiveMap {
constructor(entries) {
this._listeners = [];
if (entries) {
this._map = new Map(entries.map((entry) => [entry[0], selfOrRegister(entry[1])]));
}
else {
this._map = new Map();
}
}
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== live_1.CrdtType.Map) {
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
}
const map = new LiveMap();
map.attach(id, doc, item.parentId, item.parentKey);
const children = parentToChildren.get(id);
if (children == null) {
return map;
}
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);
map._map.set(crdt.parentKey, child);
}
return map;
}
get [INTERNAL]() {
return {
ctx: this._ctx,
apply: this.apply.bind(this),
attachChild: this.attachChild.bind(this),
attach: this.attach.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);
for (const [key, value] of this._map) {
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
}
}
return ops;
}
attachChild(key, child) {
const previousValue = this._map.get(key);
if (previousValue instanceof LiveObject) {
previousValue[INTERNAL].detach();
}
this._map.set(key, child);
this.notify();
}
detachChild(child) {
for (const [key, value] of this._map) {
if (value === child) {
this._map.delete(key);
}
}
if (child instanceof LiveObject) {
child[INTERNAL].detach();
}
else if (child instanceof LiveRegister) {
child[INTERNAL].detach();
}
this.notify();
}
get(key) {
const value = this._map.get(key);
if (value instanceof LiveRegister) {
return value.data;
}
return this._map.get(key);
}
set(key, value) {
if (this._ctx) {
const ops = [];
const oldValue = this._map.get(key);
if (oldValue instanceof LiveObject) {
oldValue[INTERNAL].detach();
}
if (value instanceof LiveObject) {
ops.push(...value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
this._map.set(key, value);
}
else if (value instanceof LiveMap || value instanceof LiveList) {
throw new Error("Adding a map or a list inside map is not yet supported");
}
else {
const register = new LiveRegister(value);
ops.push(...register[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
this._map.set(key, register);
}
this._ctx.doc.dispatch(ops);
this.notify();
}
else {
if (value instanceof LiveObject) {
this._map.set(key, value);
}
else if (value instanceof LiveMap || value instanceof LiveList) {
throw new Error("Adding a map or a list inside map is not yet supported");
}
else {
const register = new LiveRegister(value);
this._map.set(key, register);
}
this.notify();
}
}
get size() {
return this._map.size;
}
has(key) {
return this._map.has(key);
}
delete(key) {
if (this._ctx) {
const item = this._map.get(key);
if (item instanceof LiveObject) {
const itemCtx = item[INTERNAL].ctx;
if (itemCtx == null) {
throw new Error("Tried to detach a CRDT that is not yet attached");
}
item[INTERNAL].detach();
this._ctx.doc.dispatch([{ type: live_1.OpType.DeleteObject, id: itemCtx.id }]);
}
else if (item instanceof LiveRegister) {
const itemCtx = item[INTERNAL].ctx;
if (itemCtx == null) {
throw new Error("Tried to detach a CRDT that is not yet attached");
}
item[INTERNAL].detach();
this._ctx.doc.dispatch([{ type: live_1.OpType.DeleteObject, id: itemCtx.id }]);
}
}
const isDeleted = this._map.delete(key);
if (isDeleted) {
this.notify();
}
return isDeleted;
}
entries() {
const innerIterator = this._map.entries();
return {
[Symbol.iterator]: function () {
return this;
},
next() {
const iteratorValue = innerIterator.next();
if (iteratorValue.done) {
return {
done: true,
value: undefined,
};
}
const entry = iteratorValue.value;
return {
value: [entry[0], selfOrRegisterValue(iteratorValue.value[1])],
};
},
};
}
[Symbol.iterator]() {
return this.entries();
}
keys() {
return this._map.keys();
}
values() {
const innerIterator = this._map.values();
return {
[Symbol.iterator]: function () {
return this;
},
next() {
const iteratorValue = innerIterator.next();
if (iteratorValue.done) {
return {
done: true,
value: undefined,
};
}
return {
value: selfOrRegisterValue(iteratorValue.value),
};
},
};
}
forEach(callback) {
for (const entry of this) {
callback(entry[1], entry[0], this);
}
}
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) {
return obj;
}
else if (obj instanceof LiveMap || obj instanceof LiveList) {
throw new Error("Nested map and list are not yet supported inside a map");
}
else {
return new LiveRegister(obj);
}
}
class LiveRegister {
constructor(data) {
this._data = data;
}
get data() {
return this._data;
}
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== live_1.CrdtType.Register) {
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
}
const register = new LiveRegister(item.data);
register.attach(id, doc, item.parentId, item.parentKey);
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("Cannot detach CRDT on register");
}
detach() {
if (this._ctx) {
this._ctx.doc.deleteItem(this._ctx.id);
}
}
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 {

@@ -363,3 +733,4 @@ constructor(items = []) {

const newPosition = position_1.makePosition(position);
this._items.push([items[i], newPosition]);
const item = selfOrRegister(items[i]);
this._items.push([item, newPosition]);
position = newPosition;

@@ -376,3 +747,3 @@ }

for (const entry of children) {
const child = LiveRecord.deserialize(entry, parentToChildren, doc);
const child = LiveObject.deserialize(entry, parentToChildren, doc);
list.attachChild(entry[1].parentKey, child);

@@ -391,7 +762,17 @@ }

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!");
throw new Error("LiveList is already part of the storage");
}

@@ -431,3 +812,3 @@ doc.addItem(id, this);

this._items.splice(indexToDelete);
if (child instanceof LiveRecord) {
if (child instanceof LiveObject) {
child[INTERNAL].detach();

@@ -455,6 +836,7 @@ }

: position_1.makePosition(this._items[this._items.length - 1][1]);
this._items.push([item, position]);
const value = selfOrRegister(item);
this._items.push([value, position]);
this.notify();
if (this._ctx) {
const ops = item[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);

@@ -470,7 +852,8 @@ }

const position = position_1.makePosition(before, after);
this._items.push([item, position]);
const value = selfOrRegister(item);
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 = item[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);

@@ -512,6 +895,10 @@ }

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([
{
type: live_1.OpType.SetParentKey,
id: item[0][INTERNAL].ctx.id,
id: id,
parentKey: position,

@@ -533,3 +920,3 @@ },

id: childRecord[INTERNAL].ctx.id,
type: live_1.OpType.DeleteRecord,
type: live_1.OpType.DeleteObject,
},

@@ -542,6 +929,7 @@ ]);

toArray() {
return this._items.map((entry) => entry[0]);
// TODO: typing
return this._items.map((entry) => selfOrRegisterValue(entry[0]));
}
get(index) {
return this._items[index][0];
return selfOrRegisterValue(this._items[index][0]);
}

@@ -558,4 +946,4 @@ subscribe(listener) {

switch (entry[1].type) {
case live_1.CrdtType.Record: {
return LiveRecord.deserialize(entry, parentToChildren, doc);
case live_1.CrdtType.Object: {
return LiveObject.deserialize(entry, parentToChildren, doc);
}

@@ -565,2 +953,8 @@ case live_1.CrdtType.List: {

}
case live_1.CrdtType.Map: {
return LiveMap.deserialize(entry, parentToChildren, doc);
}
case live_1.CrdtType.Register: {
return LiveRegister.deserialize(entry, parentToChildren, doc);
}
default: {

@@ -571,1 +965,7 @@ throw new Error("Unexpected CRDT type");

}
function isCrdt(obj) {
return (obj instanceof LiveObject ||
obj instanceof LiveMap ||
obj instanceof LiveList ||
obj instanceof LiveRegister);
}

2

lib/cjs/index.d.ts

@@ -1,3 +0,3 @@

export { LiveRecord, LiveList, RecordData } from "./doc";
export { LiveObject, LiveList, LiveMap } from "./doc";
export type { Others, Presence, Room, Client, User } from "./types";
export { createClient } from "./client";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createClient = exports.LiveList = exports.LiveRecord = void 0;
exports.createClient = exports.LiveMap = exports.LiveList = exports.LiveObject = void 0;
var doc_1 = require("./doc");
Object.defineProperty(exports, "LiveRecord", { enumerable: true, get: function () { return doc_1.LiveRecord; } });
Object.defineProperty(exports, "LiveObject", { enumerable: true, get: function () { return doc_1.LiveObject; } });
Object.defineProperty(exports, "LiveList", { enumerable: true, get: function () { return doc_1.LiveList; } });
Object.defineProperty(exports, "LiveMap", { enumerable: true, get: function () { return doc_1.LiveMap; } });
var client_1 = require("./client");
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });

@@ -74,7 +74,9 @@ import { Presence } from "./types";

export declare enum CrdtType {
Record = 0,
List = 1
Object = 0,
List = 1,
Map = 2,
Register = 3
}
export declare type SerializedRecord = {
type: CrdtType.Record;
export declare type SerializedObject = {
type: CrdtType.Object;
parentId?: string;

@@ -91,3 +93,14 @@ parentKey?: string;

};
export declare type SerializedCrdt = SerializedRecord | SerializedList;
export declare type SerializedMap = {
type: CrdtType.Map;
parentId: string;
parentKey: string;
};
export declare type SerializedRegister = {
type: CrdtType.Register;
parentId: string;
parentKey: string;
data: any;
};
export declare type SerializedCrdt = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
export declare enum OpType {

@@ -97,11 +110,13 @@ Init = 0,

CreateList = 2,
UpdateRecord = 3,
CreateRecord = 4,
DeleteRecord = 5,
DeleteRecordKey = 6
UpdateObject = 3,
CreateObject = 4,
DeleteObject = 5,
DeleteObjectKey = 6,
CreateMap = 7,
CreateRegister = 8
}
export declare type Op = CreateRecordOp | RecordUpdateOp | DeleteRecordOp | CreateListOp | SetParentKeyOp | DeleteRecordKeyOp;
export declare type RecordUpdateOp = {
export declare type Op = CreateObjectOp | UpdateObjectOp | DeleteObjectOp | CreateListOp | SetParentKeyOp | DeleteObjectKeyOp | CreateMapOp | CreateRegisterOp;
export declare type UpdateObjectOp = {
id: string;
type: OpType.UpdateRecord;
type: OpType.UpdateObject;
data: {

@@ -111,5 +126,5 @@ [key: string]: any;

};
export declare type CreateRecordOp = {
export declare type CreateObjectOp = {
id: string;
type: OpType.CreateRecord;
type: OpType.CreateObject;
parentId?: string;

@@ -127,6 +142,19 @@ parentKey?: string;

};
export declare type DeleteRecordOp = {
export declare type CreateMapOp = {
id: string;
type: OpType.DeleteRecord;
type: OpType.CreateMap;
parentId: string;
parentKey: string;
};
export declare type CreateRegisterOp = {
id: string;
type: OpType.CreateRegister;
parentId: string;
parentKey: string;
data: any;
};
export declare type DeleteObjectOp = {
id: string;
type: OpType.DeleteObject;
};
export declare type SetParentKeyOp = {

@@ -137,5 +165,5 @@ id: string;

};
export declare type DeleteRecordKeyOp = {
export declare type DeleteObjectKeyOp = {
id: string;
type: OpType.DeleteRecordKey;
type: OpType.DeleteObjectKey;
key: string;

@@ -142,0 +170,0 @@ };

@@ -23,4 +23,6 @@ "use strict";

(function (CrdtType) {
CrdtType[CrdtType["Record"] = 0] = "Record";
CrdtType[CrdtType["Object"] = 0] = "Object";
CrdtType[CrdtType["List"] = 1] = "List";
CrdtType[CrdtType["Map"] = 2] = "Map";
CrdtType[CrdtType["Register"] = 3] = "Register";
})(CrdtType = exports.CrdtType || (exports.CrdtType = {}));

@@ -32,6 +34,8 @@ var OpType;

OpType[OpType["CreateList"] = 2] = "CreateList";
OpType[OpType["UpdateRecord"] = 3] = "UpdateRecord";
OpType[OpType["CreateRecord"] = 4] = "CreateRecord";
OpType[OpType["DeleteRecord"] = 5] = "DeleteRecord";
OpType[OpType["DeleteRecordKey"] = 6] = "DeleteRecordKey";
OpType[OpType["UpdateObject"] = 3] = "UpdateObject";
OpType[OpType["CreateObject"] = 4] = "CreateObject";
OpType[OpType["DeleteObject"] = 5] = "DeleteObject";
OpType[OpType["DeleteObjectKey"] = 6] = "DeleteObjectKey";
OpType[OpType["CreateMap"] = 7] = "CreateMap";
OpType[OpType["CreateRegister"] = 8] = "CreateRegister";
})(OpType = exports.OpType || (exports.OpType = {}));

@@ -38,0 +42,0 @@ var WebsocketCloseCodes;

@@ -1,2 +0,1 @@

import { RecordData } from "./doc";
import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback } from "./types";

@@ -85,3 +84,3 @@ import { ClientMessage, Op } from "./live";

getStorage: <TRoot>() => Promise<{
root: import("./doc").LiveRecord<TRoot>;
root: import("./doc").LiveObject<TRoot>;
}>;

@@ -107,4 +106,4 @@ selectors: {

defaultPresence?: Presence;
defaultStorageRoot?: RecordData;
defaultStorageRoot?: Record<string, any>;
}): InternalRoom;
export {};

@@ -1,2 +0,2 @@

import { LiveRecord, RecordData } from "./doc";
import { LiveObject } from "./doc";
export declare type MyPresenceCallback<T extends Presence = Presence> = (me: T) => void;

@@ -29,3 +29,3 @@ export declare type OthersEventCallback<T extends Presence = Presence> = (others: Others<T>, event: OthersEvent<T>) => void;

*/
enter<TStorageRoot = RecordData>(roomId: string, options?: {
enter<TStorageRoot extends Record<string, any> = Record<string, any>>(roomId: string, options?: {
defaultPresence?: Presence;

@@ -263,5 +263,5 @@ defaultStorageRoot?: TStorageRoot;

getStorage: <TRoot>() => Promise<{
root: LiveRecord<TRoot>;
root: LiveObject<TRoot>;
}>;
};
export {};
import { Op, SerializedCrdtWithId, SerializedList } from "./live";
declare const INTERNAL: unique symbol;
declare type Dispatch = (ops: Op[]) => void;
declare type Crdt = LiveRecord | LiveList;
export declare type RecordData = Record<string, any>;
export declare class Doc<T extends RecordData = RecordData> {
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;
detachChild(child: ICrdt): void;
};
}
export declare class Doc<T extends Record<string, any> = Record<string, any>> {
private _root;

@@ -16,15 +23,17 @@ private actor;

dispatch(ops: Op[]): void;
addItem(id: string, item: Crdt): void;
addItem(id: string, item: ICrdt): void;
deleteItem(id: string): void;
apply(op: Op): void;
private applyCreateRegister;
private applyDeleteRecordKey;
private applyUpdateRecord;
private applyCreateRecord;
private applyCreateMap;
private applyCreateObject;
private applyDeleteRecord;
private applySetParentKey;
get root(): LiveRecord<T>;
get root(): LiveObject<T>;
count(): number;
generateId(): string;
}
export declare class LiveRecord<T extends RecordData = RecordData> {
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> {
private _map;

@@ -34,3 +43,3 @@ private _listeners;

constructor(object?: T);
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveRecord<{
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<{
[key: string]: any;

@@ -44,8 +53,12 @@ }>;

} | undefined;
attachChild: (key: keyof T, child: Crdt) => void;
detachChild: (child: Crdt) => void;
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;

@@ -65,5 +78,44 @@ private attachChild;

}
export declare class LiveList<T extends LiveRecord = LiveRecord> {
export declare class LiveMap<TKey extends string = string, TValue = any> implements ICrdt {
private _listeners;
private _map;
private _ctx?;
constructor(entries?: readonly (readonly [TKey, TValue])[] | null | undefined);
static deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveMap<string, any>;
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[];
detachChild: (child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private apply;
private attach;
private attachChild;
private detachChild;
get(key: TKey): TValue | undefined;
set(key: TKey, value: TValue): void;
get size(): number;
has(key: TKey): boolean;
delete(key: TKey): boolean;
entries(): IterableIterator<[string, TValue]>;
[Symbol.iterator](): IterableIterator<[string, TValue]>;
keys(): IterableIterator<TKey>;
values(): IterableIterator<TValue>;
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?;
private _items;

@@ -78,9 +130,13 @@ constructor(items?: T[]);

} | undefined;
attachChild: (key: string, child: LiveRecord<Record<string, any>>) => void;
detachChild: (child: Crdt) => void;
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: Crdt) => void;
setChildKey: (key: string, child: ICrdt) => void;
getParentId: () => string | undefined;
getId: () => string | undefined;
};
private _getParentId;
private _getId;
private attach;

@@ -87,0 +143,0 @@ private detach;

@@ -15,3 +15,3 @@ import { remove } from "./utils";

static from(root, actor = 0, dispatch = noOp) {
const rootRecord = new LiveRecord(root);
const rootRecord = new LiveObject(root);
const storage = new Doc(rootRecord, actor, dispatch);

@@ -47,3 +47,3 @@ const ops = rootRecord[INTERNAL].attach(storage.generateId(), storage);

const doc = new Doc(null, actor, dispatch);
doc._root = LiveRecord.deserialize(root, parentToChildren, doc);
doc._root = LiveObject.deserialize(root, parentToChildren, doc);
return doc;

@@ -62,11 +62,15 @@ }

switch (op.type) {
case OpType.UpdateRecord: {
case OpType.UpdateObject: {
this.applyUpdateRecord(op);
break;
}
case OpType.CreateRecord: {
this.applyCreateRecord(op);
case OpType.CreateObject: {
this.applyCreateObject(op);
break;
}
case OpType.DeleteRecord: {
case OpType.CreateMap: {
this.applyCreateMap(op);
break;
}
case OpType.DeleteObject: {
this.applyDeleteRecord(op);

@@ -79,11 +83,27 @@ break;

}
case OpType.DeleteRecordKey: {
case OpType.DeleteObjectKey: {
this.applyDeleteRecordKey(op);
break;
}
case OpType.CreateRegister: {
this.applyCreateRegister(op);
break;
}
}
}
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);
if (parent == null) {
return;
}
if (!(parent instanceof LiveMap) && !(parent instanceof LiveList)) {
throw new Error("LiveRegister can only be attached to a LiveMap or LiveList");
}
parent[INTERNAL].attachChild(op.parentKey, newRegister);
}
applyDeleteRecordKey(op) {
const item = this._items.get(op.id);
if (item) {
if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);

@@ -94,9 +114,9 @@ }

const item = this._items.get(op.id);
if (item) {
if (item && item instanceof LiveObject) {
item[INTERNAL].apply(op);
}
}
applyCreateRecord(op) {
const newRecord = new LiveRecord(op.data);
newRecord[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
applyCreateMap(op) {
const newMap = new LiveMap();
newMap[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
if (op.parentId && op.parentKey) {

@@ -107,5 +127,16 @@ const parent = this._items.get(op.parentId);

}
parent[INTERNAL].attachChild(op.parentKey, newRecord);
parent[INTERNAL].attachChild(op.parentKey, newMap);
}
}
applyCreateObject(op) {
const newObj = new LiveObject(op.data);
newObj[INTERNAL].attach(op.id, this, op.parentId, op.parentKey);
if (op.parentId && op.parentKey) {
const parent = this._items.get(op.parentId);
if (parent == null) {
throw new Error("Parent is missing");
}
parent[INTERNAL].attachChild(op.parentKey, newObj);
}
}
applyDeleteRecord(op) {

@@ -116,3 +147,3 @@ const item = this._items.get(op.id);

}
const parentId = item[INTERNAL].ctx.parentId;
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {

@@ -131,3 +162,3 @@ return;

}
const parentId = item[INTERNAL].ctx.parentId;
const parentId = item[INTERNAL].getParentId();
if (parentId == null) {

@@ -151,3 +182,3 @@ return;

}
export class LiveRecord {
export class LiveObject {
constructor(object = {}) {

@@ -158,6 +189,6 @@ this._listeners = [];

static deserialize([id, item], parentToChildren, doc) {
if (item.type !== CrdtType.Record) {
if (item.type !== CrdtType.Object) {
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
}
const record = new LiveRecord(item.data);
const record = new LiveObject(item.data);
record.attach(id, doc, item.parentId, item.parentKey);

@@ -186,7 +217,17 @@ const children = parentToChildren.get(id);

apply: this.apply.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("LiveRecord is already part of the storage!");
throw new Error("LiveObject is already part of the storage");
}

@@ -202,3 +243,3 @@ doc.addItem(id, this);

id: this._ctx.id,
type: OpType.CreateRecord,
type: OpType.CreateObject,
parentId,

@@ -210,5 +251,8 @@ parentKey,

for (const [key, value] of this._map) {
if (value instanceof LiveRecord) {
if (value instanceof LiveObject) {
ops.push(...value.attach(doc.generateId(), doc, this._ctx.id, key));
}
else if (value instanceof LiveMap) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
}
else if (value instanceof LiveList) {

@@ -224,2 +268,6 @@ ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));

attachChild(key, child) {
const previousValue = this._map.get(key);
if (previousValue instanceof LiveObject) {
previousValue.detach();
}
this._map.set(key, child);

@@ -234,3 +282,3 @@ this.notify();

}
if (child instanceof LiveRecord) {
if (child instanceof LiveObject) {
child.detach();

@@ -246,3 +294,3 @@ }

for (const [, value] of this._map) {
if (value instanceof LiveRecord) {
if (value instanceof LiveObject) {
value.detach();

@@ -253,6 +301,6 @@ }

apply(op) {
if (op.type === OpType.UpdateRecord) {
if (op.type === OpType.UpdateObject) {
for (const key in op.data) {
const oldValue = this._map.get(key);
if (oldValue instanceof LiveRecord) {
if (oldValue instanceof LiveObject) {
oldValue.detach();

@@ -265,6 +313,6 @@ }

}
else if (op.type === OpType.DeleteRecordKey) {
else if (op.type === OpType.DeleteObjectKey) {
const key = op.key;
const oldValue = this._map.get(key);
if (oldValue instanceof LiveRecord) {
if (oldValue instanceof LiveObject) {
oldValue.detach();

@@ -295,7 +343,7 @@ }

const item = this._map.get(key);
if (item instanceof LiveRecord) {
if (item instanceof LiveObject) {
item.detach();
}
this._ctx.doc.dispatch([
{ type: OpType.DeleteRecordKey, id: this._ctx.id, key: key },
{ type: OpType.DeleteObjectKey, id: this._ctx.id, key: key },
]);

@@ -311,3 +359,3 @@ }

id: this._ctx.id,
type: OpType.UpdateRecord,
type: OpType.UpdateObject,
data: {},

@@ -318,8 +366,8 @@ };

const oldValue = this._map.get(key);
if (oldValue instanceof LiveRecord) {
if (oldValue instanceof LiveObject) {
oldValue.detach();
}
const value = overrides[key];
if (value instanceof LiveRecord) {
ops.push(...value.attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
}

@@ -349,2 +397,323 @@ else {

}
// TODO: Consider removing default parameter
export class LiveMap {
constructor(entries) {
this._listeners = [];
if (entries) {
this._map = new Map(entries.map((entry) => [entry[0], selfOrRegister(entry[1])]));
}
else {
this._map = new Map();
}
}
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== CrdtType.Map) {
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
}
const map = new LiveMap();
map.attach(id, doc, item.parentId, item.parentKey);
const children = parentToChildren.get(id);
if (children == null) {
return map;
}
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);
map._map.set(crdt.parentKey, child);
}
return map;
}
get [INTERNAL]() {
return {
ctx: this._ctx,
apply: this.apply.bind(this),
attachChild: this.attachChild.bind(this),
attach: this.attach.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);
for (const [key, value] of this._map) {
if (isCrdt(value)) {
ops.push(...value[INTERNAL].attach(doc.generateId(), doc, this._ctx.id, key));
}
}
return ops;
}
attachChild(key, child) {
const previousValue = this._map.get(key);
if (previousValue instanceof LiveObject) {
previousValue[INTERNAL].detach();
}
this._map.set(key, child);
this.notify();
}
detachChild(child) {
for (const [key, value] of this._map) {
if (value === child) {
this._map.delete(key);
}
}
if (child instanceof LiveObject) {
child[INTERNAL].detach();
}
else if (child instanceof LiveRegister) {
child[INTERNAL].detach();
}
this.notify();
}
get(key) {
const value = this._map.get(key);
if (value instanceof LiveRegister) {
return value.data;
}
return this._map.get(key);
}
set(key, value) {
if (this._ctx) {
const ops = [];
const oldValue = this._map.get(key);
if (oldValue instanceof LiveObject) {
oldValue[INTERNAL].detach();
}
if (value instanceof LiveObject) {
ops.push(...value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
this._map.set(key, value);
}
else if (value instanceof LiveMap || value instanceof LiveList) {
throw new Error("Adding a map or a list inside map is not yet supported");
}
else {
const register = new LiveRegister(value);
ops.push(...register[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, key));
this._map.set(key, register);
}
this._ctx.doc.dispatch(ops);
this.notify();
}
else {
if (value instanceof LiveObject) {
this._map.set(key, value);
}
else if (value instanceof LiveMap || value instanceof LiveList) {
throw new Error("Adding a map or a list inside map is not yet supported");
}
else {
const register = new LiveRegister(value);
this._map.set(key, register);
}
this.notify();
}
}
get size() {
return this._map.size;
}
has(key) {
return this._map.has(key);
}
delete(key) {
if (this._ctx) {
const item = this._map.get(key);
if (item instanceof LiveObject) {
const itemCtx = item[INTERNAL].ctx;
if (itemCtx == null) {
throw new Error("Tried to detach a CRDT that is not yet attached");
}
item[INTERNAL].detach();
this._ctx.doc.dispatch([{ type: OpType.DeleteObject, id: itemCtx.id }]);
}
else if (item instanceof LiveRegister) {
const itemCtx = item[INTERNAL].ctx;
if (itemCtx == null) {
throw new Error("Tried to detach a CRDT that is not yet attached");
}
item[INTERNAL].detach();
this._ctx.doc.dispatch([{ type: OpType.DeleteObject, id: itemCtx.id }]);
}
}
const isDeleted = this._map.delete(key);
if (isDeleted) {
this.notify();
}
return isDeleted;
}
entries() {
const innerIterator = this._map.entries();
return {
[Symbol.iterator]: function () {
return this;
},
next() {
const iteratorValue = innerIterator.next();
if (iteratorValue.done) {
return {
done: true,
value: undefined,
};
}
const entry = iteratorValue.value;
return {
value: [entry[0], selfOrRegisterValue(iteratorValue.value[1])],
};
},
};
}
[Symbol.iterator]() {
return this.entries();
}
keys() {
return this._map.keys();
}
values() {
const innerIterator = this._map.values();
return {
[Symbol.iterator]: function () {
return this;
},
next() {
const iteratorValue = innerIterator.next();
if (iteratorValue.done) {
return {
done: true,
value: undefined,
};
}
return {
value: selfOrRegisterValue(iteratorValue.value),
};
},
};
}
forEach(callback) {
for (const entry of this) {
callback(entry[1], entry[0], this);
}
}
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) {
return obj;
}
else if (obj instanceof LiveMap || obj instanceof LiveList) {
throw new Error("Nested map and list are not yet supported inside a map");
}
else {
return new LiveRegister(obj);
}
}
class LiveRegister {
constructor(data) {
this._data = data;
}
get data() {
return this._data;
}
static deserialize([id, item], parentToChildren, doc) {
if (item.type !== CrdtType.Register) {
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
}
const register = new LiveRegister(item.data);
register.attach(id, doc, item.parentId, item.parentKey);
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("Cannot detach CRDT on register");
}
detach() {
if (this._ctx) {
this._ctx.doc.deleteItem(this._ctx.id);
}
}
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 {

@@ -358,3 +727,4 @@ constructor(items = []) {

const newPosition = makePosition(position);
this._items.push([items[i], newPosition]);
const item = selfOrRegister(items[i]);
this._items.push([item, newPosition]);
position = newPosition;

@@ -371,3 +741,3 @@ }

for (const entry of children) {
const child = LiveRecord.deserialize(entry, parentToChildren, doc);
const child = LiveObject.deserialize(entry, parentToChildren, doc);
list.attachChild(entry[1].parentKey, child);

@@ -386,7 +756,17 @@ }

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!");
throw new Error("LiveList is already part of the storage");
}

@@ -426,3 +806,3 @@ doc.addItem(id, this);

this._items.splice(indexToDelete);
if (child instanceof LiveRecord) {
if (child instanceof LiveObject) {
child[INTERNAL].detach();

@@ -450,6 +830,7 @@ }

: makePosition(this._items[this._items.length - 1][1]);
this._items.push([item, position]);
const value = selfOrRegister(item);
this._items.push([value, position]);
this.notify();
if (this._ctx) {
const ops = item[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
const ops = value[INTERNAL].attach(this._ctx.doc.generateId(), this._ctx.doc, this._ctx.id, position);
this._ctx.doc.dispatch(ops);

@@ -465,7 +846,8 @@ }

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

@@ -507,6 +889,10 @@ }

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([
{
type: OpType.SetParentKey,
id: item[0][INTERNAL].ctx.id,
id: id,
parentKey: position,

@@ -528,3 +914,3 @@ },

id: childRecord[INTERNAL].ctx.id,
type: OpType.DeleteRecord,
type: OpType.DeleteObject,
},

@@ -537,6 +923,7 @@ ]);

toArray() {
return this._items.map((entry) => entry[0]);
// TODO: typing
return this._items.map((entry) => selfOrRegisterValue(entry[0]));
}
get(index) {
return this._items[index][0];
return selfOrRegisterValue(this._items[index][0]);
}

@@ -552,4 +939,4 @@ subscribe(listener) {

switch (entry[1].type) {
case CrdtType.Record: {
return LiveRecord.deserialize(entry, parentToChildren, doc);
case CrdtType.Object: {
return LiveObject.deserialize(entry, parentToChildren, doc);
}

@@ -559,2 +946,8 @@ case CrdtType.List: {

}
case CrdtType.Map: {
return LiveMap.deserialize(entry, parentToChildren, doc);
}
case CrdtType.Register: {
return LiveRegister.deserialize(entry, parentToChildren, doc);
}
default: {

@@ -565,1 +958,7 @@ throw new Error("Unexpected CRDT type");

}
function isCrdt(obj) {
return (obj instanceof LiveObject ||
obj instanceof LiveMap ||
obj instanceof LiveList ||
obj instanceof LiveRegister);
}

@@ -1,3 +0,3 @@

export { LiveRecord, LiveList, RecordData } from "./doc";
export { LiveObject, LiveList, LiveMap } from "./doc";
export type { Others, Presence, Room, Client, User } from "./types";
export { createClient } from "./client";

@@ -1,2 +0,2 @@

export { LiveRecord, LiveList } from "./doc";
export { LiveObject, LiveList, LiveMap } from "./doc";
export { createClient } from "./client";

@@ -74,7 +74,9 @@ import { Presence } from "./types";

export declare enum CrdtType {
Record = 0,
List = 1
Object = 0,
List = 1,
Map = 2,
Register = 3
}
export declare type SerializedRecord = {
type: CrdtType.Record;
export declare type SerializedObject = {
type: CrdtType.Object;
parentId?: string;

@@ -91,3 +93,14 @@ parentKey?: string;

};
export declare type SerializedCrdt = SerializedRecord | SerializedList;
export declare type SerializedMap = {
type: CrdtType.Map;
parentId: string;
parentKey: string;
};
export declare type SerializedRegister = {
type: CrdtType.Register;
parentId: string;
parentKey: string;
data: any;
};
export declare type SerializedCrdt = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
export declare enum OpType {

@@ -97,11 +110,13 @@ Init = 0,

CreateList = 2,
UpdateRecord = 3,
CreateRecord = 4,
DeleteRecord = 5,
DeleteRecordKey = 6
UpdateObject = 3,
CreateObject = 4,
DeleteObject = 5,
DeleteObjectKey = 6,
CreateMap = 7,
CreateRegister = 8
}
export declare type Op = CreateRecordOp | RecordUpdateOp | DeleteRecordOp | CreateListOp | SetParentKeyOp | DeleteRecordKeyOp;
export declare type RecordUpdateOp = {
export declare type Op = CreateObjectOp | UpdateObjectOp | DeleteObjectOp | CreateListOp | SetParentKeyOp | DeleteObjectKeyOp | CreateMapOp | CreateRegisterOp;
export declare type UpdateObjectOp = {
id: string;
type: OpType.UpdateRecord;
type: OpType.UpdateObject;
data: {

@@ -111,5 +126,5 @@ [key: string]: any;

};
export declare type CreateRecordOp = {
export declare type CreateObjectOp = {
id: string;
type: OpType.CreateRecord;
type: OpType.CreateObject;
parentId?: string;

@@ -127,6 +142,19 @@ parentKey?: string;

};
export declare type DeleteRecordOp = {
export declare type CreateMapOp = {
id: string;
type: OpType.DeleteRecord;
type: OpType.CreateMap;
parentId: string;
parentKey: string;
};
export declare type CreateRegisterOp = {
id: string;
type: OpType.CreateRegister;
parentId: string;
parentKey: string;
data: any;
};
export declare type DeleteObjectOp = {
id: string;
type: OpType.DeleteObject;
};
export declare type SetParentKeyOp = {

@@ -137,5 +165,5 @@ id: string;

};
export declare type DeleteRecordKeyOp = {
export declare type DeleteObjectKeyOp = {
id: string;
type: OpType.DeleteRecordKey;
type: OpType.DeleteObjectKey;
key: string;

@@ -142,0 +170,0 @@ };

@@ -20,4 +20,6 @@ export var ServerMessageType;

(function (CrdtType) {
CrdtType[CrdtType["Record"] = 0] = "Record";
CrdtType[CrdtType["Object"] = 0] = "Object";
CrdtType[CrdtType["List"] = 1] = "List";
CrdtType[CrdtType["Map"] = 2] = "Map";
CrdtType[CrdtType["Register"] = 3] = "Register";
})(CrdtType || (CrdtType = {}));

@@ -29,6 +31,8 @@ export var OpType;

OpType[OpType["CreateList"] = 2] = "CreateList";
OpType[OpType["UpdateRecord"] = 3] = "UpdateRecord";
OpType[OpType["CreateRecord"] = 4] = "CreateRecord";
OpType[OpType["DeleteRecord"] = 5] = "DeleteRecord";
OpType[OpType["DeleteRecordKey"] = 6] = "DeleteRecordKey";
OpType[OpType["UpdateObject"] = 3] = "UpdateObject";
OpType[OpType["CreateObject"] = 4] = "CreateObject";
OpType[OpType["DeleteObject"] = 5] = "DeleteObject";
OpType[OpType["DeleteObjectKey"] = 6] = "DeleteObjectKey";
OpType[OpType["CreateMap"] = 7] = "CreateMap";
OpType[OpType["CreateRegister"] = 8] = "CreateRegister";
})(OpType || (OpType = {}));

@@ -35,0 +39,0 @@ export var WebsocketCloseCodes;

@@ -1,2 +0,1 @@

import { RecordData } from "./doc";
import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback } from "./types";

@@ -85,3 +84,3 @@ import { ClientMessage, Op } from "./live";

getStorage: <TRoot>() => Promise<{
root: import("./doc").LiveRecord<TRoot>;
root: import("./doc").LiveObject<TRoot>;
}>;

@@ -107,4 +106,4 @@ selectors: {

defaultPresence?: Presence;
defaultStorageRoot?: RecordData;
defaultStorageRoot?: Record<string, any>;
}): InternalRoom;
export {};

@@ -1,2 +0,2 @@

import { LiveRecord, RecordData } from "./doc";
import { LiveObject } from "./doc";
export declare type MyPresenceCallback<T extends Presence = Presence> = (me: T) => void;

@@ -29,3 +29,3 @@ export declare type OthersEventCallback<T extends Presence = Presence> = (others: Others<T>, event: OthersEvent<T>) => void;

*/
enter<TStorageRoot = RecordData>(roomId: string, options?: {
enter<TStorageRoot extends Record<string, any> = Record<string, any>>(roomId: string, options?: {
defaultPresence?: Presence;

@@ -263,5 +263,5 @@ defaultStorageRoot?: TStorageRoot;

getStorage: <TRoot>() => Promise<{
root: LiveRecord<TRoot>;
root: LiveObject<TRoot>;
}>;
};
export {};
{
"name": "@liveblocks/client",
"version": "0.12.0-beta.1",
"version": "0.12.0-beta.2",
"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