@liveblocks/client 0.16.10 → 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 +14 -2
- package/index.js +32 -45
- package/index.mjs +36 -48
- package/internal.d.ts +86 -182
- package/internal.js +19 -20
- package/internal.mjs +14 -16
- package/package.json +13 -9
- package/shared.d.ts +342 -186
- package/shared.js +608 -350
- package/shared.mjs +644 -314
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,45 +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
|
-
|
|
76
|
-
} catch (e) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
183
|
+
case "NoParent":
|
|
184
|
+
this._parent = NoParent;
|
|
185
|
+
break;
|
|
80
186
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
187
|
+
case "Orphaned":
|
|
188
|
+
this._parent = Orphaned(this.parent.oldKey);
|
|
189
|
+
break;
|
|
84
190
|
|
|
85
|
-
|
|
86
|
-
|
|
191
|
+
default:
|
|
192
|
+
assertNever(this.parent, "Unknown state");
|
|
193
|
+
}
|
|
194
|
+
this.__doc = void 0;
|
|
195
|
+
}
|
|
87
196
|
}
|
|
88
197
|
|
|
89
198
|
class LiveRegister extends AbstractCrdt {
|
|
@@ -97,28 +206,27 @@ class LiveRegister extends AbstractCrdt {
|
|
|
97
206
|
const register = new LiveRegister(item.data);
|
|
98
207
|
return register._attach(id, doc), register;
|
|
99
208
|
}
|
|
100
|
-
_serialize(parentId, parentKey, doc
|
|
209
|
+
_serialize(parentId, parentKey, doc) {
|
|
101
210
|
if (null == this._id || null == parentId || null == parentKey) throw new Error("Cannot serialize register if parentId or parentKey is undefined");
|
|
102
211
|
return [ {
|
|
103
212
|
type: OpCode.CREATE_REGISTER,
|
|
104
213
|
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
105
214
|
id: this._id,
|
|
106
|
-
intent: intent,
|
|
107
215
|
parentId: parentId,
|
|
108
216
|
parentKey: parentKey,
|
|
109
217
|
data: this.data
|
|
110
218
|
} ];
|
|
111
219
|
}
|
|
112
220
|
_toSerializedCrdt() {
|
|
113
|
-
|
|
221
|
+
if ("HasParent" !== this.parent.type) throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
114
222
|
return {
|
|
115
223
|
type: CrdtType.REGISTER,
|
|
116
|
-
parentId:
|
|
117
|
-
parentKey: this.
|
|
224
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
225
|
+
parentKey: this.parent.key,
|
|
118
226
|
data: this.data
|
|
119
227
|
};
|
|
120
228
|
}
|
|
121
|
-
_attachChild(_op
|
|
229
|
+
_attachChild(_op) {
|
|
122
230
|
throw new Error("Method not implemented.");
|
|
123
231
|
}
|
|
124
232
|
_detachChild(_crdt) {
|
|
@@ -130,7 +238,7 @@ class LiveRegister extends AbstractCrdt {
|
|
|
130
238
|
}
|
|
131
239
|
|
|
132
240
|
function makePosition(before, after) {
|
|
133
|
-
return null
|
|
241
|
+
return null != before && null != after ? pos(makePositionFromCodes(posCodes(before), posCodes(after))) : null != before ? function(before) {
|
|
134
242
|
const result = [], beforeCodes = posCodes(before);
|
|
135
243
|
for (let i = 0; i < beforeCodes.length; i++) {
|
|
136
244
|
const code = beforeCodes[i];
|
|
@@ -144,7 +252,7 @@ function makePosition(before, after) {
|
|
|
144
252
|
}
|
|
145
253
|
}
|
|
146
254
|
return pos(result);
|
|
147
|
-
}(before) : null
|
|
255
|
+
}(before) : null != after ? function(after) {
|
|
148
256
|
const result = [], afterCodes = posCodes(after);
|
|
149
257
|
for (let i = 0; i < afterCodes.length; i++) {
|
|
150
258
|
const code = afterCodes[i];
|
|
@@ -158,7 +266,7 @@ function makePosition(before, after) {
|
|
|
158
266
|
}
|
|
159
267
|
}
|
|
160
268
|
return pos(result);
|
|
161
|
-
}(after) : pos(
|
|
269
|
+
}(after) : pos([ 33 ]);
|
|
162
270
|
}
|
|
163
271
|
|
|
164
272
|
function makePositionFromCodes(before, after) {
|
|
@@ -204,114 +312,243 @@ function comparePosition(posA, posB) {
|
|
|
204
312
|
class LiveList extends AbstractCrdt {
|
|
205
313
|
constructor(items = []) {
|
|
206
314
|
let position;
|
|
207
|
-
super(), this._items = [];
|
|
315
|
+
super(), this._items = [], this._implicitlyDeletedItems = new Set;
|
|
208
316
|
for (let i = 0; i < items.length; i++) {
|
|
209
|
-
const newPosition = makePosition(position), item =
|
|
210
|
-
this._items.push(
|
|
317
|
+
const newPosition = makePosition(position), item = lsonToLiveNode(items[i]);
|
|
318
|
+
item._setParentLink(this, newPosition), this._items.push(item), position = newPosition;
|
|
211
319
|
}
|
|
212
320
|
}
|
|
213
321
|
static _deserialize([id], parentToChildren, doc) {
|
|
214
|
-
const list = new LiveList
|
|
322
|
+
const list = new LiveList;
|
|
215
323
|
list._attach(id, doc);
|
|
216
324
|
const children = parentToChildren.get(id);
|
|
217
325
|
if (null == children) return list;
|
|
218
|
-
for (const
|
|
219
|
-
const child = deserialize(
|
|
220
|
-
child._setParentLink(list,
|
|
221
|
-
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);
|
|
222
329
|
}
|
|
223
330
|
return list;
|
|
224
331
|
}
|
|
225
|
-
_serialize(parentId, parentKey, doc
|
|
332
|
+
_serialize(parentId, parentKey, doc) {
|
|
226
333
|
if (null == this._id) throw new Error("Cannot serialize item is not attached");
|
|
227
|
-
if (null == parentId || null == parentKey) throw new Error("Cannot serialize list if parentId or parentKey is undefined");
|
|
228
334
|
const ops = [], op = {
|
|
229
335
|
id: this._id,
|
|
230
336
|
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
231
|
-
intent: intent,
|
|
232
337
|
type: OpCode.CREATE_LIST,
|
|
233
338
|
parentId: parentId,
|
|
234
339
|
parentKey: parentKey
|
|
235
340
|
};
|
|
236
341
|
ops.push(op);
|
|
237
|
-
for (const
|
|
342
|
+
for (const item of this._items) ops.push(...item._serialize(this._id, item._getParentKeyOrThrow(), doc));
|
|
238
343
|
return ops;
|
|
239
344
|
}
|
|
240
345
|
_indexOfPosition(position) {
|
|
241
|
-
return this._items.findIndex((item => item
|
|
346
|
+
return this._items.findIndex((item => item._getParentKeyOrThrow() === position));
|
|
242
347
|
}
|
|
243
348
|
_attach(id, doc) {
|
|
244
349
|
super._attach(id, doc);
|
|
245
|
-
for (const
|
|
350
|
+
for (const item of this._items) item._attach(doc.generateId(), doc);
|
|
246
351
|
}
|
|
247
352
|
_detach() {
|
|
248
353
|
super._detach();
|
|
249
|
-
for (const
|
|
354
|
+
for (const item of this._items) item._detach();
|
|
250
355
|
}
|
|
251
|
-
|
|
252
|
-
var _a;
|
|
356
|
+
_applyRemoteSet(op) {
|
|
253
357
|
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
254
|
-
const {id: id, parentKey:
|
|
255
|
-
if (void 0 !== this._doc.getItem(id)) return {
|
|
256
|
-
modified: !1
|
|
257
|
-
};
|
|
358
|
+
const {id: id, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
258
359
|
child._attach(id, this._doc), child._setParentLink(this, key);
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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: []
|
|
417
|
+
};
|
|
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: []
|
|
273
424
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
425
|
+
}
|
|
426
|
+
}
|
|
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);
|
|
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: []
|
|
277
461
|
};
|
|
278
462
|
}
|
|
279
|
-
if (isLocal) {
|
|
280
|
-
const before = this._items[index] ? this._items[index][1] : void 0, after = this._items[index + 1] ? this._items[index + 1][1] : void 0;
|
|
281
|
-
newKey = makePosition(before, after), child._setParentLink(this, newKey);
|
|
282
|
-
} else this._items[index][1] = makePosition(key, null === (_a = this._items[index + 1]) || void 0 === _a ? void 0 : _a[1]);
|
|
283
463
|
}
|
|
284
|
-
|
|
285
|
-
|
|
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);
|
|
286
498
|
return {
|
|
499
|
+
modified: makeUpdate(this, [ insertDelta(this._indexOfPosition(newKey), child) ]),
|
|
287
500
|
reverse: [ {
|
|
288
501
|
type: OpCode.DELETE_CRDT,
|
|
289
502
|
id: id
|
|
290
|
-
} ]
|
|
291
|
-
modified: {
|
|
292
|
-
node: this,
|
|
293
|
-
type: "LiveList",
|
|
294
|
-
updates: [ {
|
|
295
|
-
index: newIndex,
|
|
296
|
-
type: "insert",
|
|
297
|
-
item: child instanceof LiveRegister ? child.data : child
|
|
298
|
-
} ]
|
|
299
|
-
}
|
|
503
|
+
} ]
|
|
300
504
|
};
|
|
301
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
|
+
}
|
|
302
547
|
_detachChild(child) {
|
|
303
548
|
if (child) {
|
|
304
|
-
const reverse = child._serialize(this._id,
|
|
305
|
-
this._items.splice(indexToDelete, 1), child._detach()
|
|
306
|
-
|
|
307
|
-
modified: {
|
|
308
|
-
node: this,
|
|
309
|
-
type: "LiveList",
|
|
310
|
-
updates: [ {
|
|
311
|
-
index: indexToDelete,
|
|
312
|
-
type: "delete"
|
|
313
|
-
} ]
|
|
314
|
-
},
|
|
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) ]),
|
|
315
552
|
reverse: reverse
|
|
316
553
|
};
|
|
317
554
|
}
|
|
@@ -319,41 +556,100 @@ class LiveList extends AbstractCrdt {
|
|
|
319
556
|
modified: !1
|
|
320
557
|
};
|
|
321
558
|
}
|
|
322
|
-
|
|
559
|
+
_applySetChildKeyRemote(newKey, child) {
|
|
323
560
|
var _a;
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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) ]),
|
|
341
634
|
reverse: [ {
|
|
342
635
|
type: OpCode.SET_PARENT_KEY,
|
|
343
|
-
id:
|
|
636
|
+
id: nn(child._id),
|
|
344
637
|
parentKey: previousKey
|
|
345
638
|
} ]
|
|
346
639
|
};
|
|
347
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
|
+
}
|
|
348
644
|
_apply(op, isLocal) {
|
|
349
645
|
return super._apply(op, isLocal);
|
|
350
646
|
}
|
|
351
647
|
_toSerializedCrdt() {
|
|
352
|
-
|
|
648
|
+
if ("HasParent" !== this.parent.type) throw new Error("Cannot serialize LiveList if parent is missing");
|
|
353
649
|
return {
|
|
354
650
|
type: CrdtType.LIST,
|
|
355
|
-
parentId:
|
|
356
|
-
parentKey: this.
|
|
651
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
652
|
+
parentKey: this.parent.key
|
|
357
653
|
};
|
|
358
654
|
}
|
|
359
655
|
get length() {
|
|
@@ -364,25 +660,14 @@ class LiveList extends AbstractCrdt {
|
|
|
364
660
|
}
|
|
365
661
|
insert(element, index) {
|
|
366
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}`);
|
|
367
|
-
const position = makePosition(this._items[index - 1] ? this._items[index - 1]
|
|
368
|
-
value._setParentLink(this, position), this._items.push(
|
|
369
|
-
|
|
370
|
-
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) {
|
|
371
666
|
const id = this._doc.generateId();
|
|
372
|
-
value._attach(id, this._doc)
|
|
373
|
-
const storageUpdates = new Map;
|
|
374
|
-
storageUpdates.set(this._id, {
|
|
375
|
-
node: this,
|
|
376
|
-
type: "LiveList",
|
|
377
|
-
updates: [ {
|
|
378
|
-
index: newIndex,
|
|
379
|
-
item: value instanceof LiveRegister ? value.data : value,
|
|
380
|
-
type: "insert"
|
|
381
|
-
} ]
|
|
382
|
-
}), 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), [ {
|
|
383
668
|
type: OpCode.DELETE_CRDT,
|
|
384
669
|
id: id
|
|
385
|
-
} ],
|
|
670
|
+
} ], new Map([ [ this._id, makeUpdate(this, [ insertDelta(index, value) ]) ] ]));
|
|
386
671
|
}
|
|
387
672
|
}
|
|
388
673
|
move(index, targetIndex) {
|
|
@@ -391,31 +676,20 @@ class LiveList extends AbstractCrdt {
|
|
|
391
676
|
if (index < 0) throw new Error("index cannot be less than 0");
|
|
392
677
|
if (index >= this._items.length) throw new Error("index cannot be greater or equal than the list length");
|
|
393
678
|
let beforePosition = null, afterPosition = null;
|
|
394
|
-
index < targetIndex ? (afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1]
|
|
395
|
-
beforePosition = this._items[targetIndex]
|
|
396
|
-
beforePosition = 0 === targetIndex ? void 0 : this._items[targetIndex - 1]
|
|
397
|
-
const position = makePosition(beforePosition, afterPosition), item = this._items[index], previousPosition = item
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const storageUpdates = new Map;
|
|
402
|
-
storageUpdates.set(this._id, {
|
|
403
|
-
node: this,
|
|
404
|
-
type: "LiveList",
|
|
405
|
-
updates: [ {
|
|
406
|
-
index: newIndex,
|
|
407
|
-
previousIndex: index,
|
|
408
|
-
item: item[0],
|
|
409
|
-
type: "move"
|
|
410
|
-
} ]
|
|
411
|
-
}), 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([ {
|
|
412
686
|
type: OpCode.SET_PARENT_KEY,
|
|
413
|
-
id: item
|
|
687
|
+
id: nn(item._id),
|
|
414
688
|
opId: this._doc.generateOpId(),
|
|
415
689
|
parentKey: position
|
|
416
690
|
} ], [ {
|
|
417
691
|
type: OpCode.SET_PARENT_KEY,
|
|
418
|
-
id: item
|
|
692
|
+
id: nn(item._id),
|
|
419
693
|
parentKey: previousPosition
|
|
420
694
|
} ], storageUpdates);
|
|
421
695
|
}
|
|
@@ -423,22 +697,15 @@ class LiveList extends AbstractCrdt {
|
|
|
423
697
|
delete(index) {
|
|
424
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}`);
|
|
425
699
|
const item = this._items[index];
|
|
426
|
-
if (item
|
|
427
|
-
const childRecordId = item
|
|
700
|
+
if (item._detach(), this._items.splice(index, 1), this._doc) {
|
|
701
|
+
const childRecordId = item._id;
|
|
428
702
|
if (childRecordId) {
|
|
429
703
|
const storageUpdates = new Map;
|
|
430
|
-
storageUpdates.set(this._id, {
|
|
431
|
-
node: this,
|
|
432
|
-
type: "LiveList",
|
|
433
|
-
updates: [ {
|
|
434
|
-
index: index,
|
|
435
|
-
type: "delete"
|
|
436
|
-
} ]
|
|
437
|
-
}), this._doc.dispatch([ {
|
|
704
|
+
storageUpdates.set(nn(this._id), makeUpdate(this, [ deleteDelta(index) ])), this._doc.dispatch([ {
|
|
438
705
|
id: childRecordId,
|
|
439
706
|
opId: this._doc.generateOpId(),
|
|
440
707
|
type: OpCode.DELETE_CRDT
|
|
441
|
-
} ], item
|
|
708
|
+
} ], item._serialize(nn(this._id), item._getParentKeyOrThrow()), storageUpdates);
|
|
442
709
|
}
|
|
443
710
|
}
|
|
444
711
|
}
|
|
@@ -447,50 +714,41 @@ class LiveList extends AbstractCrdt {
|
|
|
447
714
|
const ops = [], reverseOps = [], updateDelta = [];
|
|
448
715
|
let i = 0;
|
|
449
716
|
for (const item of this._items) {
|
|
450
|
-
item
|
|
451
|
-
const childId = item
|
|
717
|
+
item._detach();
|
|
718
|
+
const childId = item._id;
|
|
452
719
|
childId && (ops.push({
|
|
720
|
+
type: OpCode.DELETE_CRDT,
|
|
453
721
|
id: childId,
|
|
454
|
-
|
|
455
|
-
}), reverseOps.push(...item
|
|
456
|
-
|
|
457
|
-
type: "delete"
|
|
458
|
-
})), i++;
|
|
722
|
+
opId: this._doc.generateOpId()
|
|
723
|
+
}), reverseOps.push(...item._serialize(nn(this._id), item._getParentKeyOrThrow())),
|
|
724
|
+
updateDelta.push(deleteDelta(i))), i++;
|
|
459
725
|
}
|
|
460
726
|
this._items = [];
|
|
461
727
|
const storageUpdates = new Map;
|
|
462
|
-
storageUpdates.set(this._id,
|
|
463
|
-
node: this,
|
|
464
|
-
type: "LiveList",
|
|
465
|
-
updates: updateDelta
|
|
466
|
-
}), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
728
|
+
storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta)), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
467
729
|
} else {
|
|
468
|
-
for (const item of this._items) item
|
|
730
|
+
for (const item of this._items) item._detach();
|
|
469
731
|
this._items = [];
|
|
470
732
|
}
|
|
471
733
|
}
|
|
472
734
|
set(index, item) {
|
|
473
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}`);
|
|
474
|
-
const
|
|
736
|
+
const existingItem = this._items[index], position = existingItem._getParentKeyOrThrow(), existingId = existingItem._id;
|
|
475
737
|
existingItem._detach();
|
|
476
|
-
const value =
|
|
477
|
-
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) {
|
|
478
740
|
const id = this._doc.generateId();
|
|
479
741
|
value._attach(id, this._doc);
|
|
480
742
|
const storageUpdates = new Map;
|
|
481
|
-
storageUpdates.set(this._id,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
item: value instanceof LiveRegister ? value.data : value,
|
|
487
|
-
type: "set"
|
|
488
|
-
} ]
|
|
489
|
-
}), 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);
|
|
490
748
|
}
|
|
491
749
|
}
|
|
492
750
|
toArray() {
|
|
493
|
-
return this._items.map((entry =>
|
|
751
|
+
return this._items.map((entry => liveNodeToLson(entry)));
|
|
494
752
|
}
|
|
495
753
|
every(predicate) {
|
|
496
754
|
return this.toArray().every(predicate);
|
|
@@ -508,7 +766,7 @@ class LiveList extends AbstractCrdt {
|
|
|
508
766
|
return this.toArray().forEach(callbackfn);
|
|
509
767
|
}
|
|
510
768
|
get(index) {
|
|
511
|
-
if (!(index < 0 || index >= this._items.length)) return
|
|
769
|
+
if (!(index < 0 || index >= this._items.length)) return liveNodeToLson(this._items[index]);
|
|
512
770
|
}
|
|
513
771
|
indexOf(searchElement, fromIndex) {
|
|
514
772
|
return this.toArray().indexOf(searchElement, fromIndex);
|
|
@@ -517,7 +775,7 @@ class LiveList extends AbstractCrdt {
|
|
|
517
775
|
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
518
776
|
}
|
|
519
777
|
map(callback) {
|
|
520
|
-
return this._items.map(((entry, i) => callback(
|
|
778
|
+
return this._items.map(((entry, i) => callback(liveNodeToLson(entry), i)));
|
|
521
779
|
}
|
|
522
780
|
some(predicate) {
|
|
523
781
|
return this.toArray().some(predicate);
|
|
@@ -525,6 +783,20 @@ class LiveList extends AbstractCrdt {
|
|
|
525
783
|
[Symbol.iterator]() {
|
|
526
784
|
return new LiveListIterator(this._items);
|
|
527
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
|
+
}
|
|
528
800
|
}
|
|
529
801
|
|
|
530
802
|
class LiveListIterator {
|
|
@@ -536,57 +808,85 @@ class LiveListIterator {
|
|
|
536
808
|
}
|
|
537
809
|
next() {
|
|
538
810
|
const result = this._innerIterator.next();
|
|
539
|
-
|
|
811
|
+
if (result.done) return {
|
|
540
812
|
done: !0,
|
|
541
813
|
value: void 0
|
|
542
|
-
}
|
|
543
|
-
|
|
814
|
+
};
|
|
815
|
+
return {
|
|
816
|
+
value: liveNodeToLson(result.value)
|
|
544
817
|
};
|
|
545
818
|
}
|
|
546
819
|
}
|
|
547
820
|
|
|
548
|
-
|
|
821
|
+
function makeUpdate(liveList, deltaUpdates) {
|
|
822
|
+
return {
|
|
823
|
+
node: liveList,
|
|
824
|
+
type: "LiveList",
|
|
825
|
+
updates: deltaUpdates
|
|
826
|
+
};
|
|
827
|
+
}
|
|
549
828
|
|
|
550
|
-
function
|
|
551
|
-
|
|
552
|
-
|
|
829
|
+
function setDelta(index, item) {
|
|
830
|
+
return {
|
|
831
|
+
index: index,
|
|
832
|
+
type: "set",
|
|
833
|
+
item: item instanceof LiveRegister ? item.data : item
|
|
834
|
+
};
|
|
553
835
|
}
|
|
554
836
|
|
|
555
|
-
function
|
|
556
|
-
|
|
837
|
+
function deleteDelta(index) {
|
|
838
|
+
return {
|
|
839
|
+
index: index,
|
|
840
|
+
type: "delete"
|
|
841
|
+
};
|
|
557
842
|
}
|
|
558
843
|
|
|
559
|
-
function
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
844
|
+
function insertDelta(index, item) {
|
|
845
|
+
return {
|
|
846
|
+
index: index,
|
|
847
|
+
type: "insert",
|
|
848
|
+
item: item instanceof LiveRegister ? item.data : item
|
|
849
|
+
};
|
|
564
850
|
}
|
|
565
851
|
|
|
566
|
-
function
|
|
567
|
-
|
|
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;
|
|
568
870
|
}
|
|
569
871
|
|
|
570
872
|
class LiveMap extends AbstractCrdt {
|
|
571
873
|
constructor(entries) {
|
|
572
|
-
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([])`."),
|
|
573
875
|
entries) {
|
|
574
876
|
const mappedEntries = [];
|
|
575
877
|
for (const entry of entries) {
|
|
576
|
-
const value =
|
|
878
|
+
const value = lsonToLiveNode(entry[1]);
|
|
577
879
|
value._setParentLink(this, entry[0]), mappedEntries.push([ entry[0], value ]);
|
|
578
880
|
}
|
|
579
881
|
this._map = new Map(mappedEntries);
|
|
580
882
|
} else this._map = new Map;
|
|
581
883
|
}
|
|
582
|
-
_serialize(parentId, parentKey, doc
|
|
884
|
+
_serialize(parentId, parentKey, doc) {
|
|
583
885
|
if (null == this._id) throw new Error("Cannot serialize item is not attached");
|
|
584
|
-
if (null == parentId || null == parentKey) throw new Error("Cannot serialize map if parentId or parentKey is undefined");
|
|
585
886
|
const ops = [], op = {
|
|
586
887
|
id: this._id,
|
|
587
888
|
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
588
889
|
type: OpCode.CREATE_MAP,
|
|
589
|
-
intent: intent,
|
|
590
890
|
parentId: parentId,
|
|
591
891
|
parentKey: parentKey
|
|
592
892
|
};
|
|
@@ -599,30 +899,32 @@ class LiveMap extends AbstractCrdt {
|
|
|
599
899
|
map._attach(id, doc);
|
|
600
900
|
const children = parentToChildren.get(id);
|
|
601
901
|
if (null == children) return map;
|
|
602
|
-
for (const
|
|
603
|
-
const
|
|
604
|
-
if (null == crdt.parentKey) throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
605
|
-
const child = deserialize(entry, parentToChildren, doc);
|
|
902
|
+
for (const [id, crdt] of children) {
|
|
903
|
+
const child = deserialize([ id, crdt ], parentToChildren, doc);
|
|
606
904
|
child._setParentLink(map, crdt.parentKey), map._map.set(crdt.parentKey, child);
|
|
607
905
|
}
|
|
608
906
|
return map;
|
|
609
907
|
}
|
|
610
908
|
_attach(id, doc) {
|
|
611
909
|
super._attach(id, doc);
|
|
612
|
-
for (const [_key, value] of this._map)
|
|
910
|
+
for (const [_key, value] of this._map) isLiveNode(value) && value._attach(doc.generateId(), doc);
|
|
613
911
|
}
|
|
614
|
-
_attachChild(op
|
|
912
|
+
_attachChild(op) {
|
|
615
913
|
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
616
|
-
const {id: id, parentKey:
|
|
914
|
+
const {id: id, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
617
915
|
if (void 0 !== this._doc.getItem(id)) return {
|
|
618
916
|
modified: !1
|
|
619
917
|
};
|
|
620
918
|
const previousValue = this._map.get(key);
|
|
621
919
|
let reverse;
|
|
622
|
-
|
|
920
|
+
if (previousValue) {
|
|
921
|
+
const thisId = nn(this._id);
|
|
922
|
+
reverse = previousValue._serialize(thisId, key), previousValue._detach();
|
|
923
|
+
} else reverse = [ {
|
|
623
924
|
type: OpCode.DELETE_CRDT,
|
|
624
925
|
id: id
|
|
625
|
-
} ]
|
|
926
|
+
} ];
|
|
927
|
+
return child._setParentLink(this, key), child._attach(id, this._doc), this._map.set(key, child),
|
|
626
928
|
{
|
|
627
929
|
modified: {
|
|
628
930
|
node: this,
|
|
@@ -641,7 +943,7 @@ class LiveMap extends AbstractCrdt {
|
|
|
641
943
|
for (const item of this._map.values()) item._detach();
|
|
642
944
|
}
|
|
643
945
|
_detachChild(child) {
|
|
644
|
-
const
|
|
946
|
+
const id = nn(this._id), parentKey = nn(child._parentKey), reverse = child._serialize(id, parentKey, this._doc);
|
|
645
947
|
for (const [key, value] of this._map) value === child && this._map.delete(key);
|
|
646
948
|
child._detach();
|
|
647
949
|
return {
|
|
@@ -649,7 +951,7 @@ class LiveMap extends AbstractCrdt {
|
|
|
649
951
|
node: this,
|
|
650
952
|
type: "LiveMap",
|
|
651
953
|
updates: {
|
|
652
|
-
[
|
|
954
|
+
[parentKey]: {
|
|
653
955
|
type: "delete"
|
|
654
956
|
}
|
|
655
957
|
}
|
|
@@ -658,21 +960,21 @@ class LiveMap extends AbstractCrdt {
|
|
|
658
960
|
};
|
|
659
961
|
}
|
|
660
962
|
_toSerializedCrdt() {
|
|
661
|
-
|
|
963
|
+
if ("HasParent" !== this.parent.type) throw new Error("Cannot serialize LiveMap if parent is missing");
|
|
662
964
|
return {
|
|
663
965
|
type: CrdtType.MAP,
|
|
664
|
-
parentId:
|
|
665
|
-
parentKey: this.
|
|
966
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
967
|
+
parentKey: this.parent.key
|
|
666
968
|
};
|
|
667
969
|
}
|
|
668
970
|
get(key) {
|
|
669
971
|
const value = this._map.get(key);
|
|
670
|
-
if (null != value) return
|
|
972
|
+
if (null != value) return liveNodeToLson(value);
|
|
671
973
|
}
|
|
672
974
|
set(key, value) {
|
|
673
975
|
const oldValue = this._map.get(key);
|
|
674
976
|
oldValue && oldValue._detach();
|
|
675
|
-
const item =
|
|
977
|
+
const item = lsonToLiveNode(value);
|
|
676
978
|
if (item._setParentLink(this, key), this._map.set(key, item), this._doc && this._id) {
|
|
677
979
|
const id = this._doc.generateId();
|
|
678
980
|
item._attach(id, this._doc);
|
|
@@ -701,8 +1003,8 @@ class LiveMap extends AbstractCrdt {
|
|
|
701
1003
|
const item = this._map.get(key);
|
|
702
1004
|
if (null == item) return !1;
|
|
703
1005
|
if (item._detach(), this._map.delete(key), this._doc && item._id) {
|
|
704
|
-
const storageUpdates = new Map;
|
|
705
|
-
storageUpdates.set(
|
|
1006
|
+
const thisId = nn(this._id), storageUpdates = new Map;
|
|
1007
|
+
storageUpdates.set(thisId, {
|
|
706
1008
|
node: this,
|
|
707
1009
|
type: "LiveMap",
|
|
708
1010
|
updates: {
|
|
@@ -714,14 +1016,14 @@ class LiveMap extends AbstractCrdt {
|
|
|
714
1016
|
type: OpCode.DELETE_CRDT,
|
|
715
1017
|
id: item._id,
|
|
716
1018
|
opId: this._doc.generateOpId()
|
|
717
|
-
} ], item._serialize(
|
|
1019
|
+
} ], item._serialize(thisId, key), storageUpdates);
|
|
718
1020
|
}
|
|
719
1021
|
return !0;
|
|
720
1022
|
}
|
|
721
1023
|
entries() {
|
|
722
1024
|
const innerIterator = this._map.entries();
|
|
723
1025
|
return {
|
|
724
|
-
[Symbol.iterator]
|
|
1026
|
+
[Symbol.iterator]() {
|
|
725
1027
|
return this;
|
|
726
1028
|
},
|
|
727
1029
|
next() {
|
|
@@ -731,7 +1033,7 @@ class LiveMap extends AbstractCrdt {
|
|
|
731
1033
|
value: void 0
|
|
732
1034
|
};
|
|
733
1035
|
return {
|
|
734
|
-
value: [ iteratorValue.value[0],
|
|
1036
|
+
value: [ iteratorValue.value[0], liveNodeToLson(iteratorValue.value[1]) ]
|
|
735
1037
|
};
|
|
736
1038
|
}
|
|
737
1039
|
};
|
|
@@ -745,16 +1047,17 @@ class LiveMap extends AbstractCrdt {
|
|
|
745
1047
|
values() {
|
|
746
1048
|
const innerIterator = this._map.values();
|
|
747
1049
|
return {
|
|
748
|
-
[Symbol.iterator]
|
|
1050
|
+
[Symbol.iterator]() {
|
|
749
1051
|
return this;
|
|
750
1052
|
},
|
|
751
1053
|
next() {
|
|
752
1054
|
const iteratorValue = innerIterator.next();
|
|
753
|
-
|
|
1055
|
+
if (iteratorValue.done) return {
|
|
754
1056
|
done: !0,
|
|
755
1057
|
value: void 0
|
|
756
|
-
}
|
|
757
|
-
|
|
1058
|
+
};
|
|
1059
|
+
return {
|
|
1060
|
+
value: liveNodeToLson(iteratorValue.value)
|
|
758
1061
|
};
|
|
759
1062
|
}
|
|
760
1063
|
};
|
|
@@ -764,8 +1067,12 @@ class LiveMap extends AbstractCrdt {
|
|
|
764
1067
|
}
|
|
765
1068
|
}
|
|
766
1069
|
|
|
767
|
-
function
|
|
768
|
-
|
|
1070
|
+
function isJsonArray(data) {
|
|
1071
|
+
return Array.isArray(data);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function isJsonObject(data) {
|
|
1075
|
+
return null !== data && "object" == typeof data && !isJsonArray(data);
|
|
769
1076
|
}
|
|
770
1077
|
|
|
771
1078
|
function remove(array, item) {
|
|
@@ -779,7 +1086,7 @@ function compact(items) {
|
|
|
779
1086
|
return items.filter((item => null != item));
|
|
780
1087
|
}
|
|
781
1088
|
|
|
782
|
-
function
|
|
1089
|
+
function creationOpToLiveNode(op) {
|
|
783
1090
|
switch (op.type) {
|
|
784
1091
|
case OpCode.CREATE_REGISTER:
|
|
785
1092
|
return new LiveRegister(op.data);
|
|
@@ -792,11 +1099,14 @@ function creationOpToLiveStructure(op) {
|
|
|
792
1099
|
|
|
793
1100
|
case OpCode.CREATE_LIST:
|
|
794
1101
|
return new LiveList;
|
|
1102
|
+
|
|
1103
|
+
default:
|
|
1104
|
+
return assertNever(0, "Unknown creation Op");
|
|
795
1105
|
}
|
|
796
1106
|
}
|
|
797
1107
|
|
|
798
1108
|
function isSameNodeOrChildOf(node, parent) {
|
|
799
|
-
return node === parent ||
|
|
1109
|
+
return node === parent || "HasParent" === node.parent.type && isSameNodeOrChildOf(node.parent.node, parent);
|
|
800
1110
|
}
|
|
801
1111
|
|
|
802
1112
|
function deserialize([id, crdt], parentToChildren, doc) {
|
|
@@ -818,18 +1128,28 @@ function deserialize([id, crdt], parentToChildren, doc) {
|
|
|
818
1128
|
}
|
|
819
1129
|
}
|
|
820
1130
|
|
|
821
|
-
function
|
|
822
|
-
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;
|
|
823
1141
|
}
|
|
824
1142
|
|
|
825
|
-
function
|
|
826
|
-
return
|
|
1143
|
+
function isLiveObject(value) {
|
|
1144
|
+
return value instanceof LiveObject;
|
|
827
1145
|
}
|
|
828
1146
|
|
|
829
|
-
function
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
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");
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
function lsonToLiveNode(value) {
|
|
1152
|
+
return value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList ? value : new LiveRegister(value);
|
|
833
1153
|
}
|
|
834
1154
|
|
|
835
1155
|
function getTreesDiffOperations(currentItems, newItems) {
|
|
@@ -848,7 +1168,7 @@ function getTreesDiffOperations(currentItems, newItems) {
|
|
|
848
1168
|
})), crdt.parentKey !== currentCrdt.parentKey && ops.push({
|
|
849
1169
|
type: OpCode.SET_PARENT_KEY,
|
|
850
1170
|
id: id,
|
|
851
|
-
parentKey: crdt.parentKey
|
|
1171
|
+
parentKey: nn(crdt.parentKey, "Parent key must not be missing")
|
|
852
1172
|
}); else switch (crdt.type) {
|
|
853
1173
|
case CrdtType.REGISTER:
|
|
854
1174
|
ops.push({
|
|
@@ -950,7 +1270,7 @@ function findNonSerializableValue(value, path = "") {
|
|
|
950
1270
|
function isTokenValid(token) {
|
|
951
1271
|
const tokenParts = token.split(".");
|
|
952
1272
|
if (3 !== tokenParts.length) return !1;
|
|
953
|
-
const data =
|
|
1273
|
+
const data = tryParseJson(atob(tokenParts[1]));
|
|
954
1274
|
if (void 0 === data || !isJsonObject(data) || "number" != typeof data.exp) return !1;
|
|
955
1275
|
return !(Date.now() / 1e3 > data.exp - 300);
|
|
956
1276
|
}
|
|
@@ -959,22 +1279,40 @@ function entries(obj) {
|
|
|
959
1279
|
return Object.entries(obj);
|
|
960
1280
|
}
|
|
961
1281
|
|
|
1282
|
+
function tryParseJson(rawMessage) {
|
|
1283
|
+
try {
|
|
1284
|
+
return JSON.parse(rawMessage);
|
|
1285
|
+
} catch (e) {
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
function b64decode(b64value) {
|
|
1291
|
+
try {
|
|
1292
|
+
const formattedValue = b64value.replace(/-/g, "+").replace(/_/g, "/");
|
|
1293
|
+
return decodeURIComponent(atob(formattedValue).split("").map((function(c) {
|
|
1294
|
+
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
|
1295
|
+
})).join(""));
|
|
1296
|
+
} catch (err) {
|
|
1297
|
+
return atob(b64value);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
962
1301
|
class LiveObject extends AbstractCrdt {
|
|
963
1302
|
constructor(obj = {}) {
|
|
964
1303
|
super(), this._propToLastUpdate = new Map;
|
|
965
1304
|
for (const key in obj) {
|
|
966
1305
|
const value = obj[key];
|
|
967
|
-
value
|
|
1306
|
+
isLiveNode(value) && value._setParentLink(this, key);
|
|
968
1307
|
}
|
|
969
1308
|
this._map = new Map(Object.entries(obj));
|
|
970
1309
|
}
|
|
971
|
-
_serialize(parentId, parentKey, doc
|
|
1310
|
+
_serialize(parentId, parentKey, doc) {
|
|
972
1311
|
if (null == this._id) throw new Error("Cannot serialize item is not attached");
|
|
973
1312
|
const opId = null == doc ? void 0 : doc.generateOpId(), ops = [], op = void 0 !== parentId && void 0 !== parentKey ? {
|
|
974
1313
|
type: OpCode.CREATE_OBJECT,
|
|
975
1314
|
id: this._id,
|
|
976
1315
|
opId: opId,
|
|
977
|
-
intent: intent,
|
|
978
1316
|
parentId: parentId,
|
|
979
1317
|
parentKey: parentKey,
|
|
980
1318
|
data: {}
|
|
@@ -982,11 +1320,10 @@ class LiveObject extends AbstractCrdt {
|
|
|
982
1320
|
type: OpCode.CREATE_OBJECT,
|
|
983
1321
|
id: this._id,
|
|
984
1322
|
opId: opId,
|
|
985
|
-
intent: intent,
|
|
986
1323
|
data: {}
|
|
987
1324
|
};
|
|
988
1325
|
ops.push(op);
|
|
989
|
-
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;
|
|
990
1327
|
return ops;
|
|
991
1328
|
}
|
|
992
1329
|
static _deserialize([id, item], parentToChildren, doc) {
|
|
@@ -994,43 +1331,41 @@ class LiveObject extends AbstractCrdt {
|
|
|
994
1331
|
return liveObj._attach(id, doc), this._deserializeChildren(liveObj, parentToChildren, doc);
|
|
995
1332
|
}
|
|
996
1333
|
static _deserializeChildren(liveObj, parentToChildren, doc) {
|
|
997
|
-
const children = parentToChildren.get(liveObj._id);
|
|
1334
|
+
const children = parentToChildren.get(nn(liveObj._id));
|
|
998
1335
|
if (null == children) return liveObj;
|
|
999
|
-
for (const
|
|
1000
|
-
const
|
|
1001
|
-
if (null == crdt.parentKey) throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
1002
|
-
const child = deserialize(entry, parentToChildren, doc);
|
|
1336
|
+
for (const [id, crdt] of children) {
|
|
1337
|
+
const child = deserialize([ id, crdt ], parentToChildren, doc);
|
|
1003
1338
|
child._setParentLink(liveObj, crdt.parentKey), liveObj._map.set(crdt.parentKey, child);
|
|
1004
1339
|
}
|
|
1005
1340
|
return liveObj;
|
|
1006
1341
|
}
|
|
1007
1342
|
_attach(id, doc) {
|
|
1008
1343
|
super._attach(id, doc);
|
|
1009
|
-
for (const [_key, value] of this._map) value
|
|
1344
|
+
for (const [_key, value] of this._map) isLiveNode(value) && value._attach(doc.generateId(), doc);
|
|
1010
1345
|
}
|
|
1011
|
-
_attachChild(op,
|
|
1346
|
+
_attachChild(op, source) {
|
|
1012
1347
|
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
1013
|
-
const {id: id,
|
|
1348
|
+
const {id: id, opId: opId, parentKey: key} = op, child = creationOpToLiveNode(op);
|
|
1014
1349
|
if (void 0 !== this._doc.getItem(id)) return this._propToLastUpdate.get(key) === opId && this._propToLastUpdate.delete(key),
|
|
1015
1350
|
{
|
|
1016
1351
|
modified: !1
|
|
1017
1352
|
};
|
|
1018
|
-
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),
|
|
1019
1354
|
{
|
|
1020
1355
|
modified: !1
|
|
1021
1356
|
}) : {
|
|
1022
1357
|
modified: !1
|
|
1023
1358
|
};
|
|
1024
|
-
const previousValue = this._map.get(key);
|
|
1359
|
+
const thisId = nn(this._id), previousValue = this._map.get(key);
|
|
1025
1360
|
let reverse;
|
|
1026
|
-
return
|
|
1361
|
+
return isLiveNode(previousValue) ? (reverse = previousValue._serialize(thisId, key),
|
|
1027
1362
|
previousValue._detach()) : reverse = void 0 === previousValue ? [ {
|
|
1028
1363
|
type: OpCode.DELETE_OBJECT_KEY,
|
|
1029
|
-
id:
|
|
1364
|
+
id: thisId,
|
|
1030
1365
|
key: key
|
|
1031
1366
|
} ] : [ {
|
|
1032
1367
|
type: OpCode.UPDATE_OBJECT,
|
|
1033
|
-
id:
|
|
1368
|
+
id: thisId,
|
|
1034
1369
|
data: {
|
|
1035
1370
|
[key]: previousValue
|
|
1036
1371
|
}
|
|
@@ -1050,7 +1385,7 @@ class LiveObject extends AbstractCrdt {
|
|
|
1050
1385
|
}
|
|
1051
1386
|
_detachChild(child) {
|
|
1052
1387
|
if (child) {
|
|
1053
|
-
const
|
|
1388
|
+
const id = nn(this._id), parentKey = nn(child._parentKey), reverse = child._serialize(id, parentKey, this._doc);
|
|
1054
1389
|
for (const [key, value] of this._map) value === child && this._map.delete(key);
|
|
1055
1390
|
child._detach();
|
|
1056
1391
|
return {
|
|
@@ -1058,7 +1393,7 @@ class LiveObject extends AbstractCrdt {
|
|
|
1058
1393
|
node: this,
|
|
1059
1394
|
type: "LiveObject",
|
|
1060
1395
|
updates: {
|
|
1061
|
-
[
|
|
1396
|
+
[parentKey]: {
|
|
1062
1397
|
type: "delete"
|
|
1063
1398
|
}
|
|
1064
1399
|
}
|
|
@@ -1070,24 +1405,20 @@ class LiveObject extends AbstractCrdt {
|
|
|
1070
1405
|
modified: !1
|
|
1071
1406
|
};
|
|
1072
1407
|
}
|
|
1073
|
-
_detachChildren() {
|
|
1074
|
-
for (const [key, value] of this._map) this._map.delete(key), value._detach();
|
|
1075
|
-
}
|
|
1076
1408
|
_detach() {
|
|
1077
1409
|
super._detach();
|
|
1078
|
-
for (const value of this._map.values())
|
|
1410
|
+
for (const value of this._map.values()) isLiveNode(value) && value._detach();
|
|
1079
1411
|
}
|
|
1080
1412
|
_apply(op, isLocal) {
|
|
1081
1413
|
return op.type === OpCode.UPDATE_OBJECT ? this._applyUpdate(op, isLocal) : op.type === OpCode.DELETE_OBJECT_KEY ? this._applyDeleteObjectKey(op) : super._apply(op, isLocal);
|
|
1082
1414
|
}
|
|
1083
1415
|
_toSerializedCrdt() {
|
|
1084
|
-
var _a;
|
|
1085
1416
|
const data = {};
|
|
1086
|
-
for (const [key, value] of this._map) value
|
|
1087
|
-
return
|
|
1417
|
+
for (const [key, value] of this._map) isLiveNode(value) || (data[key] = value);
|
|
1418
|
+
return "HasParent" === this.parent.type && this.parent.node._id ? {
|
|
1088
1419
|
type: CrdtType.OBJECT,
|
|
1089
|
-
parentId: this.
|
|
1090
|
-
parentKey: this.
|
|
1420
|
+
parentId: this.parent.node._id,
|
|
1421
|
+
parentKey: this.parent.key,
|
|
1091
1422
|
data: data
|
|
1092
1423
|
} : {
|
|
1093
1424
|
type: CrdtType.OBJECT,
|
|
@@ -1096,24 +1427,23 @@ class LiveObject extends AbstractCrdt {
|
|
|
1096
1427
|
}
|
|
1097
1428
|
_applyUpdate(op, isLocal) {
|
|
1098
1429
|
let isModified = !1;
|
|
1099
|
-
const reverse = [], reverseUpdate = {
|
|
1430
|
+
const id = nn(this._id), reverse = [], reverseUpdate = {
|
|
1100
1431
|
type: OpCode.UPDATE_OBJECT,
|
|
1101
|
-
id:
|
|
1432
|
+
id: id,
|
|
1102
1433
|
data: {}
|
|
1103
1434
|
};
|
|
1104
1435
|
reverse.push(reverseUpdate);
|
|
1105
1436
|
for (const key in op.data) {
|
|
1106
1437
|
const oldValue = this._map.get(key);
|
|
1107
|
-
oldValue
|
|
1108
|
-
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({
|
|
1109
1439
|
type: OpCode.DELETE_OBJECT_KEY,
|
|
1110
|
-
id:
|
|
1440
|
+
id: id,
|
|
1111
1441
|
key: key
|
|
1112
1442
|
});
|
|
1113
1443
|
}
|
|
1114
1444
|
const updateDelta = {};
|
|
1115
1445
|
for (const key in op.data) {
|
|
1116
|
-
if (isLocal) this._propToLastUpdate.set(key, op.opId); else {
|
|
1446
|
+
if (isLocal) this._propToLastUpdate.set(key, nn(op.opId)); else {
|
|
1117
1447
|
if (null != this._propToLastUpdate.get(key)) {
|
|
1118
1448
|
if (this._propToLastUpdate.get(key) === op.opId) {
|
|
1119
1449
|
this._propToLastUpdate.delete(key);
|
|
@@ -1124,7 +1454,7 @@ class LiveObject extends AbstractCrdt {
|
|
|
1124
1454
|
isModified = !0;
|
|
1125
1455
|
}
|
|
1126
1456
|
const oldValue = this._map.get(key);
|
|
1127
|
-
|
|
1457
|
+
isLiveNode(oldValue) && oldValue._detach(), isModified = !0, updateDelta[key] = {
|
|
1128
1458
|
type: "update"
|
|
1129
1459
|
}, this._map.set(key, op.data[key]);
|
|
1130
1460
|
}
|
|
@@ -1148,11 +1478,11 @@ class LiveObject extends AbstractCrdt {
|
|
|
1148
1478
|
if (void 0 !== this._propToLastUpdate.get(key)) return {
|
|
1149
1479
|
modified: !1
|
|
1150
1480
|
};
|
|
1151
|
-
const oldValue = this._map.get(key);
|
|
1481
|
+
const oldValue = this._map.get(key), id = nn(this._id);
|
|
1152
1482
|
let reverse = [];
|
|
1153
|
-
return
|
|
1483
|
+
return isLiveNode(oldValue) ? (reverse = oldValue._serialize(id, op.key), oldValue._detach()) : void 0 !== oldValue && (reverse = [ {
|
|
1154
1484
|
type: OpCode.UPDATE_OBJECT,
|
|
1155
|
-
id:
|
|
1485
|
+
id: id,
|
|
1156
1486
|
data: {
|
|
1157
1487
|
[key]: oldValue
|
|
1158
1488
|
}
|
|
@@ -1187,10 +1517,10 @@ class LiveObject extends AbstractCrdt {
|
|
|
1187
1517
|
delete(key) {
|
|
1188
1518
|
const keyAsString = key, oldValue = this._map.get(keyAsString);
|
|
1189
1519
|
if (void 0 === oldValue) return;
|
|
1190
|
-
if (null == this._doc || null == this._id) return oldValue
|
|
1520
|
+
if (null == this._doc || null == this._id) return isLiveNode(oldValue) && oldValue._detach(),
|
|
1191
1521
|
void this._map.delete(keyAsString);
|
|
1192
1522
|
let reverse;
|
|
1193
|
-
oldValue
|
|
1523
|
+
isLiveNode(oldValue) ? (oldValue._detach(), reverse = oldValue._serialize(this._id, keyAsString)) : reverse = [ {
|
|
1194
1524
|
type: OpCode.UPDATE_OBJECT,
|
|
1195
1525
|
data: {
|
|
1196
1526
|
[keyAsString]: oldValue
|
|
@@ -1217,9 +1547,9 @@ class LiveObject extends AbstractCrdt {
|
|
|
1217
1547
|
if (null == this._doc || null == this._id) {
|
|
1218
1548
|
for (const key in overrides) {
|
|
1219
1549
|
const oldValue = this._map.get(key);
|
|
1220
|
-
oldValue
|
|
1550
|
+
isLiveNode(oldValue) && oldValue._detach();
|
|
1221
1551
|
const newValue = overrides[key];
|
|
1222
|
-
newValue
|
|
1552
|
+
isLiveNode(newValue) && newValue._setParentLink(this, key), this._map.set(key, newValue);
|
|
1223
1553
|
}
|
|
1224
1554
|
return;
|
|
1225
1555
|
}
|
|
@@ -1230,17 +1560,17 @@ class LiveObject extends AbstractCrdt {
|
|
|
1230
1560
|
}, updateDelta = {};
|
|
1231
1561
|
for (const key in overrides) {
|
|
1232
1562
|
const oldValue = this._map.get(key);
|
|
1233
|
-
oldValue
|
|
1563
|
+
isLiveNode(oldValue) ? (reverseOps.push(...oldValue._serialize(this._id, key)),
|
|
1234
1564
|
oldValue._detach()) : void 0 === oldValue ? reverseOps.push({
|
|
1235
1565
|
type: OpCode.DELETE_OBJECT_KEY,
|
|
1236
1566
|
id: this._id,
|
|
1237
1567
|
key: key
|
|
1238
1568
|
}) : reverseUpdateOp.data[key] = oldValue;
|
|
1239
1569
|
const newValue = overrides[key];
|
|
1240
|
-
if (newValue
|
|
1570
|
+
if (isLiveNode(newValue)) {
|
|
1241
1571
|
newValue._setParentLink(this, key), newValue._attach(this._doc.generateId(), this._doc);
|
|
1242
1572
|
const newAttachChildOps = newValue._serialize(this._id, key, this._doc), createCrdtOp = newAttachChildOps.find((op => op.parentId === this._id));
|
|
1243
|
-
createCrdtOp && this._propToLastUpdate.set(key, createCrdtOp.opId), ops.push(...newAttachChildOps);
|
|
1573
|
+
createCrdtOp && this._propToLastUpdate.set(key, nn(createCrdtOp.opId)), ops.push(...newAttachChildOps);
|
|
1244
1574
|
} else updatedProps[key] = newValue, this._propToLastUpdate.set(key, opId);
|
|
1245
1575
|
this._map.set(key, newValue), updateDelta[key] = {
|
|
1246
1576
|
type: "update"
|
|
@@ -1262,4 +1592,4 @@ class LiveObject extends AbstractCrdt {
|
|
|
1262
1592
|
}
|
|
1263
1593
|
}
|
|
1264
1594
|
|
|
1265
|
-
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 };
|