@liveblocks/client 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -6
- package/lib/cjs/AbstractCrdt.d.ts +61 -0
- package/lib/cjs/AbstractCrdt.js +98 -0
- package/lib/cjs/LiveList.d.ts +133 -0
- package/lib/cjs/LiveList.js +374 -0
- package/lib/cjs/LiveMap.d.ts +83 -0
- package/lib/cjs/LiveMap.js +272 -0
- package/lib/cjs/LiveObject.d.ts +61 -0
- package/lib/cjs/LiveObject.js +330 -0
- package/lib/cjs/LiveRegister.d.ts +21 -0
- package/lib/cjs/LiveRegister.js +69 -0
- package/lib/cjs/index.d.ts +3 -1
- package/lib/cjs/index.js +7 -5
- package/lib/cjs/room.d.ts +50 -9
- package/lib/cjs/room.js +476 -85
- package/lib/cjs/types.d.ts +174 -40
- package/lib/cjs/utils.d.ts +7 -0
- package/lib/cjs/utils.js +64 -1
- package/lib/esm/AbstractCrdt.d.ts +61 -0
- package/lib/esm/AbstractCrdt.js +94 -0
- package/lib/esm/LiveList.d.ts +133 -0
- package/lib/esm/LiveList.js +370 -0
- package/lib/esm/LiveMap.d.ts +83 -0
- package/lib/esm/LiveMap.js +268 -0
- package/lib/esm/LiveObject.d.ts +61 -0
- package/lib/esm/LiveObject.js +326 -0
- package/lib/esm/LiveRegister.d.ts +21 -0
- package/lib/esm/LiveRegister.js +65 -0
- package/lib/esm/index.d.ts +3 -1
- package/lib/esm/index.js +3 -1
- package/lib/esm/room.d.ts +50 -9
- package/lib/esm/room.js +478 -84
- package/lib/esm/types.d.ts +174 -40
- package/lib/esm/utils.d.ts +7 -0
- package/lib/esm/utils.js +58 -0
- package/package.json +3 -3
- package/lib/cjs/doc.d.ts +0 -347
- package/lib/cjs/doc.js +0 -1349
- package/lib/cjs/storage.d.ts +0 -21
- package/lib/cjs/storage.js +0 -68
- package/lib/esm/doc.d.ts +0 -347
- package/lib/esm/doc.js +0 -1342
- package/lib/esm/storage.d.ts +0 -21
- package/lib/esm/storage.js +0 -65
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _LiveMap_map;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.LiveMap = void 0;
|
|
16
|
+
const AbstractCrdt_1 = require("./AbstractCrdt");
|
|
17
|
+
const utils_1 = require("./utils");
|
|
18
|
+
const live_1 = require("./live");
|
|
19
|
+
/**
|
|
20
|
+
* The LiveMap class is similar to a JavaScript Map that is synchronized on all clients.
|
|
21
|
+
* Keys should be a string, and values should be serializable to JSON.
|
|
22
|
+
* If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
|
|
23
|
+
*/
|
|
24
|
+
class LiveMap extends AbstractCrdt_1.AbstractCrdt {
|
|
25
|
+
constructor(entries) {
|
|
26
|
+
super();
|
|
27
|
+
_LiveMap_map.set(this, void 0);
|
|
28
|
+
if (entries) {
|
|
29
|
+
const mappedEntries = [];
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const value = (0, utils_1.selfOrRegister)(entry[1]);
|
|
32
|
+
value._setParentLink(this, entry[0]);
|
|
33
|
+
mappedEntries.push([entry[0], value]);
|
|
34
|
+
}
|
|
35
|
+
__classPrivateFieldSet(this, _LiveMap_map, new Map(mappedEntries), "f");
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
__classPrivateFieldSet(this, _LiveMap_map, new Map(), "f");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* INTERNAL
|
|
43
|
+
*/
|
|
44
|
+
_serialize(parentId, parentKey) {
|
|
45
|
+
if (this._id == null) {
|
|
46
|
+
throw new Error("Cannot serialize item is not attached");
|
|
47
|
+
}
|
|
48
|
+
if (parentId == null || parentKey == null) {
|
|
49
|
+
throw new Error("Cannot serialize map if parentId or parentKey is undefined");
|
|
50
|
+
}
|
|
51
|
+
const ops = [];
|
|
52
|
+
const op = {
|
|
53
|
+
id: this._id,
|
|
54
|
+
type: live_1.OpType.CreateMap,
|
|
55
|
+
parentId,
|
|
56
|
+
parentKey,
|
|
57
|
+
};
|
|
58
|
+
ops.push(op);
|
|
59
|
+
for (const [key, value] of __classPrivateFieldGet(this, _LiveMap_map, "f")) {
|
|
60
|
+
ops.push(...value._serialize(this._id, key));
|
|
61
|
+
}
|
|
62
|
+
return ops;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* INTERNAL
|
|
66
|
+
*/
|
|
67
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
68
|
+
if (item.type !== live_1.CrdtType.Map) {
|
|
69
|
+
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
|
|
70
|
+
}
|
|
71
|
+
const map = new LiveMap();
|
|
72
|
+
map._attach(id, doc);
|
|
73
|
+
const children = parentToChildren.get(id);
|
|
74
|
+
if (children == null) {
|
|
75
|
+
return map;
|
|
76
|
+
}
|
|
77
|
+
for (const entry of children) {
|
|
78
|
+
const crdt = entry[1];
|
|
79
|
+
if (crdt.parentKey == null) {
|
|
80
|
+
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
81
|
+
}
|
|
82
|
+
const child = (0, utils_1.deserialize)(entry, parentToChildren, doc);
|
|
83
|
+
child._setParentLink(map, crdt.parentKey);
|
|
84
|
+
__classPrivateFieldGet(map, _LiveMap_map, "f").set(crdt.parentKey, child);
|
|
85
|
+
}
|
|
86
|
+
return map;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* INTERNAL
|
|
90
|
+
*/
|
|
91
|
+
_attach(id, doc) {
|
|
92
|
+
super._attach(id, doc);
|
|
93
|
+
for (const [key, value] of __classPrivateFieldGet(this, _LiveMap_map, "f")) {
|
|
94
|
+
if ((0, utils_1.isCrdt)(value)) {
|
|
95
|
+
value._attach(doc.generateId(), doc);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* INTERNAL
|
|
101
|
+
*/
|
|
102
|
+
_attachChild(id, key, child) {
|
|
103
|
+
if (this._doc == null) {
|
|
104
|
+
throw new Error("Can't attach child if doc is not present");
|
|
105
|
+
}
|
|
106
|
+
const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
107
|
+
let reverse;
|
|
108
|
+
if (previousValue) {
|
|
109
|
+
reverse = previousValue._serialize(this._id, key);
|
|
110
|
+
previousValue._detach();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
reverse = [{ type: live_1.OpType.DeleteCrdt, id }];
|
|
114
|
+
}
|
|
115
|
+
child._setParentLink(this, key);
|
|
116
|
+
child._attach(id, this._doc);
|
|
117
|
+
__classPrivateFieldGet(this, _LiveMap_map, "f").set(key, child);
|
|
118
|
+
return { modified: this, reverse };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* INTERNAL
|
|
122
|
+
*/
|
|
123
|
+
_detach() {
|
|
124
|
+
super._detach();
|
|
125
|
+
for (const item of __classPrivateFieldGet(this, _LiveMap_map, "f").values()) {
|
|
126
|
+
item._detach();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* INTERNAL
|
|
131
|
+
*/
|
|
132
|
+
_detachChild(child) {
|
|
133
|
+
for (const [key, value] of __classPrivateFieldGet(this, _LiveMap_map, "f")) {
|
|
134
|
+
if (value === child) {
|
|
135
|
+
__classPrivateFieldGet(this, _LiveMap_map, "f").delete(key);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
child._detach();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Returns a specified element from the LiveMap.
|
|
142
|
+
* @param key The key of the element to return.
|
|
143
|
+
* @returns The element associated with the specified key, or undefined if the key can't be found in the LiveMap.
|
|
144
|
+
*/
|
|
145
|
+
get(key) {
|
|
146
|
+
const value = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
147
|
+
if (value == undefined) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
return (0, utils_1.selfOrRegisterValue)(value);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Adds or updates an element with a specified key and a value.
|
|
154
|
+
* @param key The key of the element to add. Should be a string.
|
|
155
|
+
* @param value The value of the element to add. Should be serializable to JSON.
|
|
156
|
+
*/
|
|
157
|
+
set(key, value) {
|
|
158
|
+
const oldValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
159
|
+
if (oldValue) {
|
|
160
|
+
oldValue._detach();
|
|
161
|
+
}
|
|
162
|
+
const item = (0, utils_1.selfOrRegister)(value);
|
|
163
|
+
item._setParentLink(this, key);
|
|
164
|
+
__classPrivateFieldGet(this, _LiveMap_map, "f").set(key, item);
|
|
165
|
+
if (this._doc && this._id) {
|
|
166
|
+
const id = this._doc.generateId();
|
|
167
|
+
item._attach(id, this._doc);
|
|
168
|
+
this._doc.dispatch(item._serialize(this._id, key), oldValue
|
|
169
|
+
? oldValue._serialize(this._id, key)
|
|
170
|
+
: [{ type: live_1.OpType.DeleteCrdt, id }], [this]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Returns the number of elements in the LiveMap.
|
|
175
|
+
*/
|
|
176
|
+
get size() {
|
|
177
|
+
return __classPrivateFieldGet(this, _LiveMap_map, "f").size;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Returns a boolean indicating whether an element with the specified key exists or not.
|
|
181
|
+
* @param key The key of the element to test for presence.
|
|
182
|
+
*/
|
|
183
|
+
has(key) {
|
|
184
|
+
return __classPrivateFieldGet(this, _LiveMap_map, "f").has(key);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Removes the specified element by key.
|
|
188
|
+
* @param key The key of the element to remove.
|
|
189
|
+
* @returns true if an element existed and has been removed, or false if the element does not exist.
|
|
190
|
+
*/
|
|
191
|
+
delete(key) {
|
|
192
|
+
const item = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
|
|
193
|
+
if (item == null) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
item._detach();
|
|
197
|
+
if (this._doc && item._id) {
|
|
198
|
+
this._doc.dispatch([{ type: live_1.OpType.DeleteCrdt, id: item._id }], item._serialize(this._id, key), [this]);
|
|
199
|
+
}
|
|
200
|
+
__classPrivateFieldGet(this, _LiveMap_map, "f").delete(key);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns a new Iterator object that contains the [key, value] pairs for each element.
|
|
205
|
+
*/
|
|
206
|
+
entries() {
|
|
207
|
+
const innerIterator = __classPrivateFieldGet(this, _LiveMap_map, "f").entries();
|
|
208
|
+
return {
|
|
209
|
+
[Symbol.iterator]: function () {
|
|
210
|
+
return this;
|
|
211
|
+
},
|
|
212
|
+
next() {
|
|
213
|
+
const iteratorValue = innerIterator.next();
|
|
214
|
+
if (iteratorValue.done) {
|
|
215
|
+
return {
|
|
216
|
+
done: true,
|
|
217
|
+
value: undefined,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const entry = iteratorValue.value;
|
|
221
|
+
return {
|
|
222
|
+
value: [entry[0], (0, utils_1.selfOrRegisterValue)(iteratorValue.value[1])],
|
|
223
|
+
};
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Same function object as the initial value of the entries method.
|
|
229
|
+
*/
|
|
230
|
+
[(_LiveMap_map = new WeakMap(), Symbol.iterator)]() {
|
|
231
|
+
return this.entries();
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Returns a new Iterator object that contains the keys for each element.
|
|
235
|
+
*/
|
|
236
|
+
keys() {
|
|
237
|
+
return __classPrivateFieldGet(this, _LiveMap_map, "f").keys();
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Returns a new Iterator object that contains the values for each element.
|
|
241
|
+
*/
|
|
242
|
+
values() {
|
|
243
|
+
const innerIterator = __classPrivateFieldGet(this, _LiveMap_map, "f").values();
|
|
244
|
+
return {
|
|
245
|
+
[Symbol.iterator]: function () {
|
|
246
|
+
return this;
|
|
247
|
+
},
|
|
248
|
+
next() {
|
|
249
|
+
const iteratorValue = innerIterator.next();
|
|
250
|
+
if (iteratorValue.done) {
|
|
251
|
+
return {
|
|
252
|
+
done: true,
|
|
253
|
+
value: undefined,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
value: (0, utils_1.selfOrRegisterValue)(iteratorValue.value),
|
|
258
|
+
};
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Executes a provided function once per each key/value pair in the Map object, in insertion order.
|
|
264
|
+
* @param callback Function to execute for each entry in the map.
|
|
265
|
+
*/
|
|
266
|
+
forEach(callback) {
|
|
267
|
+
for (const entry of this) {
|
|
268
|
+
callback(entry[1], entry[0], this);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.LiveMap = LiveMap;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
|
|
2
|
+
import { Op, SerializedCrdtWithId } from "./live";
|
|
3
|
+
/**
|
|
4
|
+
* The LiveObject class is similar to a JavaScript object that is synchronized on all clients.
|
|
5
|
+
* Keys should be a string, and values should be serializable to JSON.
|
|
6
|
+
* If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
|
|
7
|
+
*/
|
|
8
|
+
export declare class LiveObject<T extends Record<string, any> = Record<string, any>> extends AbstractCrdt {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(object?: T);
|
|
11
|
+
/**
|
|
12
|
+
* INTERNAL
|
|
13
|
+
*/
|
|
14
|
+
_serialize(parentId?: string, parentKey?: string): Op[];
|
|
15
|
+
/**
|
|
16
|
+
* INTERNAL
|
|
17
|
+
*/
|
|
18
|
+
static _deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveObject<{
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* INTERNAL
|
|
23
|
+
*/
|
|
24
|
+
_attach(id: string, doc: Doc): void;
|
|
25
|
+
/**
|
|
26
|
+
* INTERNAL
|
|
27
|
+
*/
|
|
28
|
+
_attachChild(id: string, key: keyof T, child: AbstractCrdt): ApplyResult;
|
|
29
|
+
/**
|
|
30
|
+
* INTERNAL
|
|
31
|
+
*/
|
|
32
|
+
_detachChild(child: AbstractCrdt): void;
|
|
33
|
+
/**
|
|
34
|
+
* INTERNAL
|
|
35
|
+
*/
|
|
36
|
+
_detach(): void;
|
|
37
|
+
/**
|
|
38
|
+
* INTERNAL
|
|
39
|
+
*/
|
|
40
|
+
_apply(op: Op): ApplyResult;
|
|
41
|
+
/**
|
|
42
|
+
* Transform the LiveObject into a javascript object
|
|
43
|
+
*/
|
|
44
|
+
toObject(): T;
|
|
45
|
+
/**
|
|
46
|
+
* Adds or updates a property with a specified key and a value.
|
|
47
|
+
* @param key The key of the property to add
|
|
48
|
+
* @param value The value of the property to add
|
|
49
|
+
*/
|
|
50
|
+
set<TKey extends keyof T>(key: TKey, value: T[TKey]): void;
|
|
51
|
+
/**
|
|
52
|
+
* Returns a specified property from the LiveObject.
|
|
53
|
+
* @param key The key of the property to get
|
|
54
|
+
*/
|
|
55
|
+
get<TKey extends keyof T>(key: TKey): T[TKey];
|
|
56
|
+
/**
|
|
57
|
+
* Adds or updates multiple properties at once with an object.
|
|
58
|
+
* @param overrides The object used to overrides properties
|
|
59
|
+
*/
|
|
60
|
+
update(overrides: Partial<T>): void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _LiveObject_instances, _LiveObject_map, _LiveObject_propToLastUpdate, _LiveObject_applyUpdate, _LiveObject_applyDeleteObjectKey;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.LiveObject = void 0;
|
|
16
|
+
const AbstractCrdt_1 = require("./AbstractCrdt");
|
|
17
|
+
const utils_1 = require("./utils");
|
|
18
|
+
const live_1 = require("./live");
|
|
19
|
+
/**
|
|
20
|
+
* The LiveObject class is similar to a JavaScript object that is synchronized on all clients.
|
|
21
|
+
* Keys should be a string, and values should be serializable to JSON.
|
|
22
|
+
* If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
|
|
23
|
+
*/
|
|
24
|
+
class LiveObject extends AbstractCrdt_1.AbstractCrdt {
|
|
25
|
+
constructor(object = {}) {
|
|
26
|
+
super();
|
|
27
|
+
_LiveObject_instances.add(this);
|
|
28
|
+
_LiveObject_map.set(this, void 0);
|
|
29
|
+
_LiveObject_propToLastUpdate.set(this, new Map());
|
|
30
|
+
for (const key in object) {
|
|
31
|
+
const value = object[key];
|
|
32
|
+
if (value instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
33
|
+
value._setParentLink(this, key);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
__classPrivateFieldSet(this, _LiveObject_map, new Map(Object.entries(object)), "f");
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* INTERNAL
|
|
40
|
+
*/
|
|
41
|
+
_serialize(parentId, parentKey) {
|
|
42
|
+
if (this._id == null) {
|
|
43
|
+
throw new Error("Cannot serialize item is not attached");
|
|
44
|
+
}
|
|
45
|
+
const ops = [];
|
|
46
|
+
const op = {
|
|
47
|
+
id: this._id,
|
|
48
|
+
type: live_1.OpType.CreateObject,
|
|
49
|
+
parentId,
|
|
50
|
+
parentKey,
|
|
51
|
+
data: {},
|
|
52
|
+
};
|
|
53
|
+
ops.push(op);
|
|
54
|
+
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) {
|
|
55
|
+
if (value instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
56
|
+
ops.push(...value._serialize(this._id, key));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
op.data[key] = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return ops;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* INTERNAL
|
|
66
|
+
*/
|
|
67
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
68
|
+
if (item.type !== live_1.CrdtType.Object) {
|
|
69
|
+
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
|
|
70
|
+
}
|
|
71
|
+
const object = new LiveObject(item.data);
|
|
72
|
+
object._attach(id, doc);
|
|
73
|
+
const children = parentToChildren.get(id);
|
|
74
|
+
if (children == null) {
|
|
75
|
+
return object;
|
|
76
|
+
}
|
|
77
|
+
for (const entry of children) {
|
|
78
|
+
const crdt = entry[1];
|
|
79
|
+
if (crdt.parentKey == null) {
|
|
80
|
+
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
81
|
+
}
|
|
82
|
+
const child = (0, utils_1.deserialize)(entry, parentToChildren, doc);
|
|
83
|
+
child._setParentLink(object, crdt.parentKey);
|
|
84
|
+
__classPrivateFieldGet(object, _LiveObject_map, "f").set(crdt.parentKey, child);
|
|
85
|
+
}
|
|
86
|
+
return object;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* INTERNAL
|
|
90
|
+
*/
|
|
91
|
+
_attach(id, doc) {
|
|
92
|
+
super._attach(id, doc);
|
|
93
|
+
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) {
|
|
94
|
+
if (value instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
95
|
+
value._attach(doc.generateId(), doc);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* INTERNAL
|
|
101
|
+
*/
|
|
102
|
+
_attachChild(id, key, child) {
|
|
103
|
+
if (this._doc == null) {
|
|
104
|
+
throw new Error("Can't attach child if doc is not present");
|
|
105
|
+
}
|
|
106
|
+
const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
107
|
+
let reverse;
|
|
108
|
+
if ((0, utils_1.isCrdt)(previousValue)) {
|
|
109
|
+
reverse = previousValue._serialize(this._id, key);
|
|
110
|
+
previousValue._detach();
|
|
111
|
+
}
|
|
112
|
+
else if (previousValue === undefined) {
|
|
113
|
+
reverse = [
|
|
114
|
+
{ type: live_1.OpType.DeleteObjectKey, id: this._id, key: key },
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
reverse = [
|
|
119
|
+
{
|
|
120
|
+
type: live_1.OpType.UpdateObject,
|
|
121
|
+
id: this._id,
|
|
122
|
+
data: { [key]: previousValue },
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, child);
|
|
127
|
+
child._setParentLink(this, key);
|
|
128
|
+
child._attach(id, this._doc);
|
|
129
|
+
return { reverse, modified: this };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* INTERNAL
|
|
133
|
+
*/
|
|
134
|
+
_detachChild(child) {
|
|
135
|
+
for (const [key, value] of __classPrivateFieldGet(this, _LiveObject_map, "f")) {
|
|
136
|
+
if (value === child) {
|
|
137
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (child) {
|
|
141
|
+
child._detach();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* INTERNAL
|
|
146
|
+
*/
|
|
147
|
+
_detach() {
|
|
148
|
+
super._detach();
|
|
149
|
+
for (const value of __classPrivateFieldGet(this, _LiveObject_map, "f").values()) {
|
|
150
|
+
if ((0, utils_1.isCrdt)(value)) {
|
|
151
|
+
value._detach();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* INTERNAL
|
|
157
|
+
*/
|
|
158
|
+
_apply(op) {
|
|
159
|
+
if (op.type === live_1.OpType.UpdateObject) {
|
|
160
|
+
return __classPrivateFieldGet(this, _LiveObject_instances, "m", _LiveObject_applyUpdate).call(this, op);
|
|
161
|
+
}
|
|
162
|
+
else if (op.type === live_1.OpType.DeleteObjectKey) {
|
|
163
|
+
return __classPrivateFieldGet(this, _LiveObject_instances, "m", _LiveObject_applyDeleteObjectKey).call(this, op);
|
|
164
|
+
}
|
|
165
|
+
return super._apply(op);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Transform the LiveObject into a javascript object
|
|
169
|
+
*/
|
|
170
|
+
toObject() {
|
|
171
|
+
return Object.fromEntries(__classPrivateFieldGet(this, _LiveObject_map, "f"));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Adds or updates a property with a specified key and a value.
|
|
175
|
+
* @param key The key of the property to add
|
|
176
|
+
* @param value The value of the property to add
|
|
177
|
+
*/
|
|
178
|
+
set(key, value) {
|
|
179
|
+
// TODO: Find out why typescript complains
|
|
180
|
+
this.update({ [key]: value });
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Returns a specified property from the LiveObject.
|
|
184
|
+
* @param key The key of the property to get
|
|
185
|
+
*/
|
|
186
|
+
get(key) {
|
|
187
|
+
return __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Adds or updates multiple properties at once with an object.
|
|
191
|
+
* @param overrides The object used to overrides properties
|
|
192
|
+
*/
|
|
193
|
+
update(overrides) {
|
|
194
|
+
if (this._doc == null || this._id == null) {
|
|
195
|
+
for (const key in overrides) {
|
|
196
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
197
|
+
if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
198
|
+
oldValue._detach();
|
|
199
|
+
}
|
|
200
|
+
const newValue = overrides[key];
|
|
201
|
+
if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
202
|
+
newValue._setParentLink(this, key);
|
|
203
|
+
}
|
|
204
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const ops = [];
|
|
209
|
+
const reverseOps = [];
|
|
210
|
+
const opId = this._doc.generateOpId();
|
|
211
|
+
const updatedProps = {};
|
|
212
|
+
const reverseUpdateOp = {
|
|
213
|
+
id: this._id,
|
|
214
|
+
type: live_1.OpType.UpdateObject,
|
|
215
|
+
data: {},
|
|
216
|
+
};
|
|
217
|
+
for (const key in overrides) {
|
|
218
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
|
|
219
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
220
|
+
if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
221
|
+
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
222
|
+
oldValue._detach();
|
|
223
|
+
}
|
|
224
|
+
else if (oldValue === undefined) {
|
|
225
|
+
reverseOps.push({ type: live_1.OpType.DeleteObjectKey, id: this._id, key });
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
reverseUpdateOp.data[key] = oldValue;
|
|
229
|
+
}
|
|
230
|
+
const newValue = overrides[key];
|
|
231
|
+
if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
232
|
+
newValue._setParentLink(this, key);
|
|
233
|
+
newValue._attach(this._doc.generateId(), this._doc);
|
|
234
|
+
ops.push(...newValue._serialize(this._id, key));
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
updatedProps[key] = newValue;
|
|
238
|
+
}
|
|
239
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
|
|
240
|
+
}
|
|
241
|
+
if (Object.keys(reverseUpdateOp.data).length !== 0) {
|
|
242
|
+
reverseOps.unshift(reverseUpdateOp);
|
|
243
|
+
}
|
|
244
|
+
if (Object.keys(updatedProps).length !== 0) {
|
|
245
|
+
ops.unshift({
|
|
246
|
+
opId,
|
|
247
|
+
id: this._id,
|
|
248
|
+
type: live_1.OpType.UpdateObject,
|
|
249
|
+
data: updatedProps,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
this._doc.dispatch(ops, reverseOps, [this]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.LiveObject = LiveObject;
|
|
256
|
+
_LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _LiveObject_instances = new WeakSet(), _LiveObject_applyUpdate = function _LiveObject_applyUpdate(op) {
|
|
257
|
+
let isModified = false;
|
|
258
|
+
const reverse = [];
|
|
259
|
+
const reverseUpdate = {
|
|
260
|
+
type: live_1.OpType.UpdateObject,
|
|
261
|
+
id: this._id,
|
|
262
|
+
data: {},
|
|
263
|
+
};
|
|
264
|
+
reverse.push(reverseUpdate);
|
|
265
|
+
for (const key in op.data) {
|
|
266
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
267
|
+
if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
|
|
268
|
+
reverse.push(...oldValue._serialize(this._id, key));
|
|
269
|
+
oldValue._detach();
|
|
270
|
+
}
|
|
271
|
+
else if (oldValue !== undefined) {
|
|
272
|
+
reverseUpdate.data[key] = oldValue;
|
|
273
|
+
}
|
|
274
|
+
else if (oldValue === undefined) {
|
|
275
|
+
reverse.push({ type: live_1.OpType.DeleteObjectKey, id: this._id, key });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
let isLocal = false;
|
|
279
|
+
if (op.opId == null) {
|
|
280
|
+
isLocal = true;
|
|
281
|
+
op.opId = this._doc.generateOpId();
|
|
282
|
+
}
|
|
283
|
+
for (const key in op.data) {
|
|
284
|
+
if (isLocal) {
|
|
285
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, op.opId);
|
|
286
|
+
}
|
|
287
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) == null) {
|
|
288
|
+
// Not modified localy so we apply update
|
|
289
|
+
isModified = true;
|
|
290
|
+
}
|
|
291
|
+
else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === op.opId) {
|
|
292
|
+
// Acknowlegment from local operation
|
|
293
|
+
__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
// Conflict, ignore remote operation
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
301
|
+
if ((0, utils_1.isCrdt)(oldValue)) {
|
|
302
|
+
oldValue._detach();
|
|
303
|
+
}
|
|
304
|
+
isModified = true;
|
|
305
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").set(key, op.data[key]);
|
|
306
|
+
}
|
|
307
|
+
if (Object.keys(reverseUpdate.data).length !== 0) {
|
|
308
|
+
reverse.unshift(reverseUpdate);
|
|
309
|
+
}
|
|
310
|
+
return isModified ? { modified: this, reverse } : { modified: false };
|
|
311
|
+
}, _LiveObject_applyDeleteObjectKey = function _LiveObject_applyDeleteObjectKey(op) {
|
|
312
|
+
const key = op.key;
|
|
313
|
+
const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
|
|
314
|
+
let reverse = [];
|
|
315
|
+
if ((0, utils_1.isCrdt)(oldValue)) {
|
|
316
|
+
reverse = oldValue._serialize(this._id, op.key);
|
|
317
|
+
oldValue._detach();
|
|
318
|
+
}
|
|
319
|
+
else if (oldValue !== undefined) {
|
|
320
|
+
reverse = [
|
|
321
|
+
{
|
|
322
|
+
type: live_1.OpType.UpdateObject,
|
|
323
|
+
id: this._id,
|
|
324
|
+
data: { [key]: oldValue },
|
|
325
|
+
},
|
|
326
|
+
];
|
|
327
|
+
}
|
|
328
|
+
__classPrivateFieldGet(this, _LiveObject_map, "f").delete(key);
|
|
329
|
+
return { modified: this, reverse };
|
|
330
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
|
|
2
|
+
import { SerializedCrdtWithId, Op } from "./live";
|
|
3
|
+
/**
|
|
4
|
+
* INTERNAL
|
|
5
|
+
*/
|
|
6
|
+
export declare class LiveRegister<TValue = any> extends AbstractCrdt {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(data: TValue);
|
|
9
|
+
get data(): TValue;
|
|
10
|
+
/**
|
|
11
|
+
* INTERNAL
|
|
12
|
+
*/
|
|
13
|
+
static _deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveRegister<any>;
|
|
14
|
+
/**
|
|
15
|
+
* INTERNAL
|
|
16
|
+
*/
|
|
17
|
+
_serialize(parentId: string, parentKey: string): Op[];
|
|
18
|
+
_attachChild(id: string, key: string, crdt: AbstractCrdt): ApplyResult;
|
|
19
|
+
_detachChild(crdt: AbstractCrdt): void;
|
|
20
|
+
_apply(op: Op): ApplyResult;
|
|
21
|
+
}
|