@liveblocks/client 0.16.12 → 0.16.13
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/index.d.ts +1 -1
- package/index.js +31 -44
- package/index.mjs +35 -47
- package/internal.d.ts +77 -199
- package/internal.js +13 -15
- package/internal.mjs +14 -16
- package/package.json +13 -9
- package/shared.d.ts +342 -181
- package/shared.js +590 -341
- package/shared.mjs +625 -306
package/shared.mjs
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
const _emittedDeprecationWarnings = new Set;
|
|
2
|
+
|
|
3
|
+
function deprecate(message, key = message) {
|
|
4
|
+
"production" !== process.env.NODE_ENV && (_emittedDeprecationWarnings.has(key) || (_emittedDeprecationWarnings.add(key),
|
|
5
|
+
console.error(`DEPRECATION WARNING: ${message}`)));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function deprecateIf(condition, message, key = message) {
|
|
9
|
+
"production" !== process.env.NODE_ENV && condition && deprecate(message, key);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function throwUsageError(message) {
|
|
13
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
14
|
+
const usageError = new Error(message);
|
|
15
|
+
throw usageError.name = "Usage error", usageError;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function errorIf(condition, message) {
|
|
20
|
+
"production" !== process.env.NODE_ENV && condition && throwUsageError(message);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function assertNever(_value, errmsg) {
|
|
24
|
+
throw new Error(errmsg);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function nn(value, errmsg = "Expected value to be non-nullable") {
|
|
28
|
+
return function(condition, errmsg) {
|
|
29
|
+
if ("production" !== process.env.NODE_ENV && !condition) {
|
|
30
|
+
const err = new Error(errmsg);
|
|
31
|
+
throw err.name = "Assertion failure", err;
|
|
32
|
+
}
|
|
33
|
+
}(null != value, errmsg), value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var ClientMsgCode, OpCode, CrdtType, ServerMsgCode, WebsocketCloseCodes, OpSource;
|
|
2
37
|
|
|
3
38
|
function isRootCrdt(crdt) {
|
|
4
39
|
return crdt.type === CrdtType.OBJECT && !isChildCrdt(crdt);
|
|
@@ -8,24 +43,32 @@ function isChildCrdt(crdt) {
|
|
|
8
43
|
return void 0 !== crdt.parentId && void 0 !== crdt.parentKey;
|
|
9
44
|
}
|
|
10
45
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
46
|
+
function HasParent(node, key) {
|
|
47
|
+
return Object.freeze({
|
|
48
|
+
type: "HasParent",
|
|
49
|
+
node: node,
|
|
50
|
+
key: key
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
!function(ClientMsgCode) {
|
|
17
55
|
ClientMsgCode[ClientMsgCode.UPDATE_PRESENCE = 100] = "UPDATE_PRESENCE", ClientMsgCode[ClientMsgCode.BROADCAST_EVENT = 103] = "BROADCAST_EVENT",
|
|
18
56
|
ClientMsgCode[ClientMsgCode.FETCH_STORAGE = 200] = "FETCH_STORAGE", ClientMsgCode[ClientMsgCode.UPDATE_STORAGE = 201] = "UPDATE_STORAGE";
|
|
19
|
-
}(ClientMsgCode || (ClientMsgCode = {})), function(
|
|
20
|
-
CrdtType[CrdtType.OBJECT = 0] = "OBJECT", CrdtType[CrdtType.LIST = 1] = "LIST",
|
|
21
|
-
CrdtType[CrdtType.MAP = 2] = "MAP", CrdtType[CrdtType.REGISTER = 3] = "REGISTER";
|
|
22
|
-
}(CrdtType || (CrdtType = {})), function(OpCode) {
|
|
57
|
+
}(ClientMsgCode || (ClientMsgCode = {})), function(OpCode) {
|
|
23
58
|
OpCode[OpCode.INIT = 0] = "INIT", OpCode[OpCode.SET_PARENT_KEY = 1] = "SET_PARENT_KEY",
|
|
24
59
|
OpCode[OpCode.CREATE_LIST = 2] = "CREATE_LIST", OpCode[OpCode.UPDATE_OBJECT = 3] = "UPDATE_OBJECT",
|
|
25
60
|
OpCode[OpCode.CREATE_OBJECT = 4] = "CREATE_OBJECT", OpCode[OpCode.DELETE_CRDT = 5] = "DELETE_CRDT",
|
|
26
61
|
OpCode[OpCode.DELETE_OBJECT_KEY = 6] = "DELETE_OBJECT_KEY", OpCode[OpCode.CREATE_MAP = 7] = "CREATE_MAP",
|
|
27
62
|
OpCode[OpCode.CREATE_REGISTER = 8] = "CREATE_REGISTER";
|
|
28
|
-
}(OpCode || (OpCode = {})), function(
|
|
63
|
+
}(OpCode || (OpCode = {})), function(CrdtType) {
|
|
64
|
+
CrdtType[CrdtType.OBJECT = 0] = "OBJECT", CrdtType[CrdtType.LIST = 1] = "LIST",
|
|
65
|
+
CrdtType[CrdtType.MAP = 2] = "MAP", CrdtType[CrdtType.REGISTER = 3] = "REGISTER";
|
|
66
|
+
}(CrdtType || (CrdtType = {})), function(ServerMsgCode) {
|
|
67
|
+
ServerMsgCode[ServerMsgCode.UPDATE_PRESENCE = 100] = "UPDATE_PRESENCE", ServerMsgCode[ServerMsgCode.USER_JOINED = 101] = "USER_JOINED",
|
|
68
|
+
ServerMsgCode[ServerMsgCode.USER_LEFT = 102] = "USER_LEFT", ServerMsgCode[ServerMsgCode.BROADCASTED_EVENT = 103] = "BROADCASTED_EVENT",
|
|
69
|
+
ServerMsgCode[ServerMsgCode.ROOM_STATE = 104] = "ROOM_STATE", ServerMsgCode[ServerMsgCode.INITIAL_STORAGE_STATE = 200] = "INITIAL_STORAGE_STATE",
|
|
70
|
+
ServerMsgCode[ServerMsgCode.UPDATE_STORAGE = 201] = "UPDATE_STORAGE";
|
|
71
|
+
}(ServerMsgCode || (ServerMsgCode = {})), function(WebsocketCloseCodes) {
|
|
29
72
|
WebsocketCloseCodes[WebsocketCloseCodes.CLOSE_ABNORMAL = 1006] = "CLOSE_ABNORMAL",
|
|
30
73
|
WebsocketCloseCodes[WebsocketCloseCodes.INVALID_MESSAGE_FORMAT = 4e3] = "INVALID_MESSAGE_FORMAT",
|
|
31
74
|
WebsocketCloseCodes[WebsocketCloseCodes.NOT_ALLOWED = 4001] = "NOT_ALLOWED", WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_MESSAGES_PER_SECONDS = 4002] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS",
|
|
@@ -33,9 +76,41 @@ function isChildCrdt(crdt) {
|
|
|
33
76
|
WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP",
|
|
34
77
|
WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM",
|
|
35
78
|
WebsocketCloseCodes[WebsocketCloseCodes.CLOSE_WITHOUT_RETRY = 4999] = "CLOSE_WITHOUT_RETRY";
|
|
36
|
-
}(WebsocketCloseCodes || (WebsocketCloseCodes = {}))
|
|
79
|
+
}(WebsocketCloseCodes || (WebsocketCloseCodes = {})), function(OpSource) {
|
|
80
|
+
OpSource[OpSource.UNDOREDO_RECONNECT = 0] = "UNDOREDO_RECONNECT", OpSource[OpSource.REMOTE = 1] = "REMOTE",
|
|
81
|
+
OpSource[OpSource.ACK = 2] = "ACK";
|
|
82
|
+
}(OpSource || (OpSource = {}));
|
|
83
|
+
|
|
84
|
+
const NoParent = Object.freeze({
|
|
85
|
+
type: "NoParent"
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
function Orphaned(oldKey) {
|
|
89
|
+
return Object.freeze({
|
|
90
|
+
type: "Orphaned",
|
|
91
|
+
oldKey: oldKey
|
|
92
|
+
});
|
|
93
|
+
}
|
|
37
94
|
|
|
38
95
|
class AbstractCrdt {
|
|
96
|
+
constructor() {
|
|
97
|
+
this._parent = NoParent;
|
|
98
|
+
}
|
|
99
|
+
_getParentKeyOrThrow() {
|
|
100
|
+
switch (this.parent.type) {
|
|
101
|
+
case "HasParent":
|
|
102
|
+
return this.parent.key;
|
|
103
|
+
|
|
104
|
+
case "NoParent":
|
|
105
|
+
throw new Error("Parent key is missing");
|
|
106
|
+
|
|
107
|
+
case "Orphaned":
|
|
108
|
+
return this.parent.oldKey;
|
|
109
|
+
|
|
110
|
+
default:
|
|
111
|
+
return assertNever(this.parent, "Unknown state");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
39
114
|
get _doc() {
|
|
40
115
|
return this.__doc;
|
|
41
116
|
}
|
|
@@ -45,37 +120,79 @@ class AbstractCrdt {
|
|
|
45
120
|
get _id() {
|
|
46
121
|
return this.__id;
|
|
47
122
|
}
|
|
48
|
-
get
|
|
49
|
-
return this.
|
|
123
|
+
get parent() {
|
|
124
|
+
return this._parent;
|
|
125
|
+
}
|
|
126
|
+
get _parentNode() {
|
|
127
|
+
switch (this.parent.type) {
|
|
128
|
+
case "HasParent":
|
|
129
|
+
return this.parent.node;
|
|
130
|
+
|
|
131
|
+
case "NoParent":
|
|
132
|
+
case "Orphaned":
|
|
133
|
+
return null;
|
|
134
|
+
|
|
135
|
+
default:
|
|
136
|
+
return assertNever(this.parent, "Unknown state");
|
|
137
|
+
}
|
|
50
138
|
}
|
|
51
139
|
get _parentKey() {
|
|
52
|
-
|
|
140
|
+
switch (this.parent.type) {
|
|
141
|
+
case "HasParent":
|
|
142
|
+
return this.parent.key;
|
|
143
|
+
|
|
144
|
+
case "NoParent":
|
|
145
|
+
return null;
|
|
146
|
+
|
|
147
|
+
case "Orphaned":
|
|
148
|
+
return this.parent.oldKey;
|
|
149
|
+
|
|
150
|
+
default:
|
|
151
|
+
return assertNever(this.parent, "Unknown state");
|
|
152
|
+
}
|
|
53
153
|
}
|
|
54
154
|
_apply(op, _isLocal) {
|
|
55
|
-
return op.type === OpCode.DELETE_CRDT &&
|
|
155
|
+
return op.type === OpCode.DELETE_CRDT && "HasParent" === this.parent.type ? this.parent.node._detachChild(this) : {
|
|
56
156
|
modified: !1
|
|
57
157
|
};
|
|
58
158
|
}
|
|
59
|
-
_setParentLink(
|
|
60
|
-
|
|
61
|
-
|
|
159
|
+
_setParentLink(newParentNode, newParentKey) {
|
|
160
|
+
switch (this.parent.type) {
|
|
161
|
+
case "HasParent":
|
|
162
|
+
if (this.parent.node !== newParentNode) throw new Error("Cannot attach parent if it already exist");
|
|
163
|
+
return void (this._parent = HasParent(newParentNode, newParentKey));
|
|
164
|
+
|
|
165
|
+
case "Orphaned":
|
|
166
|
+
case "NoParent":
|
|
167
|
+
return void (this._parent = HasParent(newParentNode, newParentKey));
|
|
168
|
+
|
|
169
|
+
default:
|
|
170
|
+
return assertNever(this.parent, "Unknown state");
|
|
171
|
+
}
|
|
62
172
|
}
|
|
63
173
|
_attach(id, doc) {
|
|
64
174
|
if (this.__id || this.__doc) throw new Error("Cannot attach if CRDT is already attached");
|
|
65
175
|
doc.addItem(id, this), this.__id = id, this.__doc = doc;
|
|
66
176
|
}
|
|
67
177
|
_detach() {
|
|
68
|
-
this.__doc && this.__id && this.__doc.deleteItem(this.__id), this.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
178
|
+
switch (this.__doc && this.__id && this.__doc.deleteItem(this.__id), this.parent.type) {
|
|
179
|
+
case "HasParent":
|
|
180
|
+
this._parent = Orphaned(this.parent.key);
|
|
181
|
+
break;
|
|
72
182
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
183
|
+
case "NoParent":
|
|
184
|
+
this._parent = NoParent;
|
|
185
|
+
break;
|
|
76
186
|
|
|
77
|
-
|
|
78
|
-
|
|
187
|
+
case "Orphaned":
|
|
188
|
+
this._parent = Orphaned(this.parent.oldKey);
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
default:
|
|
192
|
+
assertNever(this.parent, "Unknown state");
|
|
193
|
+
}
|
|
194
|
+
this.__doc = void 0;
|
|
195
|
+
}
|
|
79
196
|
}
|
|
80
197
|
|
|
81
198
|
class LiveRegister extends AbstractCrdt {
|
|
@@ -89,28 +206,27 @@ class LiveRegister extends AbstractCrdt {
|
|
|
89
206
|
const register = new LiveRegister(item.data);
|
|
90
207
|
return register._attach(id, doc), register;
|
|
91
208
|
}
|
|
92
|
-
_serialize(parentId, parentKey, doc
|
|
209
|
+
_serialize(parentId, parentKey, doc) {
|
|
93
210
|
if (null == this._id || null == parentId || null == parentKey) throw new Error("Cannot serialize register if parentId or parentKey is undefined");
|
|
94
211
|
return [ {
|
|
95
212
|
type: OpCode.CREATE_REGISTER,
|
|
96
213
|
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
97
214
|
id: this._id,
|
|
98
|
-
intent: intent,
|
|
99
215
|
parentId: parentId,
|
|
100
216
|
parentKey: parentKey,
|
|
101
217
|
data: this.data
|
|
102
218
|
} ];
|
|
103
219
|
}
|
|
104
220
|
_toSerializedCrdt() {
|
|
105
|
-
|
|
221
|
+
if ("HasParent" !== this.parent.type) throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
106
222
|
return {
|
|
107
223
|
type: CrdtType.REGISTER,
|
|
108
|
-
parentId:
|
|
109
|
-
parentKey: this.
|
|
224
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
225
|
+
parentKey: this.parent.key,
|
|
110
226
|
data: this.data
|
|
111
227
|
};
|
|
112
228
|
}
|
|
113
|
-
_attachChild(_op
|
|
229
|
+
_attachChild(_op) {
|
|
114
230
|
throw new Error("Method not implemented.");
|
|
115
231
|
}
|
|
116
232
|
_detachChild(_crdt) {
|
|
@@ -122,7 +238,7 @@ class LiveRegister extends AbstractCrdt {
|
|
|
122
238
|
}
|
|
123
239
|
|
|
124
240
|
function makePosition(before, after) {
|
|
125
|
-
return null
|
|
241
|
+
return null != before && null != after ? pos(makePositionFromCodes(posCodes(before), posCodes(after))) : null != before ? function(before) {
|
|
126
242
|
const result = [], beforeCodes = posCodes(before);
|
|
127
243
|
for (let i = 0; i < beforeCodes.length; i++) {
|
|
128
244
|
const code = beforeCodes[i];
|
|
@@ -136,7 +252,7 @@ function makePosition(before, after) {
|
|
|
136
252
|
}
|
|
137
253
|
}
|
|
138
254
|
return pos(result);
|
|
139
|
-
}(before) : null
|
|
255
|
+
}(before) : null != after ? function(after) {
|
|
140
256
|
const result = [], afterCodes = posCodes(after);
|
|
141
257
|
for (let i = 0; i < afterCodes.length; i++) {
|
|
142
258
|
const code = afterCodes[i];
|
|
@@ -150,7 +266,7 @@ function makePosition(before, after) {
|
|
|
150
266
|
}
|
|
151
267
|
}
|
|
152
268
|
return pos(result);
|
|
153
|
-
}(after) : pos(
|
|
269
|
+
}(after) : pos([ 33 ]);
|
|
154
270
|
}
|
|
155
271
|
|
|
156
272
|
function makePositionFromCodes(before, after) {
|
|
@@ -196,114 +312,243 @@ function comparePosition(posA, posB) {
|
|
|
196
312
|
class LiveList extends AbstractCrdt {
|
|
197
313
|
constructor(items = []) {
|
|
198
314
|
let position;
|
|
199
|
-
super(), this._items = [];
|
|
315
|
+
super(), this._items = [], this._implicitlyDeletedItems = new Set;
|
|
200
316
|
for (let i = 0; i < items.length; i++) {
|
|
201
|
-
const newPosition = makePosition(position), item =
|
|
202
|
-
this._items.push(
|
|
317
|
+
const newPosition = makePosition(position), item = lsonToLiveNode(items[i]);
|
|
318
|
+
item._setParentLink(this, newPosition), this._items.push(item), position = newPosition;
|
|
203
319
|
}
|
|
204
320
|
}
|
|
205
321
|
static _deserialize([id], parentToChildren, doc) {
|
|
206
|
-
const list = new LiveList
|
|
322
|
+
const list = new LiveList;
|
|
207
323
|
list._attach(id, doc);
|
|
208
324
|
const children = parentToChildren.get(id);
|
|
209
325
|
if (null == children) return list;
|
|
210
|
-
for (const
|
|
211
|
-
const child = deserialize(
|
|
212
|
-
child._setParentLink(list,
|
|
213
|
-
list._items.sort(((itemA, itemB) => comparePosition(itemA[1], itemB[1])));
|
|
326
|
+
for (const [id, crdt] of children) {
|
|
327
|
+
const child = deserialize([ id, crdt ], parentToChildren, doc);
|
|
328
|
+
child._setParentLink(list, crdt.parentKey), list._items.push(child), sortListItem(list._items);
|
|
214
329
|
}
|
|
215
330
|
return list;
|
|
216
331
|
}
|
|
217
|
-
_serialize(parentId, parentKey, doc
|
|
332
|
+
_serialize(parentId, parentKey, doc) {
|
|
218
333
|
if (null == this._id) throw new Error("Cannot serialize item is not attached");
|
|
219
|
-
if (null == parentId || null == parentKey) throw new Error("Cannot serialize list if parentId or parentKey is undefined");
|
|
220
334
|
const ops = [], op = {
|
|
221
335
|
id: this._id,
|
|
222
336
|
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
223
|
-
intent: intent,
|
|
224
337
|
type: OpCode.CREATE_LIST,
|
|
225
338
|
parentId: parentId,
|
|
226
339
|
parentKey: parentKey
|
|
227
340
|
};
|
|
228
341
|
ops.push(op);
|
|
229
|
-
for (const
|
|
342
|
+
for (const item of this._items) ops.push(...item._serialize(this._id, item._getParentKeyOrThrow(), doc));
|
|
230
343
|
return ops;
|
|
231
344
|
}
|
|
232
345
|
_indexOfPosition(position) {
|
|
233
|
-
return this._items.findIndex((item => item
|
|
346
|
+
return this._items.findIndex((item => item._getParentKeyOrThrow() === position));
|
|
234
347
|
}
|
|
235
348
|
_attach(id, doc) {
|
|
236
349
|
super._attach(id, doc);
|
|
237
|
-
for (const
|
|
350
|
+
for (const item of this._items) item._attach(doc.generateId(), doc);
|
|
238
351
|
}
|
|
239
352
|
_detach() {
|
|
240
353
|
super._detach();
|
|
241
|
-
for (const
|
|
354
|
+
for (const item of this._items) item._detach();
|
|
242
355
|
}
|
|
243
|
-
|
|
244
|
-
var _a;
|
|
356
|
+
_applyRemoteSet(op) {
|
|
245
357
|
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
246
|
-
const {id: id, parentKey:
|
|
247
|
-
if (void 0 !== this._doc.getItem(id)) return {
|
|
248
|
-
modified: !1
|
|
249
|
-
};
|
|
358
|
+
const {id: id, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
250
359
|
child._attach(id, this._doc), child._setParentLink(this, key);
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
360
|
+
const deletedId = op.deletedId, existingItemIndex = this._indexOfPosition(key);
|
|
361
|
+
if (-1 !== existingItemIndex) {
|
|
362
|
+
const existingItem = this._items[existingItemIndex];
|
|
363
|
+
if (existingItem._id === deletedId) return existingItem._detach(), this._items[existingItemIndex] = child,
|
|
364
|
+
{
|
|
365
|
+
modified: makeUpdate(this, [ setDelta(existingItemIndex, child) ]),
|
|
366
|
+
reverse: []
|
|
367
|
+
};
|
|
368
|
+
{
|
|
369
|
+
this._implicitlyDeletedItems.add(existingItem), this._items[existingItemIndex] = child;
|
|
370
|
+
const delta = [ setDelta(existingItemIndex, child) ], deleteDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
371
|
+
return deleteDelta && delta.push(deleteDelta), {
|
|
372
|
+
modified: makeUpdate(this, delta),
|
|
373
|
+
reverse: []
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
{
|
|
378
|
+
const updates = [], deleteDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
379
|
+
return deleteDelta && updates.push(deleteDelta), this._items.push(child), sortListItem(this._items),
|
|
380
|
+
updates.push(insertDelta(this._indexOfPosition(key), child)), {
|
|
381
|
+
reverse: [],
|
|
382
|
+
modified: makeUpdate(this, updates)
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
_applySetAck(op) {
|
|
387
|
+
const delta = [], deletedDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
388
|
+
deletedDelta && delta.push(deletedDelta);
|
|
389
|
+
const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey), existingItem = this._items.find((item => item._id === op.id));
|
|
390
|
+
if (null != existingItem) {
|
|
391
|
+
if (existingItem._parentKey === op.parentKey) return delta.length > 0 ? {
|
|
392
|
+
modified: makeUpdate(this, delta),
|
|
393
|
+
reverse: []
|
|
394
|
+
} : {
|
|
395
|
+
modified: !1
|
|
396
|
+
};
|
|
397
|
+
-1 !== indexOfItemWithSamePosition && (this._implicitlyDeletedItems.add(this._items[indexOfItemWithSamePosition]),
|
|
398
|
+
this._items.splice(indexOfItemWithSamePosition, 1), delta.push(deleteDelta(indexOfItemWithSamePosition)));
|
|
399
|
+
const previousIndex = this._items.indexOf(existingItem);
|
|
400
|
+
existingItem._setParentLink(this, op.parentKey), sortListItem(this._items);
|
|
401
|
+
const newIndex = this._items.indexOf(existingItem);
|
|
402
|
+
return newIndex !== previousIndex && delta.push(moveDelta(previousIndex, newIndex, existingItem)),
|
|
403
|
+
{
|
|
404
|
+
modified: delta.length > 0 && makeUpdate(this, delta),
|
|
405
|
+
reverse: []
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
{
|
|
409
|
+
const orphan = nn(this._doc).getItem(op.id);
|
|
410
|
+
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
411
|
+
orphan._setParentLink(this, op.parentKey), this._implicitlyDeletedItems.delete(orphan),
|
|
412
|
+
this._items.push(orphan), sortListItem(this._items);
|
|
413
|
+
const recreatedItemIndex = this._items.indexOf(orphan);
|
|
414
|
+
return {
|
|
415
|
+
modified: makeUpdate(this, [ -1 === indexOfItemWithSamePosition ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan), ...delta ]),
|
|
416
|
+
reverse: []
|
|
265
417
|
};
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
418
|
+
}
|
|
419
|
+
{
|
|
420
|
+
const {newItem: newItem, newIndex: newIndex} = this._createAttachItemAndSort(op, op.parentKey);
|
|
421
|
+
return {
|
|
422
|
+
modified: makeUpdate(this, [ -1 === indexOfItemWithSamePosition ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem), ...delta ]),
|
|
423
|
+
reverse: []
|
|
269
424
|
};
|
|
270
425
|
}
|
|
271
|
-
if (isLocal) {
|
|
272
|
-
const before = this._items[index] ? this._items[index][1] : void 0, after = this._items[index + 1] ? this._items[index + 1][1] : void 0;
|
|
273
|
-
newKey = makePosition(before, after), child._setParentLink(this, newKey);
|
|
274
|
-
} else this._items[index][1] = makePosition(key, null === (_a = this._items[index + 1]) || void 0 === _a ? void 0 : _a[1]);
|
|
275
426
|
}
|
|
276
|
-
|
|
277
|
-
|
|
427
|
+
}
|
|
428
|
+
_detachItemAssociatedToSetOperation(deletedId) {
|
|
429
|
+
if (null == deletedId || null == this._doc) return null;
|
|
430
|
+
const deletedItem = this._doc.getItem(deletedId);
|
|
431
|
+
if (null == deletedItem) return null;
|
|
432
|
+
const result = this._detachChild(deletedItem);
|
|
433
|
+
return !1 === result.modified ? null : result.modified.updates[0];
|
|
434
|
+
}
|
|
435
|
+
_applyRemoteInsert(op) {
|
|
436
|
+
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
437
|
+
const key = op.parentKey, existingItemIndex = this._indexOfPosition(key);
|
|
438
|
+
-1 !== existingItemIndex && this._shiftItemPosition(existingItemIndex, key);
|
|
439
|
+
const {newItem: newItem, newIndex: newIndex} = this._createAttachItemAndSort(op, key);
|
|
278
440
|
return {
|
|
441
|
+
modified: makeUpdate(this, [ insertDelta(newIndex, newItem) ]),
|
|
442
|
+
reverse: []
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
_applyInsertAck(op) {
|
|
446
|
+
const existingItem = this._items.find((item => item._id === op.id)), key = op.parentKey, itemIndexAtPosition = this._indexOfPosition(key);
|
|
447
|
+
if (existingItem) {
|
|
448
|
+
if (existingItem._parentKey === key) return {
|
|
449
|
+
modified: !1
|
|
450
|
+
};
|
|
451
|
+
{
|
|
452
|
+
const oldPositionIndex = this._items.indexOf(existingItem);
|
|
453
|
+
-1 !== itemIndexAtPosition && this._shiftItemPosition(itemIndexAtPosition, key),
|
|
454
|
+
existingItem._setParentLink(this, key), sortListItem(this._items);
|
|
455
|
+
const newIndex = this._indexOfPosition(key);
|
|
456
|
+
return newIndex === oldPositionIndex ? {
|
|
457
|
+
modified: !1
|
|
458
|
+
} : {
|
|
459
|
+
modified: makeUpdate(this, [ moveDelta(oldPositionIndex, newIndex, existingItem) ]),
|
|
460
|
+
reverse: []
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
{
|
|
465
|
+
const orphan = nn(this._doc).getItem(op.id);
|
|
466
|
+
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
467
|
+
orphan._setParentLink(this, key), this._implicitlyDeletedItems.delete(orphan), this._items.push(orphan),
|
|
468
|
+
sortListItem(this._items);
|
|
469
|
+
return {
|
|
470
|
+
modified: makeUpdate(this, [ insertDelta(this._indexOfPosition(key), orphan) ]),
|
|
471
|
+
reverse: []
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
{
|
|
475
|
+
-1 !== itemIndexAtPosition && this._shiftItemPosition(itemIndexAtPosition, key);
|
|
476
|
+
const {newItem: newItem, newIndex: newIndex} = this._createAttachItemAndSort(op, key);
|
|
477
|
+
return {
|
|
478
|
+
modified: makeUpdate(this, [ insertDelta(newIndex, newItem) ]),
|
|
479
|
+
reverse: []
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
_applyInsertUndoRedo(op) {
|
|
485
|
+
var _a;
|
|
486
|
+
const {id: id, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
487
|
+
if (void 0 !== (null === (_a = this._doc) || void 0 === _a ? void 0 : _a.getItem(id))) return {
|
|
488
|
+
modified: !1
|
|
489
|
+
};
|
|
490
|
+
child._attach(id, nn(this._doc)), child._setParentLink(this, key);
|
|
491
|
+
const existingItemIndex = this._indexOfPosition(key);
|
|
492
|
+
let newKey = key;
|
|
493
|
+
if (-1 !== existingItemIndex) {
|
|
494
|
+
newKey = makePosition(this._items[existingItemIndex] ? this._items[existingItemIndex]._getParentKeyOrThrow() : void 0, this._items[existingItemIndex + 1] ? this._items[existingItemIndex + 1]._getParentKeyOrThrow() : void 0),
|
|
495
|
+
child._setParentLink(this, newKey);
|
|
496
|
+
}
|
|
497
|
+
this._items.push(child), sortListItem(this._items);
|
|
498
|
+
return {
|
|
499
|
+
modified: makeUpdate(this, [ insertDelta(this._indexOfPosition(newKey), child) ]),
|
|
279
500
|
reverse: [ {
|
|
280
501
|
type: OpCode.DELETE_CRDT,
|
|
281
502
|
id: id
|
|
282
|
-
} ]
|
|
283
|
-
modified: {
|
|
284
|
-
node: this,
|
|
285
|
-
type: "LiveList",
|
|
286
|
-
updates: [ {
|
|
287
|
-
index: newIndex,
|
|
288
|
-
type: "insert",
|
|
289
|
-
item: child instanceof LiveRegister ? child.data : child
|
|
290
|
-
} ]
|
|
291
|
-
}
|
|
503
|
+
} ]
|
|
292
504
|
};
|
|
293
505
|
}
|
|
506
|
+
_applySetUndoRedo(op) {
|
|
507
|
+
var _a;
|
|
508
|
+
const {id: id, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
509
|
+
if (void 0 !== (null === (_a = this._doc) || void 0 === _a ? void 0 : _a.getItem(id))) return {
|
|
510
|
+
modified: !1
|
|
511
|
+
};
|
|
512
|
+
const indexOfItemWithSameKey = this._indexOfPosition(key);
|
|
513
|
+
child._attach(id, nn(this._doc)), child._setParentLink(this, key);
|
|
514
|
+
const newKey = key;
|
|
515
|
+
if (-1 !== indexOfItemWithSameKey) {
|
|
516
|
+
const existingItem = this._items[indexOfItemWithSameKey];
|
|
517
|
+
existingItem._detach(), this._items[indexOfItemWithSameKey] = child;
|
|
518
|
+
const reverse = existingItem._serialize(nn(this._id), key, this._doc);
|
|
519
|
+
addIntentAndDeletedIdToOperation(reverse, op.id);
|
|
520
|
+
const delta = [ setDelta(indexOfItemWithSameKey, child) ], deletedDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
521
|
+
return deletedDelta && delta.push(deletedDelta), {
|
|
522
|
+
modified: makeUpdate(this, delta),
|
|
523
|
+
reverse: reverse
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
{
|
|
527
|
+
this._items.push(child), sortListItem(this._items), this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
528
|
+
const newIndex = this._indexOfPosition(newKey);
|
|
529
|
+
return {
|
|
530
|
+
reverse: [ {
|
|
531
|
+
type: OpCode.DELETE_CRDT,
|
|
532
|
+
id: id
|
|
533
|
+
} ],
|
|
534
|
+
modified: makeUpdate(this, [ insertDelta(newIndex, child) ])
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
_attachChild(op, source) {
|
|
539
|
+
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
540
|
+
if ("set" === op.intent) {
|
|
541
|
+
if (source === OpSource.REMOTE) return this._applyRemoteSet(op);
|
|
542
|
+
if (source === OpSource.UNDOREDO_RECONNECT) return this._applySetUndoRedo(op);
|
|
543
|
+
if (source === OpSource.ACK) return this._applySetAck(op);
|
|
544
|
+
}
|
|
545
|
+
return source === OpSource.REMOTE ? this._applyRemoteInsert(op) : source === OpSource.ACK ? this._applyInsertAck(op) : this._applyInsertUndoRedo(op);
|
|
546
|
+
}
|
|
294
547
|
_detachChild(child) {
|
|
295
548
|
if (child) {
|
|
296
|
-
const reverse = child._serialize(this._id,
|
|
297
|
-
this._items.splice(indexToDelete, 1), child._detach()
|
|
298
|
-
|
|
299
|
-
modified: {
|
|
300
|
-
node: this,
|
|
301
|
-
type: "LiveList",
|
|
302
|
-
updates: [ {
|
|
303
|
-
index: indexToDelete,
|
|
304
|
-
type: "delete"
|
|
305
|
-
} ]
|
|
306
|
-
},
|
|
549
|
+
const parentKey = nn(child._parentKey), reverse = child._serialize(nn(this._id), parentKey, this._doc), indexToDelete = this._items.indexOf(child);
|
|
550
|
+
return this._items.splice(indexToDelete, 1), child._detach(), {
|
|
551
|
+
modified: makeUpdate(this, [ deleteDelta(indexToDelete) ]),
|
|
307
552
|
reverse: reverse
|
|
308
553
|
};
|
|
309
554
|
}
|
|
@@ -311,41 +556,100 @@ class LiveList extends AbstractCrdt {
|
|
|
311
556
|
modified: !1
|
|
312
557
|
};
|
|
313
558
|
}
|
|
314
|
-
|
|
559
|
+
_applySetChildKeyRemote(newKey, child) {
|
|
315
560
|
var _a;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
561
|
+
if (this._implicitlyDeletedItems.has(child)) {
|
|
562
|
+
this._implicitlyDeletedItems.delete(child), child._setParentLink(this, newKey),
|
|
563
|
+
this._items.push(child), sortListItem(this._items);
|
|
564
|
+
return {
|
|
565
|
+
modified: makeUpdate(this, [ insertDelta(this._items.indexOf(child), child) ]),
|
|
566
|
+
reverse: []
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
if (newKey === child._parentKey) return {
|
|
570
|
+
modified: !1
|
|
571
|
+
};
|
|
572
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
573
|
+
if (-1 === existingItemIndex) {
|
|
574
|
+
const previousIndex = this._items.indexOf(child);
|
|
575
|
+
child._setParentLink(this, newKey), sortListItem(this._items);
|
|
576
|
+
const newIndex = this._items.indexOf(child);
|
|
577
|
+
return newIndex === previousIndex ? {
|
|
578
|
+
modified: !1
|
|
579
|
+
} : {
|
|
580
|
+
modified: makeUpdate(this, [ moveDelta(previousIndex, newIndex, child) ]),
|
|
581
|
+
reverse: []
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
{
|
|
585
|
+
this._items[existingItemIndex]._setParentLink(this, makePosition(newKey, null === (_a = this._items[existingItemIndex + 1]) || void 0 === _a ? void 0 : _a._getParentKeyOrThrow()));
|
|
586
|
+
const previousIndex = this._items.indexOf(child);
|
|
587
|
+
child._setParentLink(this, newKey), sortListItem(this._items);
|
|
588
|
+
const newIndex = this._items.indexOf(child);
|
|
589
|
+
return newIndex === previousIndex ? {
|
|
590
|
+
modified: !1
|
|
591
|
+
} : {
|
|
592
|
+
modified: makeUpdate(this, [ moveDelta(previousIndex, newIndex, child) ]),
|
|
593
|
+
reverse: []
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
_applySetChildKeyAck(newKey, child) {
|
|
598
|
+
var _a, _b;
|
|
599
|
+
const previousKey = nn(child._parentKey);
|
|
600
|
+
if (this._implicitlyDeletedItems.has(child)) {
|
|
601
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
602
|
+
return this._implicitlyDeletedItems.delete(child), -1 !== existingItemIndex && this._items[existingItemIndex]._setParentLink(this, makePosition(newKey, null === (_a = this._items[existingItemIndex + 1]) || void 0 === _a ? void 0 : _a._getParentKeyOrThrow())),
|
|
603
|
+
child._setParentLink(this, newKey), this._items.push(child), sortListItem(this._items),
|
|
604
|
+
{
|
|
605
|
+
modified: !1
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
{
|
|
609
|
+
if (newKey === previousKey) return {
|
|
610
|
+
modified: !1
|
|
611
|
+
};
|
|
612
|
+
const previousIndex = this._items.indexOf(child), existingItemIndex = this._indexOfPosition(newKey);
|
|
613
|
+
-1 !== existingItemIndex && this._items[existingItemIndex]._setParentLink(this, makePosition(newKey, null === (_b = this._items[existingItemIndex + 1]) || void 0 === _b ? void 0 : _b._getParentKeyOrThrow())),
|
|
614
|
+
child._setParentLink(this, newKey), sortListItem(this._items);
|
|
615
|
+
const newIndex = this._items.indexOf(child);
|
|
616
|
+
return previousIndex === newIndex ? {
|
|
617
|
+
modified: !1
|
|
618
|
+
} : {
|
|
619
|
+
modified: makeUpdate(this, [ moveDelta(previousIndex, newIndex, child) ]),
|
|
620
|
+
reverse: []
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
_applySetChildKeyUndoRedo(newKey, child) {
|
|
625
|
+
var _a;
|
|
626
|
+
const previousKey = nn(child._parentKey), previousIndex = this._items.indexOf(child), existingItemIndex = this._indexOfPosition(newKey);
|
|
627
|
+
-1 !== existingItemIndex && this._items[existingItemIndex]._setParentLink(this, makePosition(newKey, null === (_a = this._items[existingItemIndex + 1]) || void 0 === _a ? void 0 : _a._getParentKeyOrThrow())),
|
|
628
|
+
child._setParentLink(this, newKey), sortListItem(this._items);
|
|
629
|
+
const newIndex = this._items.indexOf(child);
|
|
630
|
+
return previousIndex === newIndex ? {
|
|
631
|
+
modified: !1
|
|
632
|
+
} : {
|
|
633
|
+
modified: makeUpdate(this, [ moveDelta(previousIndex, newIndex, child) ]),
|
|
333
634
|
reverse: [ {
|
|
334
635
|
type: OpCode.SET_PARENT_KEY,
|
|
335
|
-
id:
|
|
636
|
+
id: nn(child._id),
|
|
336
637
|
parentKey: previousKey
|
|
337
638
|
} ]
|
|
338
639
|
};
|
|
339
640
|
}
|
|
641
|
+
_setChildKey(newKey, child, source) {
|
|
642
|
+
return source === OpSource.REMOTE ? this._applySetChildKeyRemote(newKey, child) : source === OpSource.ACK ? this._applySetChildKeyAck(newKey, child) : this._applySetChildKeyUndoRedo(newKey, child);
|
|
643
|
+
}
|
|
340
644
|
_apply(op, isLocal) {
|
|
341
645
|
return super._apply(op, isLocal);
|
|
342
646
|
}
|
|
343
647
|
_toSerializedCrdt() {
|
|
344
|
-
|
|
648
|
+
if ("HasParent" !== this.parent.type) throw new Error("Cannot serialize LiveList if parent is missing");
|
|
345
649
|
return {
|
|
346
650
|
type: CrdtType.LIST,
|
|
347
|
-
parentId:
|
|
348
|
-
parentKey: this.
|
|
651
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
652
|
+
parentKey: this.parent.key
|
|
349
653
|
};
|
|
350
654
|
}
|
|
351
655
|
get length() {
|
|
@@ -356,25 +660,14 @@ class LiveList extends AbstractCrdt {
|
|
|
356
660
|
}
|
|
357
661
|
insert(element, index) {
|
|
358
662
|
if (index < 0 || index > this._items.length) throw new Error(`Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`);
|
|
359
|
-
const position = makePosition(this._items[index - 1] ? this._items[index - 1]
|
|
360
|
-
value._setParentLink(this, position), this._items.push(
|
|
361
|
-
|
|
362
|
-
if (this._doc && this._id) {
|
|
663
|
+
const position = makePosition(this._items[index - 1] ? this._items[index - 1]._getParentKeyOrThrow() : void 0, this._items[index] ? this._items[index]._getParentKeyOrThrow() : void 0), value = lsonToLiveNode(element);
|
|
664
|
+
if (value._setParentLink(this, position), this._items.push(value), sortListItem(this._items),
|
|
665
|
+
this._doc && this._id) {
|
|
363
666
|
const id = this._doc.generateId();
|
|
364
|
-
value._attach(id, this._doc)
|
|
365
|
-
const storageUpdates = new Map;
|
|
366
|
-
storageUpdates.set(this._id, {
|
|
367
|
-
node: this,
|
|
368
|
-
type: "LiveList",
|
|
369
|
-
updates: [ {
|
|
370
|
-
index: newIndex,
|
|
371
|
-
item: value instanceof LiveRegister ? value.data : value,
|
|
372
|
-
type: "insert"
|
|
373
|
-
} ]
|
|
374
|
-
}), this._doc.dispatch(value._serialize(this._id, position, this._doc), [ {
|
|
667
|
+
value._attach(id, this._doc), this._doc.dispatch(value._serialize(this._id, position, this._doc), [ {
|
|
375
668
|
type: OpCode.DELETE_CRDT,
|
|
376
669
|
id: id
|
|
377
|
-
} ],
|
|
670
|
+
} ], new Map([ [ this._id, makeUpdate(this, [ insertDelta(index, value) ]) ] ]));
|
|
378
671
|
}
|
|
379
672
|
}
|
|
380
673
|
move(index, targetIndex) {
|
|
@@ -383,31 +676,20 @@ class LiveList extends AbstractCrdt {
|
|
|
383
676
|
if (index < 0) throw new Error("index cannot be less than 0");
|
|
384
677
|
if (index >= this._items.length) throw new Error("index cannot be greater or equal than the list length");
|
|
385
678
|
let beforePosition = null, afterPosition = null;
|
|
386
|
-
index < targetIndex ? (afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1]
|
|
387
|
-
beforePosition = this._items[targetIndex]
|
|
388
|
-
beforePosition = 0 === targetIndex ? void 0 : this._items[targetIndex - 1]
|
|
389
|
-
const position = makePosition(beforePosition, afterPosition), item = this._items[index], previousPosition = item
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const storageUpdates = new Map;
|
|
394
|
-
storageUpdates.set(this._id, {
|
|
395
|
-
node: this,
|
|
396
|
-
type: "LiveList",
|
|
397
|
-
updates: [ {
|
|
398
|
-
index: newIndex,
|
|
399
|
-
previousIndex: index,
|
|
400
|
-
item: item[0],
|
|
401
|
-
type: "move"
|
|
402
|
-
} ]
|
|
403
|
-
}), this._doc.dispatch([ {
|
|
679
|
+
index < targetIndex ? (afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1]._getParentKeyOrThrow(),
|
|
680
|
+
beforePosition = this._items[targetIndex]._getParentKeyOrThrow()) : (afterPosition = this._items[targetIndex]._getParentKeyOrThrow(),
|
|
681
|
+
beforePosition = 0 === targetIndex ? void 0 : this._items[targetIndex - 1]._getParentKeyOrThrow());
|
|
682
|
+
const position = makePosition(beforePosition, afterPosition), item = this._items[index], previousPosition = item._getParentKeyOrThrow();
|
|
683
|
+
if (item._setParentLink(this, position), sortListItem(this._items), this._doc && this._id) {
|
|
684
|
+
const storageUpdates = new Map([ [ this._id, makeUpdate(this, [ moveDelta(index, targetIndex, item) ]) ] ]);
|
|
685
|
+
this._doc.dispatch([ {
|
|
404
686
|
type: OpCode.SET_PARENT_KEY,
|
|
405
|
-
id: item
|
|
687
|
+
id: nn(item._id),
|
|
406
688
|
opId: this._doc.generateOpId(),
|
|
407
689
|
parentKey: position
|
|
408
690
|
} ], [ {
|
|
409
691
|
type: OpCode.SET_PARENT_KEY,
|
|
410
|
-
id: item
|
|
692
|
+
id: nn(item._id),
|
|
411
693
|
parentKey: previousPosition
|
|
412
694
|
} ], storageUpdates);
|
|
413
695
|
}
|
|
@@ -415,22 +697,15 @@ class LiveList extends AbstractCrdt {
|
|
|
415
697
|
delete(index) {
|
|
416
698
|
if (index < 0 || index >= this._items.length) throw new Error(`Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`);
|
|
417
699
|
const item = this._items[index];
|
|
418
|
-
if (item
|
|
419
|
-
const childRecordId = item
|
|
700
|
+
if (item._detach(), this._items.splice(index, 1), this._doc) {
|
|
701
|
+
const childRecordId = item._id;
|
|
420
702
|
if (childRecordId) {
|
|
421
703
|
const storageUpdates = new Map;
|
|
422
|
-
storageUpdates.set(this._id, {
|
|
423
|
-
node: this,
|
|
424
|
-
type: "LiveList",
|
|
425
|
-
updates: [ {
|
|
426
|
-
index: index,
|
|
427
|
-
type: "delete"
|
|
428
|
-
} ]
|
|
429
|
-
}), this._doc.dispatch([ {
|
|
704
|
+
storageUpdates.set(nn(this._id), makeUpdate(this, [ deleteDelta(index) ])), this._doc.dispatch([ {
|
|
430
705
|
id: childRecordId,
|
|
431
706
|
opId: this._doc.generateOpId(),
|
|
432
707
|
type: OpCode.DELETE_CRDT
|
|
433
|
-
} ], item
|
|
708
|
+
} ], item._serialize(nn(this._id), item._getParentKeyOrThrow()), storageUpdates);
|
|
434
709
|
}
|
|
435
710
|
}
|
|
436
711
|
}
|
|
@@ -439,50 +714,41 @@ class LiveList extends AbstractCrdt {
|
|
|
439
714
|
const ops = [], reverseOps = [], updateDelta = [];
|
|
440
715
|
let i = 0;
|
|
441
716
|
for (const item of this._items) {
|
|
442
|
-
item
|
|
443
|
-
const childId = item
|
|
717
|
+
item._detach();
|
|
718
|
+
const childId = item._id;
|
|
444
719
|
childId && (ops.push({
|
|
720
|
+
type: OpCode.DELETE_CRDT,
|
|
445
721
|
id: childId,
|
|
446
|
-
|
|
447
|
-
}), reverseOps.push(...item
|
|
448
|
-
|
|
449
|
-
type: "delete"
|
|
450
|
-
})), i++;
|
|
722
|
+
opId: this._doc.generateOpId()
|
|
723
|
+
}), reverseOps.push(...item._serialize(nn(this._id), item._getParentKeyOrThrow())),
|
|
724
|
+
updateDelta.push(deleteDelta(i))), i++;
|
|
451
725
|
}
|
|
452
726
|
this._items = [];
|
|
453
727
|
const storageUpdates = new Map;
|
|
454
|
-
storageUpdates.set(this._id,
|
|
455
|
-
node: this,
|
|
456
|
-
type: "LiveList",
|
|
457
|
-
updates: updateDelta
|
|
458
|
-
}), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
728
|
+
storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta)), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
459
729
|
} else {
|
|
460
|
-
for (const item of this._items) item
|
|
730
|
+
for (const item of this._items) item._detach();
|
|
461
731
|
this._items = [];
|
|
462
732
|
}
|
|
463
733
|
}
|
|
464
734
|
set(index, item) {
|
|
465
735
|
if (index < 0 || index >= this._items.length) throw new Error(`Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`);
|
|
466
|
-
const
|
|
736
|
+
const existingItem = this._items[index], position = existingItem._getParentKeyOrThrow(), existingId = existingItem._id;
|
|
467
737
|
existingItem._detach();
|
|
468
|
-
const value =
|
|
469
|
-
if (value._setParentLink(this, position), this._items[index]
|
|
738
|
+
const value = lsonToLiveNode(item);
|
|
739
|
+
if (value._setParentLink(this, position), this._items[index] = value, this._doc && this._id) {
|
|
470
740
|
const id = this._doc.generateId();
|
|
471
741
|
value._attach(id, this._doc);
|
|
472
742
|
const storageUpdates = new Map;
|
|
473
|
-
storageUpdates.set(this._id,
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
item: value instanceof LiveRegister ? value.data : value,
|
|
479
|
-
type: "set"
|
|
480
|
-
} ]
|
|
481
|
-
}), this._doc.dispatch(value._serialize(this._id, position, this._doc, "set"), existingItem._serialize(this._id, position, void 0, "set"), storageUpdates);
|
|
743
|
+
storageUpdates.set(this._id, makeUpdate(this, [ setDelta(index, value) ]));
|
|
744
|
+
const ops = value._serialize(this._id, position, this._doc);
|
|
745
|
+
addIntentAndDeletedIdToOperation(ops, existingId);
|
|
746
|
+
const reverseOps = existingItem._serialize(this._id, position, void 0);
|
|
747
|
+
addIntentAndDeletedIdToOperation(reverseOps, id), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
482
748
|
}
|
|
483
749
|
}
|
|
484
750
|
toArray() {
|
|
485
|
-
return this._items.map((entry =>
|
|
751
|
+
return this._items.map((entry => liveNodeToLson(entry)));
|
|
486
752
|
}
|
|
487
753
|
every(predicate) {
|
|
488
754
|
return this.toArray().every(predicate);
|
|
@@ -500,7 +766,7 @@ class LiveList extends AbstractCrdt {
|
|
|
500
766
|
return this.toArray().forEach(callbackfn);
|
|
501
767
|
}
|
|
502
768
|
get(index) {
|
|
503
|
-
if (!(index < 0 || index >= this._items.length)) return
|
|
769
|
+
if (!(index < 0 || index >= this._items.length)) return liveNodeToLson(this._items[index]);
|
|
504
770
|
}
|
|
505
771
|
indexOf(searchElement, fromIndex) {
|
|
506
772
|
return this.toArray().indexOf(searchElement, fromIndex);
|
|
@@ -509,7 +775,7 @@ class LiveList extends AbstractCrdt {
|
|
|
509
775
|
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
510
776
|
}
|
|
511
777
|
map(callback) {
|
|
512
|
-
return this._items.map(((entry, i) => callback(
|
|
778
|
+
return this._items.map(((entry, i) => callback(liveNodeToLson(entry), i)));
|
|
513
779
|
}
|
|
514
780
|
some(predicate) {
|
|
515
781
|
return this.toArray().some(predicate);
|
|
@@ -517,6 +783,20 @@ class LiveList extends AbstractCrdt {
|
|
|
517
783
|
[Symbol.iterator]() {
|
|
518
784
|
return new LiveListIterator(this._items);
|
|
519
785
|
}
|
|
786
|
+
_createAttachItemAndSort(op, key) {
|
|
787
|
+
const newItem = creationOpToLiveNode(op);
|
|
788
|
+
newItem._attach(op.id, nn(this._doc)), newItem._setParentLink(this, key), this._items.push(newItem),
|
|
789
|
+
sortListItem(this._items);
|
|
790
|
+
return {
|
|
791
|
+
newItem: newItem,
|
|
792
|
+
newIndex: this._indexOfPosition(key)
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
_shiftItemPosition(index, key) {
|
|
796
|
+
var _a;
|
|
797
|
+
const shiftedPosition = makePosition(key, this._items.length > index + 1 ? null === (_a = this._items[index + 1]) || void 0 === _a ? void 0 : _a._getParentKeyOrThrow() : void 0);
|
|
798
|
+
this._items[index]._setParentLink(this, shiftedPosition);
|
|
799
|
+
}
|
|
520
800
|
}
|
|
521
801
|
|
|
522
802
|
class LiveListIterator {
|
|
@@ -528,57 +808,85 @@ class LiveListIterator {
|
|
|
528
808
|
}
|
|
529
809
|
next() {
|
|
530
810
|
const result = this._innerIterator.next();
|
|
531
|
-
|
|
811
|
+
if (result.done) return {
|
|
532
812
|
done: !0,
|
|
533
813
|
value: void 0
|
|
534
|
-
}
|
|
535
|
-
|
|
814
|
+
};
|
|
815
|
+
return {
|
|
816
|
+
value: liveNodeToLson(result.value)
|
|
536
817
|
};
|
|
537
818
|
}
|
|
538
819
|
}
|
|
539
820
|
|
|
540
|
-
|
|
821
|
+
function makeUpdate(liveList, deltaUpdates) {
|
|
822
|
+
return {
|
|
823
|
+
node: liveList,
|
|
824
|
+
type: "LiveList",
|
|
825
|
+
updates: deltaUpdates
|
|
826
|
+
};
|
|
827
|
+
}
|
|
541
828
|
|
|
542
|
-
function
|
|
543
|
-
|
|
544
|
-
|
|
829
|
+
function setDelta(index, item) {
|
|
830
|
+
return {
|
|
831
|
+
index: index,
|
|
832
|
+
type: "set",
|
|
833
|
+
item: item instanceof LiveRegister ? item.data : item
|
|
834
|
+
};
|
|
545
835
|
}
|
|
546
836
|
|
|
547
|
-
function
|
|
548
|
-
|
|
837
|
+
function deleteDelta(index) {
|
|
838
|
+
return {
|
|
839
|
+
index: index,
|
|
840
|
+
type: "delete"
|
|
841
|
+
};
|
|
549
842
|
}
|
|
550
843
|
|
|
551
|
-
function
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
844
|
+
function insertDelta(index, item) {
|
|
845
|
+
return {
|
|
846
|
+
index: index,
|
|
847
|
+
type: "insert",
|
|
848
|
+
item: item instanceof LiveRegister ? item.data : item
|
|
849
|
+
};
|
|
556
850
|
}
|
|
557
851
|
|
|
558
|
-
function
|
|
559
|
-
|
|
852
|
+
function moveDelta(previousIndex, index, item) {
|
|
853
|
+
return {
|
|
854
|
+
index: index,
|
|
855
|
+
type: "move",
|
|
856
|
+
previousIndex: previousIndex,
|
|
857
|
+
item: item instanceof LiveRegister ? item.data : item
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
function sortListItem(items) {
|
|
862
|
+
items.sort(((itemA, itemB) => comparePosition(itemA._getParentKeyOrThrow(), itemB._getParentKeyOrThrow())));
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function addIntentAndDeletedIdToOperation(ops, deletedId) {
|
|
866
|
+
if (0 === ops.length) throw new Error("Internal error. Serialized LiveStructure should have at least 1 operation");
|
|
867
|
+
const firstOp = ops[0];
|
|
868
|
+
if (firstOp.type !== OpCode.CREATE_LIST && firstOp.type !== OpCode.CREATE_OBJECT && firstOp.type !== OpCode.CREATE_REGISTER && firstOp.type !== OpCode.CREATE_MAP) throw new Error("Internal error. Serialized LiveStructure first op should be CreateOp");
|
|
869
|
+
firstOp.intent = "set", firstOp.deletedId = deletedId;
|
|
560
870
|
}
|
|
561
871
|
|
|
562
872
|
class LiveMap extends AbstractCrdt {
|
|
563
873
|
constructor(entries) {
|
|
564
|
-
if (super(),
|
|
874
|
+
if (super(), errorIf(null === entries, "Support for calling `new LiveMap(null)` will be removed in @liveblocks/client 0.18. Please call as `new LiveMap()`, or `new LiveMap([])`."),
|
|
565
875
|
entries) {
|
|
566
876
|
const mappedEntries = [];
|
|
567
877
|
for (const entry of entries) {
|
|
568
|
-
const value =
|
|
878
|
+
const value = lsonToLiveNode(entry[1]);
|
|
569
879
|
value._setParentLink(this, entry[0]), mappedEntries.push([ entry[0], value ]);
|
|
570
880
|
}
|
|
571
881
|
this._map = new Map(mappedEntries);
|
|
572
882
|
} else this._map = new Map;
|
|
573
883
|
}
|
|
574
|
-
_serialize(parentId, parentKey, doc
|
|
884
|
+
_serialize(parentId, parentKey, doc) {
|
|
575
885
|
if (null == this._id) throw new Error("Cannot serialize item is not attached");
|
|
576
|
-
if (null == parentId || null == parentKey) throw new Error("Cannot serialize map if parentId or parentKey is undefined");
|
|
577
886
|
const ops = [], op = {
|
|
578
887
|
id: this._id,
|
|
579
888
|
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
580
889
|
type: OpCode.CREATE_MAP,
|
|
581
|
-
intent: intent,
|
|
582
890
|
parentId: parentId,
|
|
583
891
|
parentKey: parentKey
|
|
584
892
|
};
|
|
@@ -591,30 +899,32 @@ class LiveMap extends AbstractCrdt {
|
|
|
591
899
|
map._attach(id, doc);
|
|
592
900
|
const children = parentToChildren.get(id);
|
|
593
901
|
if (null == children) return map;
|
|
594
|
-
for (const
|
|
595
|
-
const
|
|
596
|
-
if (null == crdt.parentKey) throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
597
|
-
const child = deserialize(entry, parentToChildren, doc);
|
|
902
|
+
for (const [id, crdt] of children) {
|
|
903
|
+
const child = deserialize([ id, crdt ], parentToChildren, doc);
|
|
598
904
|
child._setParentLink(map, crdt.parentKey), map._map.set(crdt.parentKey, child);
|
|
599
905
|
}
|
|
600
906
|
return map;
|
|
601
907
|
}
|
|
602
908
|
_attach(id, doc) {
|
|
603
909
|
super._attach(id, doc);
|
|
604
|
-
for (const [_key, value] of this._map)
|
|
910
|
+
for (const [_key, value] of this._map) isLiveNode(value) && value._attach(doc.generateId(), doc);
|
|
605
911
|
}
|
|
606
|
-
_attachChild(op
|
|
912
|
+
_attachChild(op) {
|
|
607
913
|
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
608
|
-
const {id: id, parentKey:
|
|
914
|
+
const {id: id, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
609
915
|
if (void 0 !== this._doc.getItem(id)) return {
|
|
610
916
|
modified: !1
|
|
611
917
|
};
|
|
612
918
|
const previousValue = this._map.get(key);
|
|
613
919
|
let reverse;
|
|
614
|
-
|
|
920
|
+
if (previousValue) {
|
|
921
|
+
const thisId = nn(this._id);
|
|
922
|
+
reverse = previousValue._serialize(thisId, key), previousValue._detach();
|
|
923
|
+
} else reverse = [ {
|
|
615
924
|
type: OpCode.DELETE_CRDT,
|
|
616
925
|
id: id
|
|
617
|
-
} ]
|
|
926
|
+
} ];
|
|
927
|
+
return child._setParentLink(this, key), child._attach(id, this._doc), this._map.set(key, child),
|
|
618
928
|
{
|
|
619
929
|
modified: {
|
|
620
930
|
node: this,
|
|
@@ -633,7 +943,7 @@ class LiveMap extends AbstractCrdt {
|
|
|
633
943
|
for (const item of this._map.values()) item._detach();
|
|
634
944
|
}
|
|
635
945
|
_detachChild(child) {
|
|
636
|
-
const
|
|
946
|
+
const id = nn(this._id), parentKey = nn(child._parentKey), reverse = child._serialize(id, parentKey, this._doc);
|
|
637
947
|
for (const [key, value] of this._map) value === child && this._map.delete(key);
|
|
638
948
|
child._detach();
|
|
639
949
|
return {
|
|
@@ -641,7 +951,7 @@ class LiveMap extends AbstractCrdt {
|
|
|
641
951
|
node: this,
|
|
642
952
|
type: "LiveMap",
|
|
643
953
|
updates: {
|
|
644
|
-
[
|
|
954
|
+
[parentKey]: {
|
|
645
955
|
type: "delete"
|
|
646
956
|
}
|
|
647
957
|
}
|
|
@@ -650,21 +960,21 @@ class LiveMap extends AbstractCrdt {
|
|
|
650
960
|
};
|
|
651
961
|
}
|
|
652
962
|
_toSerializedCrdt() {
|
|
653
|
-
|
|
963
|
+
if ("HasParent" !== this.parent.type) throw new Error("Cannot serialize LiveMap if parent is missing");
|
|
654
964
|
return {
|
|
655
965
|
type: CrdtType.MAP,
|
|
656
|
-
parentId:
|
|
657
|
-
parentKey: this.
|
|
966
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
967
|
+
parentKey: this.parent.key
|
|
658
968
|
};
|
|
659
969
|
}
|
|
660
970
|
get(key) {
|
|
661
971
|
const value = this._map.get(key);
|
|
662
|
-
if (null != value) return
|
|
972
|
+
if (null != value) return liveNodeToLson(value);
|
|
663
973
|
}
|
|
664
974
|
set(key, value) {
|
|
665
975
|
const oldValue = this._map.get(key);
|
|
666
976
|
oldValue && oldValue._detach();
|
|
667
|
-
const item =
|
|
977
|
+
const item = lsonToLiveNode(value);
|
|
668
978
|
if (item._setParentLink(this, key), this._map.set(key, item), this._doc && this._id) {
|
|
669
979
|
const id = this._doc.generateId();
|
|
670
980
|
item._attach(id, this._doc);
|
|
@@ -693,8 +1003,8 @@ class LiveMap extends AbstractCrdt {
|
|
|
693
1003
|
const item = this._map.get(key);
|
|
694
1004
|
if (null == item) return !1;
|
|
695
1005
|
if (item._detach(), this._map.delete(key), this._doc && item._id) {
|
|
696
|
-
const storageUpdates = new Map;
|
|
697
|
-
storageUpdates.set(
|
|
1006
|
+
const thisId = nn(this._id), storageUpdates = new Map;
|
|
1007
|
+
storageUpdates.set(thisId, {
|
|
698
1008
|
node: this,
|
|
699
1009
|
type: "LiveMap",
|
|
700
1010
|
updates: {
|
|
@@ -706,14 +1016,14 @@ class LiveMap extends AbstractCrdt {
|
|
|
706
1016
|
type: OpCode.DELETE_CRDT,
|
|
707
1017
|
id: item._id,
|
|
708
1018
|
opId: this._doc.generateOpId()
|
|
709
|
-
} ], item._serialize(
|
|
1019
|
+
} ], item._serialize(thisId, key), storageUpdates);
|
|
710
1020
|
}
|
|
711
1021
|
return !0;
|
|
712
1022
|
}
|
|
713
1023
|
entries() {
|
|
714
1024
|
const innerIterator = this._map.entries();
|
|
715
1025
|
return {
|
|
716
|
-
[Symbol.iterator]
|
|
1026
|
+
[Symbol.iterator]() {
|
|
717
1027
|
return this;
|
|
718
1028
|
},
|
|
719
1029
|
next() {
|
|
@@ -723,7 +1033,7 @@ class LiveMap extends AbstractCrdt {
|
|
|
723
1033
|
value: void 0
|
|
724
1034
|
};
|
|
725
1035
|
return {
|
|
726
|
-
value: [ iteratorValue.value[0],
|
|
1036
|
+
value: [ iteratorValue.value[0], liveNodeToLson(iteratorValue.value[1]) ]
|
|
727
1037
|
};
|
|
728
1038
|
}
|
|
729
1039
|
};
|
|
@@ -737,16 +1047,17 @@ class LiveMap extends AbstractCrdt {
|
|
|
737
1047
|
values() {
|
|
738
1048
|
const innerIterator = this._map.values();
|
|
739
1049
|
return {
|
|
740
|
-
[Symbol.iterator]
|
|
1050
|
+
[Symbol.iterator]() {
|
|
741
1051
|
return this;
|
|
742
1052
|
},
|
|
743
1053
|
next() {
|
|
744
1054
|
const iteratorValue = innerIterator.next();
|
|
745
|
-
|
|
1055
|
+
if (iteratorValue.done) return {
|
|
746
1056
|
done: !0,
|
|
747
1057
|
value: void 0
|
|
748
|
-
}
|
|
749
|
-
|
|
1058
|
+
};
|
|
1059
|
+
return {
|
|
1060
|
+
value: liveNodeToLson(iteratorValue.value)
|
|
750
1061
|
};
|
|
751
1062
|
}
|
|
752
1063
|
};
|
|
@@ -756,8 +1067,12 @@ class LiveMap extends AbstractCrdt {
|
|
|
756
1067
|
}
|
|
757
1068
|
}
|
|
758
1069
|
|
|
759
|
-
function
|
|
760
|
-
|
|
1070
|
+
function isJsonArray(data) {
|
|
1071
|
+
return Array.isArray(data);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function isJsonObject(data) {
|
|
1075
|
+
return null !== data && "object" == typeof data && !isJsonArray(data);
|
|
761
1076
|
}
|
|
762
1077
|
|
|
763
1078
|
function remove(array, item) {
|
|
@@ -771,7 +1086,7 @@ function compact(items) {
|
|
|
771
1086
|
return items.filter((item => null != item));
|
|
772
1087
|
}
|
|
773
1088
|
|
|
774
|
-
function
|
|
1089
|
+
function creationOpToLiveNode(op) {
|
|
775
1090
|
switch (op.type) {
|
|
776
1091
|
case OpCode.CREATE_REGISTER:
|
|
777
1092
|
return new LiveRegister(op.data);
|
|
@@ -784,11 +1099,14 @@ function creationOpToLiveStructure(op) {
|
|
|
784
1099
|
|
|
785
1100
|
case OpCode.CREATE_LIST:
|
|
786
1101
|
return new LiveList;
|
|
1102
|
+
|
|
1103
|
+
default:
|
|
1104
|
+
return assertNever(0, "Unknown creation Op");
|
|
787
1105
|
}
|
|
788
1106
|
}
|
|
789
1107
|
|
|
790
1108
|
function isSameNodeOrChildOf(node, parent) {
|
|
791
|
-
return node === parent ||
|
|
1109
|
+
return node === parent || "HasParent" === node.parent.type && isSameNodeOrChildOf(node.parent.node, parent);
|
|
792
1110
|
}
|
|
793
1111
|
|
|
794
1112
|
function deserialize([id, crdt], parentToChildren, doc) {
|
|
@@ -810,18 +1128,28 @@ function deserialize([id, crdt], parentToChildren, doc) {
|
|
|
810
1128
|
}
|
|
811
1129
|
}
|
|
812
1130
|
|
|
813
|
-
function
|
|
814
|
-
return
|
|
1131
|
+
function isLiveNode(value) {
|
|
1132
|
+
return isLiveList(value) || function(value) {
|
|
1133
|
+
return value instanceof LiveMap;
|
|
1134
|
+
}(value) || isLiveObject(value) || function(value) {
|
|
1135
|
+
return value instanceof LiveRegister;
|
|
1136
|
+
}(value);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
function isLiveList(value) {
|
|
1140
|
+
return value instanceof LiveList;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function isLiveObject(value) {
|
|
1144
|
+
return value instanceof LiveObject;
|
|
815
1145
|
}
|
|
816
1146
|
|
|
817
|
-
function
|
|
818
|
-
return obj instanceof LiveRegister ? obj.data : obj;
|
|
1147
|
+
function liveNodeToLson(obj) {
|
|
1148
|
+
return obj instanceof LiveRegister ? obj.data : obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject ? obj : assertNever(0, "Unknown AbstractCrdt");
|
|
819
1149
|
}
|
|
820
1150
|
|
|
821
|
-
function
|
|
822
|
-
|
|
823
|
-
if (obj instanceof LiveRegister) throw new Error("Internal error. LiveRegister should not be created from selfOrRegister");
|
|
824
|
-
return new LiveRegister(obj);
|
|
1151
|
+
function lsonToLiveNode(value) {
|
|
1152
|
+
return value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList ? value : new LiveRegister(value);
|
|
825
1153
|
}
|
|
826
1154
|
|
|
827
1155
|
function getTreesDiffOperations(currentItems, newItems) {
|
|
@@ -840,7 +1168,7 @@ function getTreesDiffOperations(currentItems, newItems) {
|
|
|
840
1168
|
})), crdt.parentKey !== currentCrdt.parentKey && ops.push({
|
|
841
1169
|
type: OpCode.SET_PARENT_KEY,
|
|
842
1170
|
id: id,
|
|
843
|
-
parentKey: crdt.parentKey
|
|
1171
|
+
parentKey: nn(crdt.parentKey, "Parent key must not be missing")
|
|
844
1172
|
}); else switch (crdt.type) {
|
|
845
1173
|
case CrdtType.REGISTER:
|
|
846
1174
|
ops.push({
|
|
@@ -975,17 +1303,16 @@ class LiveObject extends AbstractCrdt {
|
|
|
975
1303
|
super(), this._propToLastUpdate = new Map;
|
|
976
1304
|
for (const key in obj) {
|
|
977
1305
|
const value = obj[key];
|
|
978
|
-
value
|
|
1306
|
+
isLiveNode(value) && value._setParentLink(this, key);
|
|
979
1307
|
}
|
|
980
1308
|
this._map = new Map(Object.entries(obj));
|
|
981
1309
|
}
|
|
982
|
-
_serialize(parentId, parentKey, doc
|
|
1310
|
+
_serialize(parentId, parentKey, doc) {
|
|
983
1311
|
if (null == this._id) throw new Error("Cannot serialize item is not attached");
|
|
984
1312
|
const opId = null == doc ? void 0 : doc.generateOpId(), ops = [], op = void 0 !== parentId && void 0 !== parentKey ? {
|
|
985
1313
|
type: OpCode.CREATE_OBJECT,
|
|
986
1314
|
id: this._id,
|
|
987
1315
|
opId: opId,
|
|
988
|
-
intent: intent,
|
|
989
1316
|
parentId: parentId,
|
|
990
1317
|
parentKey: parentKey,
|
|
991
1318
|
data: {}
|
|
@@ -993,11 +1320,10 @@ class LiveObject extends AbstractCrdt {
|
|
|
993
1320
|
type: OpCode.CREATE_OBJECT,
|
|
994
1321
|
id: this._id,
|
|
995
1322
|
opId: opId,
|
|
996
|
-
intent: intent,
|
|
997
1323
|
data: {}
|
|
998
1324
|
};
|
|
999
1325
|
ops.push(op);
|
|
1000
|
-
for (const [key, value] of this._map) value
|
|
1326
|
+
for (const [key, value] of this._map) isLiveNode(value) ? ops.push(...value._serialize(this._id, key, doc)) : op.data[key] = value;
|
|
1001
1327
|
return ops;
|
|
1002
1328
|
}
|
|
1003
1329
|
static _deserialize([id, item], parentToChildren, doc) {
|
|
@@ -1005,43 +1331,41 @@ class LiveObject extends AbstractCrdt {
|
|
|
1005
1331
|
return liveObj._attach(id, doc), this._deserializeChildren(liveObj, parentToChildren, doc);
|
|
1006
1332
|
}
|
|
1007
1333
|
static _deserializeChildren(liveObj, parentToChildren, doc) {
|
|
1008
|
-
const children = parentToChildren.get(liveObj._id);
|
|
1334
|
+
const children = parentToChildren.get(nn(liveObj._id));
|
|
1009
1335
|
if (null == children) return liveObj;
|
|
1010
|
-
for (const
|
|
1011
|
-
const
|
|
1012
|
-
if (null == crdt.parentKey) throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
1013
|
-
const child = deserialize(entry, parentToChildren, doc);
|
|
1336
|
+
for (const [id, crdt] of children) {
|
|
1337
|
+
const child = deserialize([ id, crdt ], parentToChildren, doc);
|
|
1014
1338
|
child._setParentLink(liveObj, crdt.parentKey), liveObj._map.set(crdt.parentKey, child);
|
|
1015
1339
|
}
|
|
1016
1340
|
return liveObj;
|
|
1017
1341
|
}
|
|
1018
1342
|
_attach(id, doc) {
|
|
1019
1343
|
super._attach(id, doc);
|
|
1020
|
-
for (const [_key, value] of this._map) value
|
|
1344
|
+
for (const [_key, value] of this._map) isLiveNode(value) && value._attach(doc.generateId(), doc);
|
|
1021
1345
|
}
|
|
1022
|
-
_attachChild(op,
|
|
1346
|
+
_attachChild(op, source) {
|
|
1023
1347
|
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
1024
|
-
const {id: id,
|
|
1348
|
+
const {id: id, opId: opId, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
1025
1349
|
if (void 0 !== this._doc.getItem(id)) return this._propToLastUpdate.get(key) === opId && this._propToLastUpdate.delete(key),
|
|
1026
1350
|
{
|
|
1027
1351
|
modified: !1
|
|
1028
1352
|
};
|
|
1029
|
-
if (
|
|
1353
|
+
if (source === OpSource.UNDOREDO_RECONNECT) this._propToLastUpdate.set(key, nn(opId)); else if (void 0 !== this._propToLastUpdate.get(key)) return this._propToLastUpdate.get(key) === opId ? (this._propToLastUpdate.delete(key),
|
|
1030
1354
|
{
|
|
1031
1355
|
modified: !1
|
|
1032
1356
|
}) : {
|
|
1033
1357
|
modified: !1
|
|
1034
1358
|
};
|
|
1035
|
-
const previousValue = this._map.get(key);
|
|
1359
|
+
const thisId = nn(this._id), previousValue = this._map.get(key);
|
|
1036
1360
|
let reverse;
|
|
1037
|
-
return
|
|
1361
|
+
return isLiveNode(previousValue) ? (reverse = previousValue._serialize(thisId, key),
|
|
1038
1362
|
previousValue._detach()) : reverse = void 0 === previousValue ? [ {
|
|
1039
1363
|
type: OpCode.DELETE_OBJECT_KEY,
|
|
1040
|
-
id:
|
|
1364
|
+
id: thisId,
|
|
1041
1365
|
key: key
|
|
1042
1366
|
} ] : [ {
|
|
1043
1367
|
type: OpCode.UPDATE_OBJECT,
|
|
1044
|
-
id:
|
|
1368
|
+
id: thisId,
|
|
1045
1369
|
data: {
|
|
1046
1370
|
[key]: previousValue
|
|
1047
1371
|
}
|
|
@@ -1061,7 +1385,7 @@ class LiveObject extends AbstractCrdt {
|
|
|
1061
1385
|
}
|
|
1062
1386
|
_detachChild(child) {
|
|
1063
1387
|
if (child) {
|
|
1064
|
-
const
|
|
1388
|
+
const id = nn(this._id), parentKey = nn(child._parentKey), reverse = child._serialize(id, parentKey, this._doc);
|
|
1065
1389
|
for (const [key, value] of this._map) value === child && this._map.delete(key);
|
|
1066
1390
|
child._detach();
|
|
1067
1391
|
return {
|
|
@@ -1069,7 +1393,7 @@ class LiveObject extends AbstractCrdt {
|
|
|
1069
1393
|
node: this,
|
|
1070
1394
|
type: "LiveObject",
|
|
1071
1395
|
updates: {
|
|
1072
|
-
[
|
|
1396
|
+
[parentKey]: {
|
|
1073
1397
|
type: "delete"
|
|
1074
1398
|
}
|
|
1075
1399
|
}
|
|
@@ -1081,24 +1405,20 @@ class LiveObject extends AbstractCrdt {
|
|
|
1081
1405
|
modified: !1
|
|
1082
1406
|
};
|
|
1083
1407
|
}
|
|
1084
|
-
_detachChildren() {
|
|
1085
|
-
for (const [key, value] of this._map) this._map.delete(key), value._detach();
|
|
1086
|
-
}
|
|
1087
1408
|
_detach() {
|
|
1088
1409
|
super._detach();
|
|
1089
|
-
for (const value of this._map.values())
|
|
1410
|
+
for (const value of this._map.values()) isLiveNode(value) && value._detach();
|
|
1090
1411
|
}
|
|
1091
1412
|
_apply(op, isLocal) {
|
|
1092
1413
|
return op.type === OpCode.UPDATE_OBJECT ? this._applyUpdate(op, isLocal) : op.type === OpCode.DELETE_OBJECT_KEY ? this._applyDeleteObjectKey(op) : super._apply(op, isLocal);
|
|
1093
1414
|
}
|
|
1094
1415
|
_toSerializedCrdt() {
|
|
1095
|
-
var _a;
|
|
1096
1416
|
const data = {};
|
|
1097
|
-
for (const [key, value] of this._map) value
|
|
1098
|
-
return
|
|
1417
|
+
for (const [key, value] of this._map) isLiveNode(value) || (data[key] = value);
|
|
1418
|
+
return "HasParent" === this.parent.type && this.parent.node._id ? {
|
|
1099
1419
|
type: CrdtType.OBJECT,
|
|
1100
|
-
parentId: this.
|
|
1101
|
-
parentKey: this.
|
|
1420
|
+
parentId: this.parent.node._id,
|
|
1421
|
+
parentKey: this.parent.key,
|
|
1102
1422
|
data: data
|
|
1103
1423
|
} : {
|
|
1104
1424
|
type: CrdtType.OBJECT,
|
|
@@ -1107,24 +1427,23 @@ class LiveObject extends AbstractCrdt {
|
|
|
1107
1427
|
}
|
|
1108
1428
|
_applyUpdate(op, isLocal) {
|
|
1109
1429
|
let isModified = !1;
|
|
1110
|
-
const reverse = [], reverseUpdate = {
|
|
1430
|
+
const id = nn(this._id), reverse = [], reverseUpdate = {
|
|
1111
1431
|
type: OpCode.UPDATE_OBJECT,
|
|
1112
|
-
id:
|
|
1432
|
+
id: id,
|
|
1113
1433
|
data: {}
|
|
1114
1434
|
};
|
|
1115
1435
|
reverse.push(reverseUpdate);
|
|
1116
1436
|
for (const key in op.data) {
|
|
1117
1437
|
const oldValue = this._map.get(key);
|
|
1118
|
-
oldValue
|
|
1119
|
-
oldValue._detach()) : void 0 !== oldValue ? reverseUpdate.data[key] = oldValue : void 0 === oldValue && reverse.push({
|
|
1438
|
+
isLiveNode(oldValue) ? (reverse.push(...oldValue._serialize(id, key)), oldValue._detach()) : void 0 !== oldValue ? reverseUpdate.data[key] = oldValue : void 0 === oldValue && reverse.push({
|
|
1120
1439
|
type: OpCode.DELETE_OBJECT_KEY,
|
|
1121
|
-
id:
|
|
1440
|
+
id: id,
|
|
1122
1441
|
key: key
|
|
1123
1442
|
});
|
|
1124
1443
|
}
|
|
1125
1444
|
const updateDelta = {};
|
|
1126
1445
|
for (const key in op.data) {
|
|
1127
|
-
if (isLocal) this._propToLastUpdate.set(key, op.opId); else {
|
|
1446
|
+
if (isLocal) this._propToLastUpdate.set(key, nn(op.opId)); else {
|
|
1128
1447
|
if (null != this._propToLastUpdate.get(key)) {
|
|
1129
1448
|
if (this._propToLastUpdate.get(key) === op.opId) {
|
|
1130
1449
|
this._propToLastUpdate.delete(key);
|
|
@@ -1135,7 +1454,7 @@ class LiveObject extends AbstractCrdt {
|
|
|
1135
1454
|
isModified = !0;
|
|
1136
1455
|
}
|
|
1137
1456
|
const oldValue = this._map.get(key);
|
|
1138
|
-
|
|
1457
|
+
isLiveNode(oldValue) && oldValue._detach(), isModified = !0, updateDelta[key] = {
|
|
1139
1458
|
type: "update"
|
|
1140
1459
|
}, this._map.set(key, op.data[key]);
|
|
1141
1460
|
}
|
|
@@ -1159,11 +1478,11 @@ class LiveObject extends AbstractCrdt {
|
|
|
1159
1478
|
if (void 0 !== this._propToLastUpdate.get(key)) return {
|
|
1160
1479
|
modified: !1
|
|
1161
1480
|
};
|
|
1162
|
-
const oldValue = this._map.get(key);
|
|
1481
|
+
const oldValue = this._map.get(key), id = nn(this._id);
|
|
1163
1482
|
let reverse = [];
|
|
1164
|
-
return
|
|
1483
|
+
return isLiveNode(oldValue) ? (reverse = oldValue._serialize(id, op.key), oldValue._detach()) : void 0 !== oldValue && (reverse = [ {
|
|
1165
1484
|
type: OpCode.UPDATE_OBJECT,
|
|
1166
|
-
id:
|
|
1485
|
+
id: id,
|
|
1167
1486
|
data: {
|
|
1168
1487
|
[key]: oldValue
|
|
1169
1488
|
}
|
|
@@ -1198,10 +1517,10 @@ class LiveObject extends AbstractCrdt {
|
|
|
1198
1517
|
delete(key) {
|
|
1199
1518
|
const keyAsString = key, oldValue = this._map.get(keyAsString);
|
|
1200
1519
|
if (void 0 === oldValue) return;
|
|
1201
|
-
if (null == this._doc || null == this._id) return oldValue
|
|
1520
|
+
if (null == this._doc || null == this._id) return isLiveNode(oldValue) && oldValue._detach(),
|
|
1202
1521
|
void this._map.delete(keyAsString);
|
|
1203
1522
|
let reverse;
|
|
1204
|
-
oldValue
|
|
1523
|
+
isLiveNode(oldValue) ? (oldValue._detach(), reverse = oldValue._serialize(this._id, keyAsString)) : reverse = [ {
|
|
1205
1524
|
type: OpCode.UPDATE_OBJECT,
|
|
1206
1525
|
data: {
|
|
1207
1526
|
[keyAsString]: oldValue
|
|
@@ -1228,9 +1547,9 @@ class LiveObject extends AbstractCrdt {
|
|
|
1228
1547
|
if (null == this._doc || null == this._id) {
|
|
1229
1548
|
for (const key in overrides) {
|
|
1230
1549
|
const oldValue = this._map.get(key);
|
|
1231
|
-
oldValue
|
|
1550
|
+
isLiveNode(oldValue) && oldValue._detach();
|
|
1232
1551
|
const newValue = overrides[key];
|
|
1233
|
-
newValue
|
|
1552
|
+
isLiveNode(newValue) && newValue._setParentLink(this, key), this._map.set(key, newValue);
|
|
1234
1553
|
}
|
|
1235
1554
|
return;
|
|
1236
1555
|
}
|
|
@@ -1241,17 +1560,17 @@ class LiveObject extends AbstractCrdt {
|
|
|
1241
1560
|
}, updateDelta = {};
|
|
1242
1561
|
for (const key in overrides) {
|
|
1243
1562
|
const oldValue = this._map.get(key);
|
|
1244
|
-
oldValue
|
|
1563
|
+
isLiveNode(oldValue) ? (reverseOps.push(...oldValue._serialize(this._id, key)),
|
|
1245
1564
|
oldValue._detach()) : void 0 === oldValue ? reverseOps.push({
|
|
1246
1565
|
type: OpCode.DELETE_OBJECT_KEY,
|
|
1247
1566
|
id: this._id,
|
|
1248
1567
|
key: key
|
|
1249
1568
|
}) : reverseUpdateOp.data[key] = oldValue;
|
|
1250
1569
|
const newValue = overrides[key];
|
|
1251
|
-
if (newValue
|
|
1570
|
+
if (isLiveNode(newValue)) {
|
|
1252
1571
|
newValue._setParentLink(this, key), newValue._attach(this._doc.generateId(), this._doc);
|
|
1253
1572
|
const newAttachChildOps = newValue._serialize(this._id, key, this._doc), createCrdtOp = newAttachChildOps.find((op => op.parentId === this._id));
|
|
1254
|
-
createCrdtOp && this._propToLastUpdate.set(key, createCrdtOp.opId), ops.push(...newAttachChildOps);
|
|
1573
|
+
createCrdtOp && this._propToLastUpdate.set(key, nn(createCrdtOp.opId)), ops.push(...newAttachChildOps);
|
|
1255
1574
|
} else updatedProps[key] = newValue, this._propToLastUpdate.set(key, opId);
|
|
1256
1575
|
this._map.set(key, newValue), updateDelta[key] = {
|
|
1257
1576
|
type: "update"
|
|
@@ -1273,4 +1592,4 @@ class LiveObject extends AbstractCrdt {
|
|
|
1273
1592
|
}
|
|
1274
1593
|
}
|
|
1275
1594
|
|
|
1276
|
-
export {
|
|
1595
|
+
export { makePosition as A, CrdtType as B, ClientMsgCode as C, isChildCrdt as D, LiveObject as L, OpSource as O, ServerMsgCode as S, WebsocketCloseCodes as W, isTokenValid as a, isSameNodeOrChildOf as b, OpCode as c, isLiveList as d, isJsonArray as e, compact as f, getTreesDiffOperations as g, b64decode as h, isLiveNode as i, isJsonObject as j, isRootCrdt as k, errorIf as l, mergeStorageUpdates as m, nn as n, LiveList as o, LiveMap as p, LiveRegister as q, remove as r, findNonSerializableValue as s, tryParseJson as t, isLiveObject as u, assertNever as v, deprecate as w, deprecateIf as x, throwUsageError as y, comparePosition as z };
|