@liveblocks/client
Advanced tools
Comparing version 0.12.0-beta.1 to 0.12.0-beta.2
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); | ||
} |
@@ -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", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
184737
5352