@liveblocks/client 0.16.15 → 0.17.0-beta1
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 +28 -8
- package/index.js +1290 -830
- package/index.mjs +1091 -782
- package/internal.d.ts +418 -248
- package/internal.js +313 -168
- package/internal.mjs +264 -130
- package/package.json +15 -10
- package/shared.d.ts +719 -650
- package/shared.js +2571 -1331
- package/shared.mjs +1992 -1209
package/shared.mjs
CHANGED
|
@@ -1,1280 +1,2063 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const _emittedDeprecationWarnings = new Set();
|
|
2
|
+
function deprecate(message, key = message) {
|
|
3
|
+
"production" !== process.env.NODE_ENV &&
|
|
4
|
+
(_emittedDeprecationWarnings.has(key) ||
|
|
5
|
+
(_emittedDeprecationWarnings.add(key),
|
|
6
|
+
console.error(`DEPRECATION WARNING: ${message}`)));
|
|
7
|
+
}
|
|
8
|
+
function deprecateIf(condition, message, key = message) {
|
|
9
|
+
"production" !== process.env.NODE_ENV && condition && deprecate(message, key);
|
|
10
|
+
}
|
|
11
|
+
function throwUsageError(message) {
|
|
12
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
13
|
+
const usageError = new Error(message);
|
|
14
|
+
throw ((usageError.name = "Usage error"), usageError);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function errorIf(condition, message) {
|
|
18
|
+
"production" !== process.env.NODE_ENV &&
|
|
19
|
+
condition &&
|
|
20
|
+
throwUsageError(message);
|
|
21
|
+
}
|
|
22
|
+
function __rest(s, e) {
|
|
23
|
+
var t = {};
|
|
24
|
+
for (var p in s)
|
|
25
|
+
Object.prototype.hasOwnProperty.call(s, p) &&
|
|
26
|
+
e.indexOf(p) < 0 &&
|
|
27
|
+
(t[p] = s[p]);
|
|
28
|
+
if (null != s && "function" == typeof Object.getOwnPropertySymbols) {
|
|
29
|
+
var i = 0;
|
|
30
|
+
for (p = Object.getOwnPropertySymbols(s); i < p.length; i++)
|
|
31
|
+
e.indexOf(p[i]) < 0 &&
|
|
32
|
+
Object.prototype.propertyIsEnumerable.call(s, p[i]) &&
|
|
33
|
+
(t[p[i]] = s[p[i]]);
|
|
34
|
+
}
|
|
35
|
+
return t;
|
|
36
|
+
}
|
|
37
|
+
function assertNever(_value, errmsg) {
|
|
38
|
+
throw new Error(errmsg);
|
|
39
|
+
}
|
|
40
|
+
function nn(value, errmsg = "Expected value to be non-nullable") {
|
|
41
|
+
return (
|
|
42
|
+
(function (condition, errmsg) {
|
|
43
|
+
if ("production" !== process.env.NODE_ENV && !condition) {
|
|
44
|
+
const err = new Error(errmsg);
|
|
45
|
+
throw ((err.name = "Assertion failure"), err);
|
|
46
|
+
}
|
|
47
|
+
})(null != value, errmsg),
|
|
48
|
+
value
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
var ClientMsgCode,
|
|
52
|
+
OpCode,
|
|
53
|
+
CrdtType,
|
|
54
|
+
ServerMsgCode,
|
|
55
|
+
WebsocketCloseCodes,
|
|
56
|
+
OpSource;
|
|
3
57
|
function isRootCrdt(crdt) {
|
|
4
|
-
|
|
58
|
+
return crdt.type === CrdtType.OBJECT && !isChildCrdt(crdt);
|
|
5
59
|
}
|
|
6
|
-
|
|
7
60
|
function isChildCrdt(crdt) {
|
|
8
|
-
|
|
61
|
+
return void 0 !== crdt.parentId && void 0 !== crdt.parentKey;
|
|
9
62
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
ClientMsgCode[ClientMsgCode.FETCH_STORAGE = 200] = "FETCH_STORAGE", ClientMsgCode[ClientMsgCode.UPDATE_STORAGE = 201] = "UPDATE_STORAGE";
|
|
19
|
-
}(ClientMsgCode || (ClientMsgCode = {})), function(CrdtType) {
|
|
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) {
|
|
23
|
-
OpCode[OpCode.INIT = 0] = "INIT", OpCode[OpCode.SET_PARENT_KEY = 1] = "SET_PARENT_KEY",
|
|
24
|
-
OpCode[OpCode.CREATE_LIST = 2] = "CREATE_LIST", OpCode[OpCode.UPDATE_OBJECT = 3] = "UPDATE_OBJECT",
|
|
25
|
-
OpCode[OpCode.CREATE_OBJECT = 4] = "CREATE_OBJECT", OpCode[OpCode.DELETE_CRDT = 5] = "DELETE_CRDT",
|
|
26
|
-
OpCode[OpCode.DELETE_OBJECT_KEY = 6] = "DELETE_OBJECT_KEY", OpCode[OpCode.CREATE_MAP = 7] = "CREATE_MAP",
|
|
27
|
-
OpCode[OpCode.CREATE_REGISTER = 8] = "CREATE_REGISTER";
|
|
28
|
-
}(OpCode || (OpCode = {})), function(WebsocketCloseCodes) {
|
|
29
|
-
WebsocketCloseCodes[WebsocketCloseCodes.CLOSE_ABNORMAL = 1006] = "CLOSE_ABNORMAL",
|
|
30
|
-
WebsocketCloseCodes[WebsocketCloseCodes.INVALID_MESSAGE_FORMAT = 4e3] = "INVALID_MESSAGE_FORMAT",
|
|
31
|
-
WebsocketCloseCodes[WebsocketCloseCodes.NOT_ALLOWED = 4001] = "NOT_ALLOWED", WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_MESSAGES_PER_SECONDS = 4002] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS",
|
|
32
|
-
WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS",
|
|
33
|
-
WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP",
|
|
34
|
-
WebsocketCloseCodes[WebsocketCloseCodes.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM",
|
|
35
|
-
WebsocketCloseCodes[WebsocketCloseCodes.CLOSE_WITHOUT_RETRY = 4999] = "CLOSE_WITHOUT_RETRY";
|
|
36
|
-
}(WebsocketCloseCodes || (WebsocketCloseCodes = {}));
|
|
37
|
-
|
|
38
|
-
class AbstractCrdt {
|
|
39
|
-
get _doc() {
|
|
40
|
-
return this.__doc;
|
|
41
|
-
}
|
|
42
|
-
get roomId() {
|
|
43
|
-
return this.__doc ? this.__doc.roomId : null;
|
|
44
|
-
}
|
|
45
|
-
get _id() {
|
|
46
|
-
return this.__id;
|
|
47
|
-
}
|
|
48
|
-
get _parent() {
|
|
49
|
-
return this.__parent;
|
|
50
|
-
}
|
|
51
|
-
get _parentKey() {
|
|
52
|
-
return this.__parentKey;
|
|
53
|
-
}
|
|
54
|
-
_apply(op, _isLocal) {
|
|
55
|
-
return op.type === OpCode.DELETE_CRDT && null != this._parent && null != this._parentKey ? this._parent._detachChild(this) : {
|
|
56
|
-
modified: !1
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
_setParentLink(parent, key) {
|
|
60
|
-
if (null != this.__parent && this.__parent !== parent) throw new Error("Cannot attach parent if it already exist");
|
|
61
|
-
this.__parentKey = key, this.__parent = parent;
|
|
62
|
-
}
|
|
63
|
-
_attach(id, doc) {
|
|
64
|
-
if (this.__id || this.__doc) throw new Error("Cannot attach if CRDT is already attached");
|
|
65
|
-
doc.addItem(id, this), this.__id = id, this.__doc = doc;
|
|
66
|
-
}
|
|
67
|
-
_detach() {
|
|
68
|
-
this.__doc && this.__id && this.__doc.deleteItem(this.__id), this.__parent = void 0,
|
|
69
|
-
this.__doc = void 0;
|
|
70
|
-
}
|
|
63
|
+
function isRoomEventName(value) {
|
|
64
|
+
return (
|
|
65
|
+
"my-presence" === value ||
|
|
66
|
+
"others" === value ||
|
|
67
|
+
"event" === value ||
|
|
68
|
+
"error" === value ||
|
|
69
|
+
"connection" === value
|
|
70
|
+
);
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return null === data || "string" == typeof data || "number" == typeof data || "boolean" == typeof data;
|
|
72
|
+
function HasParent(node, key) {
|
|
73
|
+
return Object.freeze({ type: "HasParent", node: node, key: key });
|
|
75
74
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
!(function (ClientMsgCode) {
|
|
76
|
+
(ClientMsgCode[(ClientMsgCode.UPDATE_PRESENCE = 100)] = "UPDATE_PRESENCE"),
|
|
77
|
+
(ClientMsgCode[(ClientMsgCode.BROADCAST_EVENT = 103)] = "BROADCAST_EVENT"),
|
|
78
|
+
(ClientMsgCode[(ClientMsgCode.FETCH_STORAGE = 200)] = "FETCH_STORAGE"),
|
|
79
|
+
(ClientMsgCode[(ClientMsgCode.UPDATE_STORAGE = 201)] = "UPDATE_STORAGE");
|
|
80
|
+
})(ClientMsgCode || (ClientMsgCode = {})),
|
|
81
|
+
(function (OpCode) {
|
|
82
|
+
(OpCode[(OpCode.INIT = 0)] = "INIT"),
|
|
83
|
+
(OpCode[(OpCode.SET_PARENT_KEY = 1)] = "SET_PARENT_KEY"),
|
|
84
|
+
(OpCode[(OpCode.CREATE_LIST = 2)] = "CREATE_LIST"),
|
|
85
|
+
(OpCode[(OpCode.UPDATE_OBJECT = 3)] = "UPDATE_OBJECT"),
|
|
86
|
+
(OpCode[(OpCode.CREATE_OBJECT = 4)] = "CREATE_OBJECT"),
|
|
87
|
+
(OpCode[(OpCode.DELETE_CRDT = 5)] = "DELETE_CRDT"),
|
|
88
|
+
(OpCode[(OpCode.DELETE_OBJECT_KEY = 6)] = "DELETE_OBJECT_KEY"),
|
|
89
|
+
(OpCode[(OpCode.CREATE_MAP = 7)] = "CREATE_MAP"),
|
|
90
|
+
(OpCode[(OpCode.CREATE_REGISTER = 8)] = "CREATE_REGISTER");
|
|
91
|
+
})(OpCode || (OpCode = {})),
|
|
92
|
+
(function (CrdtType) {
|
|
93
|
+
(CrdtType[(CrdtType.OBJECT = 0)] = "OBJECT"),
|
|
94
|
+
(CrdtType[(CrdtType.LIST = 1)] = "LIST"),
|
|
95
|
+
(CrdtType[(CrdtType.MAP = 2)] = "MAP"),
|
|
96
|
+
(CrdtType[(CrdtType.REGISTER = 3)] = "REGISTER");
|
|
97
|
+
})(CrdtType || (CrdtType = {})),
|
|
98
|
+
(function (ServerMsgCode) {
|
|
99
|
+
(ServerMsgCode[(ServerMsgCode.UPDATE_PRESENCE = 100)] = "UPDATE_PRESENCE"),
|
|
100
|
+
(ServerMsgCode[(ServerMsgCode.USER_JOINED = 101)] = "USER_JOINED"),
|
|
101
|
+
(ServerMsgCode[(ServerMsgCode.USER_LEFT = 102)] = "USER_LEFT"),
|
|
102
|
+
(ServerMsgCode[(ServerMsgCode.BROADCASTED_EVENT = 103)] =
|
|
103
|
+
"BROADCASTED_EVENT"),
|
|
104
|
+
(ServerMsgCode[(ServerMsgCode.ROOM_STATE = 104)] = "ROOM_STATE"),
|
|
105
|
+
(ServerMsgCode[(ServerMsgCode.INITIAL_STORAGE_STATE = 200)] =
|
|
106
|
+
"INITIAL_STORAGE_STATE"),
|
|
107
|
+
(ServerMsgCode[(ServerMsgCode.UPDATE_STORAGE = 201)] = "UPDATE_STORAGE");
|
|
108
|
+
})(ServerMsgCode || (ServerMsgCode = {})),
|
|
109
|
+
(function (WebsocketCloseCodes) {
|
|
110
|
+
(WebsocketCloseCodes[(WebsocketCloseCodes.CLOSE_ABNORMAL = 1006)] =
|
|
111
|
+
"CLOSE_ABNORMAL"),
|
|
112
|
+
(WebsocketCloseCodes[(WebsocketCloseCodes.INVALID_MESSAGE_FORMAT = 4e3)] =
|
|
113
|
+
"INVALID_MESSAGE_FORMAT"),
|
|
114
|
+
(WebsocketCloseCodes[(WebsocketCloseCodes.NOT_ALLOWED = 4001)] =
|
|
115
|
+
"NOT_ALLOWED"),
|
|
116
|
+
(WebsocketCloseCodes[
|
|
117
|
+
(WebsocketCloseCodes.MAX_NUMBER_OF_MESSAGES_PER_SECONDS = 4002)
|
|
118
|
+
] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS"),
|
|
119
|
+
(WebsocketCloseCodes[
|
|
120
|
+
(WebsocketCloseCodes.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS = 4003)
|
|
121
|
+
] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"),
|
|
122
|
+
(WebsocketCloseCodes[
|
|
123
|
+
(WebsocketCloseCodes.MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP = 4004)
|
|
124
|
+
] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"),
|
|
125
|
+
(WebsocketCloseCodes[
|
|
126
|
+
(WebsocketCloseCodes.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM = 4005)
|
|
127
|
+
] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"),
|
|
128
|
+
(WebsocketCloseCodes[(WebsocketCloseCodes.CLOSE_WITHOUT_RETRY = 4999)] =
|
|
129
|
+
"CLOSE_WITHOUT_RETRY");
|
|
130
|
+
})(WebsocketCloseCodes || (WebsocketCloseCodes = {})),
|
|
131
|
+
(function (OpSource) {
|
|
132
|
+
(OpSource[(OpSource.UNDOREDO_RECONNECT = 0)] = "UNDOREDO_RECONNECT"),
|
|
133
|
+
(OpSource[(OpSource.REMOTE = 1)] = "REMOTE"),
|
|
134
|
+
(OpSource[(OpSource.ACK = 2)] = "ACK");
|
|
135
|
+
})(OpSource || (OpSource = {}));
|
|
136
|
+
const NoParent = Object.freeze({ type: "NoParent" });
|
|
137
|
+
function Orphaned(oldKey) {
|
|
138
|
+
return Object.freeze({ type: "Orphaned", oldKey: oldKey });
|
|
79
139
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
140
|
+
class AbstractCrdt {
|
|
141
|
+
constructor() {
|
|
142
|
+
this._parent = NoParent;
|
|
143
|
+
}
|
|
144
|
+
_getParentKeyOrThrow() {
|
|
145
|
+
switch (this.parent.type) {
|
|
146
|
+
case "HasParent":
|
|
147
|
+
return this.parent.key;
|
|
148
|
+
case "NoParent":
|
|
149
|
+
throw new Error("Parent key is missing");
|
|
150
|
+
case "Orphaned":
|
|
151
|
+
return this.parent.oldKey;
|
|
152
|
+
default:
|
|
153
|
+
return assertNever(this.parent, "Unknown state");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
get _doc() {
|
|
157
|
+
return this.__doc;
|
|
158
|
+
}
|
|
159
|
+
get roomId() {
|
|
160
|
+
return this.__doc ? this.__doc.roomId : null;
|
|
161
|
+
}
|
|
162
|
+
get _id() {
|
|
163
|
+
return this.__id;
|
|
164
|
+
}
|
|
165
|
+
get parent() {
|
|
166
|
+
return this._parent;
|
|
167
|
+
}
|
|
168
|
+
get _parentNode() {
|
|
169
|
+
switch (this.parent.type) {
|
|
170
|
+
case "HasParent":
|
|
171
|
+
return this.parent.node;
|
|
172
|
+
case "NoParent":
|
|
173
|
+
case "Orphaned":
|
|
174
|
+
return null;
|
|
175
|
+
default:
|
|
176
|
+
return assertNever(this.parent, "Unknown state");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
get _parentKey() {
|
|
180
|
+
switch (this.parent.type) {
|
|
181
|
+
case "HasParent":
|
|
182
|
+
return this.parent.key;
|
|
183
|
+
case "NoParent":
|
|
184
|
+
return null;
|
|
185
|
+
case "Orphaned":
|
|
186
|
+
return this.parent.oldKey;
|
|
187
|
+
default:
|
|
188
|
+
return assertNever(this.parent, "Unknown state");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
_apply(op, _isLocal) {
|
|
192
|
+
return op.type === OpCode.DELETE_CRDT && "HasParent" === this.parent.type
|
|
193
|
+
? this.parent.node._detachChild(this)
|
|
194
|
+
: { modified: !1 };
|
|
195
|
+
}
|
|
196
|
+
_setParentLink(newParentNode, newParentKey) {
|
|
197
|
+
switch (this.parent.type) {
|
|
198
|
+
case "HasParent":
|
|
199
|
+
if (this.parent.node !== newParentNode)
|
|
200
|
+
throw new Error("Cannot attach parent if it already exist");
|
|
201
|
+
return void (this._parent = HasParent(newParentNode, newParentKey));
|
|
202
|
+
case "Orphaned":
|
|
203
|
+
case "NoParent":
|
|
204
|
+
return void (this._parent = HasParent(newParentNode, newParentKey));
|
|
205
|
+
default:
|
|
206
|
+
return assertNever(this.parent, "Unknown state");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
_attach(id, doc) {
|
|
210
|
+
if (this.__id || this.__doc)
|
|
211
|
+
throw new Error("Cannot attach if CRDT is already attached");
|
|
212
|
+
doc.addItem(id, this), (this.__id = id), (this.__doc = doc);
|
|
213
|
+
}
|
|
214
|
+
_detach() {
|
|
215
|
+
switch (
|
|
216
|
+
(this.__doc && this.__id && this.__doc.deleteItem(this.__id),
|
|
217
|
+
this.parent.type)
|
|
218
|
+
) {
|
|
219
|
+
case "HasParent":
|
|
220
|
+
this._parent = Orphaned(this.parent.key);
|
|
221
|
+
break;
|
|
222
|
+
case "NoParent":
|
|
223
|
+
this._parent = NoParent;
|
|
224
|
+
break;
|
|
225
|
+
case "Orphaned":
|
|
226
|
+
this._parent = Orphaned(this.parent.oldKey);
|
|
227
|
+
break;
|
|
228
|
+
default:
|
|
229
|
+
assertNever(this.parent, "Unknown state");
|
|
230
|
+
}
|
|
231
|
+
this.__doc = void 0;
|
|
232
|
+
}
|
|
83
233
|
}
|
|
84
|
-
|
|
85
234
|
class LiveRegister extends AbstractCrdt {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
235
|
+
constructor(data) {
|
|
236
|
+
super(), (this._data = data);
|
|
237
|
+
}
|
|
238
|
+
get data() {
|
|
239
|
+
return this._data;
|
|
240
|
+
}
|
|
241
|
+
static _deserialize([id, item], _parentToChildren, doc) {
|
|
242
|
+
const register = new LiveRegister(item.data);
|
|
243
|
+
return register._attach(id, doc), register;
|
|
244
|
+
}
|
|
245
|
+
_serialize(parentId, parentKey, doc) {
|
|
246
|
+
if (null == this._id || null == parentId || null == parentKey)
|
|
247
|
+
throw new Error(
|
|
248
|
+
"Cannot serialize register if parentId or parentKey is undefined"
|
|
249
|
+
);
|
|
250
|
+
return [
|
|
251
|
+
{
|
|
252
|
+
type: OpCode.CREATE_REGISTER,
|
|
253
|
+
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
254
|
+
id: this._id,
|
|
255
|
+
parentId: parentId,
|
|
256
|
+
parentKey: parentKey,
|
|
257
|
+
data: this.data,
|
|
258
|
+
},
|
|
259
|
+
];
|
|
260
|
+
}
|
|
261
|
+
_toSerializedCrdt() {
|
|
262
|
+
if ("HasParent" !== this.parent.type)
|
|
263
|
+
throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
264
|
+
return {
|
|
265
|
+
type: CrdtType.REGISTER,
|
|
266
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
267
|
+
parentKey: this.parent.key,
|
|
268
|
+
data: this.data,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
_attachChild(_op) {
|
|
272
|
+
throw new Error("Method not implemented.");
|
|
273
|
+
}
|
|
274
|
+
_detachChild(_crdt) {
|
|
275
|
+
throw new Error("Method not implemented.");
|
|
276
|
+
}
|
|
277
|
+
_apply(op, isLocal) {
|
|
278
|
+
return super._apply(op, isLocal);
|
|
279
|
+
}
|
|
126
280
|
}
|
|
127
|
-
|
|
128
281
|
function makePosition(before, after) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
282
|
+
return null != before && null != after
|
|
283
|
+
? pos(makePositionFromCodes(posCodes(before), posCodes(after)))
|
|
284
|
+
: null != before
|
|
285
|
+
? (function (before) {
|
|
286
|
+
const result = [],
|
|
287
|
+
beforeCodes = posCodes(before);
|
|
288
|
+
for (let i = 0; i < beforeCodes.length; i++) {
|
|
289
|
+
const code = beforeCodes[i];
|
|
290
|
+
if (126 !== code) {
|
|
291
|
+
result.push(code + 1);
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
if ((result.push(code), beforeCodes.length - 1 === i)) {
|
|
295
|
+
result.push(33);
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return pos(result);
|
|
300
|
+
})(before)
|
|
301
|
+
: null != after
|
|
302
|
+
? (function (after) {
|
|
303
|
+
const result = [],
|
|
304
|
+
afterCodes = posCodes(after);
|
|
305
|
+
for (let i = 0; i < afterCodes.length; i++) {
|
|
306
|
+
const code = afterCodes[i];
|
|
307
|
+
if (!(code <= 33)) {
|
|
308
|
+
result.push(code - 1);
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
if ((result.push(32), afterCodes.length - 1 === i)) {
|
|
312
|
+
result.push(126);
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return pos(result);
|
|
317
|
+
})(after)
|
|
318
|
+
: pos([33]);
|
|
158
319
|
}
|
|
159
|
-
|
|
160
320
|
function makePositionFromCodes(before, after) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
321
|
+
let index = 0;
|
|
322
|
+
const result = [];
|
|
323
|
+
for (;;) {
|
|
324
|
+
const beforeDigit = before[index] || 32,
|
|
325
|
+
afterDigit = after[index] || 126;
|
|
326
|
+
if (beforeDigit > afterDigit)
|
|
327
|
+
throw new Error(
|
|
328
|
+
`Impossible to generate position between ${before} and ${after}`
|
|
329
|
+
);
|
|
330
|
+
if (beforeDigit === afterDigit) {
|
|
331
|
+
result.push(beforeDigit), index++;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (afterDigit - beforeDigit == 1) {
|
|
335
|
+
result.push(beforeDigit),
|
|
336
|
+
result.push(...makePositionFromCodes(before.slice(index + 1), []));
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
const mid = (afterDigit + beforeDigit) >> 1;
|
|
340
|
+
result.push(mid);
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
return result;
|
|
179
344
|
}
|
|
180
|
-
|
|
181
345
|
function posCodes(str) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
346
|
+
const codes = [];
|
|
347
|
+
for (let i = 0; i < str.length; i++) codes.push(str.charCodeAt(i));
|
|
348
|
+
return codes;
|
|
185
349
|
}
|
|
186
|
-
|
|
187
350
|
function pos(codes) {
|
|
188
|
-
|
|
351
|
+
return String.fromCharCode(...codes);
|
|
189
352
|
}
|
|
190
|
-
|
|
191
353
|
function comparePosition(posA, posB) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
354
|
+
const aCodes = posCodes(posA),
|
|
355
|
+
bCodes = posCodes(posB),
|
|
356
|
+
maxLength = Math.max(aCodes.length, bCodes.length);
|
|
357
|
+
for (let i = 0; i < maxLength; i++) {
|
|
358
|
+
const a = null == aCodes[i] ? 32 : aCodes[i],
|
|
359
|
+
b = null == bCodes[i] ? 32 : bCodes[i];
|
|
360
|
+
if (a !== b) return a - b;
|
|
361
|
+
}
|
|
362
|
+
throw new Error(
|
|
363
|
+
`Impossible to compare similar position "${posA}" and "${posB}"`
|
|
364
|
+
);
|
|
198
365
|
}
|
|
199
|
-
|
|
200
366
|
class LiveList extends AbstractCrdt {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
367
|
+
constructor(items = []) {
|
|
368
|
+
let position;
|
|
369
|
+
super(),
|
|
370
|
+
(this._items = []),
|
|
371
|
+
(this._implicitlyDeletedItems = new Set()),
|
|
372
|
+
(this._unacknowledgedSets = new Map());
|
|
373
|
+
for (let i = 0; i < items.length; i++) {
|
|
374
|
+
const newPosition = makePosition(position),
|
|
375
|
+
item = lsonToLiveNode(items[i]);
|
|
376
|
+
item._setParentLink(this, newPosition),
|
|
377
|
+
this._items.push(item),
|
|
378
|
+
(position = newPosition);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
static _deserialize([id], parentToChildren, doc) {
|
|
382
|
+
const list = new LiveList();
|
|
383
|
+
list._attach(id, doc);
|
|
384
|
+
const children = parentToChildren.get(id);
|
|
385
|
+
if (null == children) return list;
|
|
386
|
+
for (const [id, crdt] of children) {
|
|
387
|
+
const child = deserialize([id, crdt], parentToChildren, doc);
|
|
388
|
+
child._setParentLink(list, crdt.parentKey),
|
|
389
|
+
list._items.push(child),
|
|
390
|
+
sortListItem(list._items);
|
|
391
|
+
}
|
|
392
|
+
return list;
|
|
393
|
+
}
|
|
394
|
+
_serialize(parentId, parentKey, doc) {
|
|
395
|
+
if (null == this._id)
|
|
396
|
+
throw new Error("Cannot serialize item is not attached");
|
|
397
|
+
const ops = [],
|
|
398
|
+
op = {
|
|
399
|
+
id: this._id,
|
|
400
|
+
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
401
|
+
type: OpCode.CREATE_LIST,
|
|
402
|
+
parentId: parentId,
|
|
403
|
+
parentKey: parentKey,
|
|
404
|
+
};
|
|
405
|
+
ops.push(op);
|
|
406
|
+
for (const item of this._items)
|
|
407
|
+
ops.push(...item._serialize(this._id, item._getParentKeyOrThrow(), doc));
|
|
408
|
+
return ops;
|
|
409
|
+
}
|
|
410
|
+
_indexOfPosition(position) {
|
|
411
|
+
return this._items.findIndex(
|
|
412
|
+
(item) => item._getParentKeyOrThrow() === position
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
_attach(id, doc) {
|
|
416
|
+
super._attach(id, doc);
|
|
417
|
+
for (const item of this._items) item._attach(doc.generateId(), doc);
|
|
418
|
+
}
|
|
419
|
+
_detach() {
|
|
420
|
+
super._detach();
|
|
421
|
+
for (const item of this._items) item._detach();
|
|
422
|
+
}
|
|
423
|
+
_applySetRemote(op) {
|
|
424
|
+
if (null == this._doc)
|
|
425
|
+
throw new Error("Can't attach child if doc is not present");
|
|
426
|
+
const { id: id, parentKey: key } = op,
|
|
427
|
+
child = creationOpToLiveNode(op);
|
|
428
|
+
child._attach(id, this._doc), child._setParentLink(this, key);
|
|
429
|
+
const deletedId = op.deletedId,
|
|
430
|
+
indexOfItemWithSamePosition = this._indexOfPosition(key);
|
|
431
|
+
if (-1 !== indexOfItemWithSamePosition) {
|
|
432
|
+
const itemWithSamePosition = this._items[indexOfItemWithSamePosition];
|
|
433
|
+
if (itemWithSamePosition._id === deletedId)
|
|
434
|
+
return (
|
|
435
|
+
itemWithSamePosition._detach(),
|
|
436
|
+
(this._items[indexOfItemWithSamePosition] = child),
|
|
437
|
+
{
|
|
438
|
+
modified: makeUpdate(this, [
|
|
439
|
+
setDelta(indexOfItemWithSamePosition, child),
|
|
440
|
+
]),
|
|
441
|
+
reverse: [],
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
{
|
|
445
|
+
this._implicitlyDeletedItems.add(itemWithSamePosition),
|
|
446
|
+
(this._items[indexOfItemWithSamePosition] = child);
|
|
447
|
+
const delta = [setDelta(indexOfItemWithSamePosition, child)],
|
|
448
|
+
deleteDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
449
|
+
return (
|
|
450
|
+
deleteDelta && delta.push(deleteDelta),
|
|
451
|
+
{ modified: makeUpdate(this, delta), reverse: [] }
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
{
|
|
456
|
+
const updates = [],
|
|
457
|
+
deleteDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
458
|
+
return (
|
|
459
|
+
deleteDelta && updates.push(deleteDelta),
|
|
460
|
+
this._items.push(child),
|
|
461
|
+
sortListItem(this._items),
|
|
462
|
+
updates.push(insertDelta(this._indexOfPosition(key), child)),
|
|
463
|
+
{ reverse: [], modified: makeUpdate(this, updates) }
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
_applySetAck(op) {
|
|
468
|
+
if (null == this._doc)
|
|
469
|
+
throw new Error("Can't attach child if doc is not present");
|
|
470
|
+
const delta = [],
|
|
471
|
+
deletedDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
472
|
+
deletedDelta && delta.push(deletedDelta);
|
|
473
|
+
const unacknowledgedOpId = this._unacknowledgedSets.get(op.parentKey);
|
|
474
|
+
if (null != unacknowledgedOpId) {
|
|
475
|
+
if (unacknowledgedOpId !== op.opId)
|
|
476
|
+
return 0 === delta.length
|
|
477
|
+
? { modified: !1 }
|
|
478
|
+
: { modified: makeUpdate(this, delta), reverse: [] };
|
|
479
|
+
this._unacknowledgedSets.delete(op.parentKey);
|
|
480
|
+
}
|
|
481
|
+
const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey),
|
|
482
|
+
existingItem = this._items.find((item) => item._id === op.id);
|
|
483
|
+
if (null != existingItem) {
|
|
484
|
+
if (existingItem._parentKey === op.parentKey)
|
|
485
|
+
return {
|
|
486
|
+
modified: delta.length > 0 && makeUpdate(this, delta),
|
|
487
|
+
reverse: [],
|
|
488
|
+
};
|
|
489
|
+
-1 !== indexOfItemWithSamePosition &&
|
|
490
|
+
(this._implicitlyDeletedItems.add(
|
|
491
|
+
this._items[indexOfItemWithSamePosition]
|
|
492
|
+
),
|
|
493
|
+
this._items.splice(indexOfItemWithSamePosition, 1),
|
|
494
|
+
delta.push(deleteDelta(indexOfItemWithSamePosition)));
|
|
495
|
+
const previousIndex = this._items.indexOf(existingItem);
|
|
496
|
+
existingItem._setParentLink(this, op.parentKey),
|
|
497
|
+
sortListItem(this._items);
|
|
498
|
+
const newIndex = this._items.indexOf(existingItem);
|
|
499
|
+
return (
|
|
500
|
+
newIndex !== previousIndex &&
|
|
501
|
+
delta.push(moveDelta(previousIndex, newIndex, existingItem)),
|
|
502
|
+
{ modified: delta.length > 0 && makeUpdate(this, delta), reverse: [] }
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
{
|
|
506
|
+
const orphan = this._doc.getItem(op.id);
|
|
507
|
+
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
508
|
+
orphan._setParentLink(this, op.parentKey),
|
|
509
|
+
this._implicitlyDeletedItems.delete(orphan),
|
|
510
|
+
this._items.push(orphan),
|
|
511
|
+
sortListItem(this._items);
|
|
512
|
+
const recreatedItemIndex = this._items.indexOf(orphan);
|
|
513
|
+
return {
|
|
514
|
+
modified: makeUpdate(this, [
|
|
515
|
+
-1 === indexOfItemWithSamePosition
|
|
516
|
+
? insertDelta(recreatedItemIndex, orphan)
|
|
517
|
+
: setDelta(recreatedItemIndex, orphan),
|
|
518
|
+
...delta,
|
|
519
|
+
]),
|
|
520
|
+
reverse: [],
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
{
|
|
524
|
+
-1 !== indexOfItemWithSamePosition &&
|
|
525
|
+
this._items.splice(indexOfItemWithSamePosition, 1);
|
|
526
|
+
const { newItem: newItem, newIndex: newIndex } =
|
|
527
|
+
this._createAttachItemAndSort(op, op.parentKey);
|
|
528
|
+
return {
|
|
529
|
+
modified: makeUpdate(this, [
|
|
530
|
+
-1 === indexOfItemWithSamePosition
|
|
531
|
+
? insertDelta(newIndex, newItem)
|
|
532
|
+
: setDelta(newIndex, newItem),
|
|
533
|
+
...delta,
|
|
534
|
+
]),
|
|
535
|
+
reverse: [],
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
_detachItemAssociatedToSetOperation(deletedId) {
|
|
541
|
+
if (null == deletedId || null == this._doc) return null;
|
|
542
|
+
const deletedItem = this._doc.getItem(deletedId);
|
|
543
|
+
if (null == deletedItem) return null;
|
|
544
|
+
const result = this._detachChild(deletedItem);
|
|
545
|
+
return !1 === result.modified ? null : result.modified.updates[0];
|
|
546
|
+
}
|
|
547
|
+
_applyRemoteInsert(op) {
|
|
548
|
+
if (null == this._doc)
|
|
549
|
+
throw new Error("Can't attach child if doc is not present");
|
|
550
|
+
const key = op.parentKey,
|
|
551
|
+
existingItemIndex = this._indexOfPosition(key);
|
|
552
|
+
-1 !== existingItemIndex && this._shiftItemPosition(existingItemIndex, key);
|
|
553
|
+
const { newItem: newItem, newIndex: newIndex } =
|
|
554
|
+
this._createAttachItemAndSort(op, key);
|
|
555
|
+
return {
|
|
556
|
+
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
557
|
+
reverse: [],
|
|
269
558
|
};
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
559
|
+
}
|
|
560
|
+
_applyInsertAck(op) {
|
|
561
|
+
const existingItem = this._items.find((item) => item._id === op.id),
|
|
562
|
+
key = op.parentKey,
|
|
563
|
+
itemIndexAtPosition = this._indexOfPosition(key);
|
|
564
|
+
if (existingItem) {
|
|
565
|
+
if (existingItem._parentKey === key) return { modified: !1 };
|
|
566
|
+
{
|
|
567
|
+
const oldPositionIndex = this._items.indexOf(existingItem);
|
|
568
|
+
-1 !== itemIndexAtPosition &&
|
|
569
|
+
this._shiftItemPosition(itemIndexAtPosition, key),
|
|
570
|
+
existingItem._setParentLink(this, key),
|
|
571
|
+
sortListItem(this._items);
|
|
572
|
+
const newIndex = this._indexOfPosition(key);
|
|
573
|
+
return newIndex === oldPositionIndex
|
|
574
|
+
? { modified: !1 }
|
|
575
|
+
: {
|
|
576
|
+
modified: makeUpdate(this, [
|
|
577
|
+
moveDelta(oldPositionIndex, newIndex, existingItem),
|
|
578
|
+
]),
|
|
579
|
+
reverse: [],
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
{
|
|
584
|
+
const orphan = nn(this._doc).getItem(op.id);
|
|
585
|
+
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
586
|
+
orphan._setParentLink(this, key),
|
|
587
|
+
this._implicitlyDeletedItems.delete(orphan),
|
|
588
|
+
this._items.push(orphan),
|
|
589
|
+
sortListItem(this._items);
|
|
590
|
+
return {
|
|
591
|
+
modified: makeUpdate(this, [
|
|
592
|
+
insertDelta(this._indexOfPosition(key), orphan),
|
|
593
|
+
]),
|
|
594
|
+
reverse: [],
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
{
|
|
598
|
+
-1 !== itemIndexAtPosition &&
|
|
599
|
+
this._shiftItemPosition(itemIndexAtPosition, key);
|
|
600
|
+
const { newItem: newItem, newIndex: newIndex } =
|
|
601
|
+
this._createAttachItemAndSort(op, key);
|
|
602
|
+
return {
|
|
603
|
+
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
604
|
+
reverse: [],
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
_applyInsertUndoRedo(op) {
|
|
610
|
+
var _a;
|
|
611
|
+
const { id: id, parentKey: key } = op,
|
|
612
|
+
child = creationOpToLiveNode(op);
|
|
613
|
+
if (
|
|
614
|
+
void 0 !==
|
|
615
|
+
(null === (_a = this._doc) || void 0 === _a ? void 0 : _a.getItem(id))
|
|
616
|
+
)
|
|
617
|
+
return { modified: !1 };
|
|
618
|
+
child._attach(id, nn(this._doc)), child._setParentLink(this, key);
|
|
619
|
+
const existingItemIndex = this._indexOfPosition(key);
|
|
620
|
+
let newKey = key;
|
|
621
|
+
if (-1 !== existingItemIndex) {
|
|
622
|
+
(newKey = makePosition(
|
|
623
|
+
this._items[existingItemIndex]
|
|
624
|
+
? this._items[existingItemIndex]._getParentKeyOrThrow()
|
|
625
|
+
: void 0,
|
|
626
|
+
this._items[existingItemIndex + 1]
|
|
627
|
+
? this._items[existingItemIndex + 1]._getParentKeyOrThrow()
|
|
628
|
+
: void 0
|
|
629
|
+
)),
|
|
630
|
+
child._setParentLink(this, newKey);
|
|
631
|
+
}
|
|
632
|
+
this._items.push(child), sortListItem(this._items);
|
|
633
|
+
return {
|
|
634
|
+
modified: makeUpdate(this, [
|
|
635
|
+
insertDelta(this._indexOfPosition(newKey), child),
|
|
636
|
+
]),
|
|
637
|
+
reverse: [{ type: OpCode.DELETE_CRDT, id: id }],
|
|
273
638
|
};
|
|
274
|
-
}
|
|
275
|
-
if (isLocal) {
|
|
276
|
-
const before = this._items[index] ? this._items[index][1] : void 0, after = this._items[index + 1] ? this._items[index + 1][1] : void 0;
|
|
277
|
-
newKey = makePosition(before, after), child._setParentLink(this, newKey);
|
|
278
|
-
} else this._items[index][1] = makePosition(key, null === (_a = this._items[index + 1]) || void 0 === _a ? void 0 : _a[1]);
|
|
279
|
-
}
|
|
280
|
-
this._items.push([ child, newKey ]), this._items.sort(((itemA, itemB) => comparePosition(itemA[1], itemB[1])));
|
|
281
|
-
const newIndex = this._items.findIndex((entry => entry[1] === newKey));
|
|
282
|
-
return {
|
|
283
|
-
reverse: [ {
|
|
284
|
-
type: OpCode.DELETE_CRDT,
|
|
285
|
-
id: id
|
|
286
|
-
} ],
|
|
287
|
-
modified: {
|
|
288
|
-
node: this,
|
|
289
|
-
type: "LiveList",
|
|
290
|
-
updates: [ {
|
|
291
|
-
index: newIndex,
|
|
292
|
-
type: "insert",
|
|
293
|
-
item: child instanceof LiveRegister ? child.data : child
|
|
294
|
-
} ]
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
_detachChild(child) {
|
|
299
|
-
if (child) {
|
|
300
|
-
const reverse = child._serialize(this._id, child._parentKey, this._doc), indexToDelete = this._items.findIndex((item => item[0] === child));
|
|
301
|
-
this._items.splice(indexToDelete, 1), child._detach();
|
|
302
|
-
return {
|
|
303
|
-
modified: {
|
|
304
|
-
node: this,
|
|
305
|
-
type: "LiveList",
|
|
306
|
-
updates: [ {
|
|
307
|
-
index: indexToDelete,
|
|
308
|
-
type: "delete"
|
|
309
|
-
} ]
|
|
310
|
-
},
|
|
311
|
-
reverse: reverse
|
|
312
|
-
};
|
|
313
639
|
}
|
|
640
|
+
_applySetUndoRedo(op) {
|
|
641
|
+
var _a;
|
|
642
|
+
const { id: id, parentKey: key } = op,
|
|
643
|
+
child = creationOpToLiveNode(op);
|
|
644
|
+
if (
|
|
645
|
+
void 0 !==
|
|
646
|
+
(null === (_a = this._doc) || void 0 === _a ? void 0 : _a.getItem(id))
|
|
647
|
+
)
|
|
648
|
+
return { modified: !1 };
|
|
649
|
+
this._unacknowledgedSets.set(key, nn(op.opId));
|
|
650
|
+
const indexOfItemWithSameKey = this._indexOfPosition(key);
|
|
651
|
+
child._attach(id, nn(this._doc)), child._setParentLink(this, key);
|
|
652
|
+
const newKey = key;
|
|
653
|
+
if (-1 !== indexOfItemWithSameKey) {
|
|
654
|
+
const existingItem = this._items[indexOfItemWithSameKey];
|
|
655
|
+
existingItem._detach(), (this._items[indexOfItemWithSameKey] = child);
|
|
656
|
+
const reverse = existingItem._serialize(nn(this._id), key, this._doc);
|
|
657
|
+
addIntentAndDeletedIdToOperation(reverse, op.id);
|
|
658
|
+
const delta = [setDelta(indexOfItemWithSameKey, child)],
|
|
659
|
+
deletedDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
660
|
+
return (
|
|
661
|
+
deletedDelta && delta.push(deletedDelta),
|
|
662
|
+
{ modified: makeUpdate(this, delta), reverse: reverse }
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
{
|
|
666
|
+
this._items.push(child),
|
|
667
|
+
sortListItem(this._items),
|
|
668
|
+
this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
669
|
+
const newIndex = this._indexOfPosition(newKey);
|
|
670
|
+
return {
|
|
671
|
+
reverse: [{ type: OpCode.DELETE_CRDT, id: id }],
|
|
672
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
_attachChild(op, source) {
|
|
677
|
+
if (null == this._doc)
|
|
678
|
+
throw new Error("Can't attach child if doc is not present");
|
|
679
|
+
if ("set" === op.intent) {
|
|
680
|
+
if (source === OpSource.REMOTE) return this._applySetRemote(op);
|
|
681
|
+
if (source === OpSource.UNDOREDO_RECONNECT)
|
|
682
|
+
return this._applySetUndoRedo(op);
|
|
683
|
+
if (source === OpSource.ACK) return this._applySetAck(op);
|
|
684
|
+
}
|
|
685
|
+
return source === OpSource.REMOTE
|
|
686
|
+
? this._applyRemoteInsert(op)
|
|
687
|
+
: source === OpSource.ACK
|
|
688
|
+
? this._applyInsertAck(op)
|
|
689
|
+
: this._applyInsertUndoRedo(op);
|
|
690
|
+
}
|
|
691
|
+
_detachChild(child) {
|
|
692
|
+
if (child) {
|
|
693
|
+
const parentKey = nn(child._parentKey),
|
|
694
|
+
reverse = child._serialize(nn(this._id), parentKey, this._doc),
|
|
695
|
+
indexToDelete = this._items.indexOf(child);
|
|
696
|
+
return (
|
|
697
|
+
this._items.splice(indexToDelete, 1),
|
|
698
|
+
child._detach(),
|
|
699
|
+
{
|
|
700
|
+
modified: makeUpdate(this, [deleteDelta(indexToDelete)]),
|
|
701
|
+
reverse: reverse,
|
|
702
|
+
}
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
return { modified: !1 };
|
|
706
|
+
}
|
|
707
|
+
_applySetChildKeyRemote(newKey, child) {
|
|
708
|
+
var _a;
|
|
709
|
+
if (this._implicitlyDeletedItems.has(child)) {
|
|
710
|
+
this._implicitlyDeletedItems.delete(child),
|
|
711
|
+
child._setParentLink(this, newKey),
|
|
712
|
+
this._items.push(child),
|
|
713
|
+
sortListItem(this._items);
|
|
714
|
+
return {
|
|
715
|
+
modified: makeUpdate(this, [
|
|
716
|
+
insertDelta(this._items.indexOf(child), child),
|
|
717
|
+
]),
|
|
718
|
+
reverse: [],
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
if (newKey === child._parentKey) return { modified: !1 };
|
|
722
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
723
|
+
if (-1 === existingItemIndex) {
|
|
724
|
+
const previousIndex = this._items.indexOf(child);
|
|
725
|
+
child._setParentLink(this, newKey), sortListItem(this._items);
|
|
726
|
+
const newIndex = this._items.indexOf(child);
|
|
727
|
+
return newIndex === previousIndex
|
|
728
|
+
? { modified: !1 }
|
|
729
|
+
: {
|
|
730
|
+
modified: makeUpdate(this, [
|
|
731
|
+
moveDelta(previousIndex, newIndex, child),
|
|
732
|
+
]),
|
|
733
|
+
reverse: [],
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
{
|
|
737
|
+
this._items[existingItemIndex]._setParentLink(
|
|
738
|
+
this,
|
|
739
|
+
makePosition(
|
|
740
|
+
newKey,
|
|
741
|
+
null === (_a = this._items[existingItemIndex + 1]) || void 0 === _a
|
|
742
|
+
? void 0
|
|
743
|
+
: _a._getParentKeyOrThrow()
|
|
744
|
+
)
|
|
745
|
+
);
|
|
746
|
+
const previousIndex = this._items.indexOf(child);
|
|
747
|
+
child._setParentLink(this, newKey), sortListItem(this._items);
|
|
748
|
+
const newIndex = this._items.indexOf(child);
|
|
749
|
+
return newIndex === previousIndex
|
|
750
|
+
? { modified: !1 }
|
|
751
|
+
: {
|
|
752
|
+
modified: makeUpdate(this, [
|
|
753
|
+
moveDelta(previousIndex, newIndex, child),
|
|
754
|
+
]),
|
|
755
|
+
reverse: [],
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
_applySetChildKeyAck(newKey, child) {
|
|
760
|
+
var _a, _b;
|
|
761
|
+
const previousKey = nn(child._parentKey);
|
|
762
|
+
if (this._implicitlyDeletedItems.has(child)) {
|
|
763
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
764
|
+
return (
|
|
765
|
+
this._implicitlyDeletedItems.delete(child),
|
|
766
|
+
-1 !== existingItemIndex &&
|
|
767
|
+
this._items[existingItemIndex]._setParentLink(
|
|
768
|
+
this,
|
|
769
|
+
makePosition(
|
|
770
|
+
newKey,
|
|
771
|
+
null === (_a = this._items[existingItemIndex + 1]) ||
|
|
772
|
+
void 0 === _a
|
|
773
|
+
? void 0
|
|
774
|
+
: _a._getParentKeyOrThrow()
|
|
775
|
+
)
|
|
776
|
+
),
|
|
777
|
+
child._setParentLink(this, newKey),
|
|
778
|
+
this._items.push(child),
|
|
779
|
+
sortListItem(this._items),
|
|
780
|
+
{ modified: !1 }
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
{
|
|
784
|
+
if (newKey === previousKey) return { modified: !1 };
|
|
785
|
+
const previousIndex = this._items.indexOf(child),
|
|
786
|
+
existingItemIndex = this._indexOfPosition(newKey);
|
|
787
|
+
-1 !== existingItemIndex &&
|
|
788
|
+
this._items[existingItemIndex]._setParentLink(
|
|
789
|
+
this,
|
|
790
|
+
makePosition(
|
|
791
|
+
newKey,
|
|
792
|
+
null === (_b = this._items[existingItemIndex + 1]) || void 0 === _b
|
|
793
|
+
? void 0
|
|
794
|
+
: _b._getParentKeyOrThrow()
|
|
795
|
+
)
|
|
796
|
+
),
|
|
797
|
+
child._setParentLink(this, newKey),
|
|
798
|
+
sortListItem(this._items);
|
|
799
|
+
const newIndex = this._items.indexOf(child);
|
|
800
|
+
return previousIndex === newIndex
|
|
801
|
+
? { modified: !1 }
|
|
802
|
+
: {
|
|
803
|
+
modified: makeUpdate(this, [
|
|
804
|
+
moveDelta(previousIndex, newIndex, child),
|
|
805
|
+
]),
|
|
806
|
+
reverse: [],
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
_applySetChildKeyUndoRedo(newKey, child) {
|
|
811
|
+
var _a;
|
|
812
|
+
const previousKey = nn(child._parentKey),
|
|
813
|
+
previousIndex = this._items.indexOf(child),
|
|
814
|
+
existingItemIndex = this._indexOfPosition(newKey);
|
|
815
|
+
-1 !== existingItemIndex &&
|
|
816
|
+
this._items[existingItemIndex]._setParentLink(
|
|
817
|
+
this,
|
|
818
|
+
makePosition(
|
|
819
|
+
newKey,
|
|
820
|
+
null === (_a = this._items[existingItemIndex + 1]) || void 0 === _a
|
|
821
|
+
? void 0
|
|
822
|
+
: _a._getParentKeyOrThrow()
|
|
823
|
+
)
|
|
824
|
+
),
|
|
825
|
+
child._setParentLink(this, newKey),
|
|
826
|
+
sortListItem(this._items);
|
|
827
|
+
const newIndex = this._items.indexOf(child);
|
|
828
|
+
return previousIndex === newIndex
|
|
829
|
+
? { modified: !1 }
|
|
830
|
+
: {
|
|
831
|
+
modified: makeUpdate(this, [
|
|
832
|
+
moveDelta(previousIndex, newIndex, child),
|
|
833
|
+
]),
|
|
834
|
+
reverse: [
|
|
835
|
+
{
|
|
836
|
+
type: OpCode.SET_PARENT_KEY,
|
|
837
|
+
id: nn(child._id),
|
|
838
|
+
parentKey: previousKey,
|
|
839
|
+
},
|
|
840
|
+
],
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
_setChildKey(newKey, child, source) {
|
|
844
|
+
return source === OpSource.REMOTE
|
|
845
|
+
? this._applySetChildKeyRemote(newKey, child)
|
|
846
|
+
: source === OpSource.ACK
|
|
847
|
+
? this._applySetChildKeyAck(newKey, child)
|
|
848
|
+
: this._applySetChildKeyUndoRedo(newKey, child);
|
|
849
|
+
}
|
|
850
|
+
_apply(op, isLocal) {
|
|
851
|
+
return super._apply(op, isLocal);
|
|
852
|
+
}
|
|
853
|
+
_toSerializedCrdt() {
|
|
854
|
+
if ("HasParent" !== this.parent.type)
|
|
855
|
+
throw new Error("Cannot serialize LiveList if parent is missing");
|
|
856
|
+
return {
|
|
857
|
+
type: CrdtType.LIST,
|
|
858
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
859
|
+
parentKey: this.parent.key,
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
get length() {
|
|
863
|
+
return this._items.length;
|
|
864
|
+
}
|
|
865
|
+
push(element) {
|
|
866
|
+
return this.insert(element, this.length);
|
|
867
|
+
}
|
|
868
|
+
insert(element, index) {
|
|
869
|
+
if (index < 0 || index > this._items.length)
|
|
870
|
+
throw new Error(
|
|
871
|
+
`Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
|
|
872
|
+
);
|
|
873
|
+
const position = makePosition(
|
|
874
|
+
this._items[index - 1]
|
|
875
|
+
? this._items[index - 1]._getParentKeyOrThrow()
|
|
876
|
+
: void 0,
|
|
877
|
+
this._items[index] ? this._items[index]._getParentKeyOrThrow() : void 0
|
|
878
|
+
),
|
|
879
|
+
value = lsonToLiveNode(element);
|
|
880
|
+
if (
|
|
881
|
+
(value._setParentLink(this, position),
|
|
882
|
+
this._items.push(value),
|
|
883
|
+
sortListItem(this._items),
|
|
884
|
+
this._doc && this._id)
|
|
885
|
+
) {
|
|
886
|
+
const id = this._doc.generateId();
|
|
887
|
+
value._attach(id, this._doc),
|
|
888
|
+
this._doc.dispatch(
|
|
889
|
+
value._serialize(this._id, position, this._doc),
|
|
890
|
+
[{ type: OpCode.DELETE_CRDT, id: id }],
|
|
891
|
+
new Map([[this._id, makeUpdate(this, [insertDelta(index, value)])]])
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
move(index, targetIndex) {
|
|
896
|
+
if (targetIndex < 0) throw new Error("targetIndex cannot be less than 0");
|
|
897
|
+
if (targetIndex >= this._items.length)
|
|
898
|
+
throw new Error(
|
|
899
|
+
"targetIndex cannot be greater or equal than the list length"
|
|
900
|
+
);
|
|
901
|
+
if (index < 0) throw new Error("index cannot be less than 0");
|
|
902
|
+
if (index >= this._items.length)
|
|
903
|
+
throw new Error("index cannot be greater or equal than the list length");
|
|
904
|
+
let beforePosition = null,
|
|
905
|
+
afterPosition = null;
|
|
906
|
+
index < targetIndex
|
|
907
|
+
? ((afterPosition =
|
|
908
|
+
targetIndex === this._items.length - 1
|
|
909
|
+
? void 0
|
|
910
|
+
: this._items[targetIndex + 1]._getParentKeyOrThrow()),
|
|
911
|
+
(beforePosition = this._items[targetIndex]._getParentKeyOrThrow()))
|
|
912
|
+
: ((afterPosition = this._items[targetIndex]._getParentKeyOrThrow()),
|
|
913
|
+
(beforePosition =
|
|
914
|
+
0 === targetIndex
|
|
915
|
+
? void 0
|
|
916
|
+
: this._items[targetIndex - 1]._getParentKeyOrThrow()));
|
|
917
|
+
const position = makePosition(beforePosition, afterPosition),
|
|
918
|
+
item = this._items[index],
|
|
919
|
+
previousPosition = item._getParentKeyOrThrow();
|
|
920
|
+
if (
|
|
921
|
+
(item._setParentLink(this, position),
|
|
922
|
+
sortListItem(this._items),
|
|
923
|
+
this._doc && this._id)
|
|
924
|
+
) {
|
|
925
|
+
const storageUpdates = new Map([
|
|
926
|
+
[this._id, makeUpdate(this, [moveDelta(index, targetIndex, item)])],
|
|
927
|
+
]);
|
|
928
|
+
this._doc.dispatch(
|
|
929
|
+
[
|
|
930
|
+
{
|
|
931
|
+
type: OpCode.SET_PARENT_KEY,
|
|
932
|
+
id: nn(item._id),
|
|
933
|
+
opId: this._doc.generateOpId(),
|
|
934
|
+
parentKey: position,
|
|
935
|
+
},
|
|
936
|
+
],
|
|
937
|
+
[
|
|
938
|
+
{
|
|
939
|
+
type: OpCode.SET_PARENT_KEY,
|
|
940
|
+
id: nn(item._id),
|
|
941
|
+
parentKey: previousPosition,
|
|
942
|
+
},
|
|
943
|
+
],
|
|
944
|
+
storageUpdates
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
delete(index) {
|
|
949
|
+
if (index < 0 || index >= this._items.length)
|
|
950
|
+
throw new Error(
|
|
951
|
+
`Cannot delete list item at index "${index}". index should be between 0 and ${
|
|
952
|
+
this._items.length - 1
|
|
953
|
+
}`
|
|
954
|
+
);
|
|
955
|
+
const item = this._items[index];
|
|
956
|
+
if ((item._detach(), this._items.splice(index, 1), this._doc)) {
|
|
957
|
+
const childRecordId = item._id;
|
|
958
|
+
if (childRecordId) {
|
|
959
|
+
const storageUpdates = new Map();
|
|
960
|
+
storageUpdates.set(
|
|
961
|
+
nn(this._id),
|
|
962
|
+
makeUpdate(this, [deleteDelta(index)])
|
|
963
|
+
),
|
|
964
|
+
this._doc.dispatch(
|
|
965
|
+
[
|
|
966
|
+
{
|
|
967
|
+
id: childRecordId,
|
|
968
|
+
opId: this._doc.generateOpId(),
|
|
969
|
+
type: OpCode.DELETE_CRDT,
|
|
970
|
+
},
|
|
971
|
+
],
|
|
972
|
+
item._serialize(nn(this._id), item._getParentKeyOrThrow()),
|
|
973
|
+
storageUpdates
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
clear() {
|
|
979
|
+
if (this._doc) {
|
|
980
|
+
const ops = [],
|
|
981
|
+
reverseOps = [],
|
|
982
|
+
updateDelta = [];
|
|
983
|
+
for (const item of this._items) {
|
|
984
|
+
item._detach();
|
|
985
|
+
const childId = item._id;
|
|
986
|
+
childId &&
|
|
987
|
+
(ops.push({
|
|
988
|
+
type: OpCode.DELETE_CRDT,
|
|
989
|
+
id: childId,
|
|
990
|
+
opId: this._doc.generateOpId(),
|
|
991
|
+
}),
|
|
992
|
+
reverseOps.push(
|
|
993
|
+
...item._serialize(nn(this._id), item._getParentKeyOrThrow())
|
|
994
|
+
),
|
|
995
|
+
updateDelta.push(deleteDelta(0)));
|
|
996
|
+
}
|
|
997
|
+
this._items = [];
|
|
998
|
+
const storageUpdates = new Map();
|
|
999
|
+
storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta)),
|
|
1000
|
+
this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
1001
|
+
} else {
|
|
1002
|
+
for (const item of this._items) item._detach();
|
|
1003
|
+
this._items = [];
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
set(index, item) {
|
|
1007
|
+
if (index < 0 || index >= this._items.length)
|
|
1008
|
+
throw new Error(
|
|
1009
|
+
`Cannot set list item at index "${index}". index should be between 0 and ${
|
|
1010
|
+
this._items.length - 1
|
|
1011
|
+
}`
|
|
1012
|
+
);
|
|
1013
|
+
const existingItem = this._items[index],
|
|
1014
|
+
position = existingItem._getParentKeyOrThrow(),
|
|
1015
|
+
existingId = existingItem._id;
|
|
1016
|
+
existingItem._detach();
|
|
1017
|
+
const value = lsonToLiveNode(item);
|
|
1018
|
+
if (
|
|
1019
|
+
(value._setParentLink(this, position),
|
|
1020
|
+
(this._items[index] = value),
|
|
1021
|
+
this._doc && this._id)
|
|
1022
|
+
) {
|
|
1023
|
+
const id = this._doc.generateId();
|
|
1024
|
+
value._attach(id, this._doc);
|
|
1025
|
+
const storageUpdates = new Map();
|
|
1026
|
+
storageUpdates.set(this._id, makeUpdate(this, [setDelta(index, value)]));
|
|
1027
|
+
const ops = value._serialize(this._id, position, this._doc);
|
|
1028
|
+
addIntentAndDeletedIdToOperation(ops, existingId),
|
|
1029
|
+
this._unacknowledgedSets.set(position, nn(ops[0].opId));
|
|
1030
|
+
const reverseOps = existingItem._serialize(this._id, position, void 0);
|
|
1031
|
+
addIntentAndDeletedIdToOperation(reverseOps, id),
|
|
1032
|
+
this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
toArray() {
|
|
1036
|
+
return this._items.map((entry) => liveNodeToLson(entry));
|
|
1037
|
+
}
|
|
1038
|
+
every(predicate) {
|
|
1039
|
+
return this.toArray().every(predicate);
|
|
1040
|
+
}
|
|
1041
|
+
filter(predicate) {
|
|
1042
|
+
return this.toArray().filter(predicate);
|
|
1043
|
+
}
|
|
1044
|
+
find(predicate) {
|
|
1045
|
+
return this.toArray().find(predicate);
|
|
1046
|
+
}
|
|
1047
|
+
findIndex(predicate) {
|
|
1048
|
+
return this.toArray().findIndex(predicate);
|
|
1049
|
+
}
|
|
1050
|
+
forEach(callbackfn) {
|
|
1051
|
+
return this.toArray().forEach(callbackfn);
|
|
1052
|
+
}
|
|
1053
|
+
get(index) {
|
|
1054
|
+
if (!(index < 0 || index >= this._items.length))
|
|
1055
|
+
return liveNodeToLson(this._items[index]);
|
|
1056
|
+
}
|
|
1057
|
+
indexOf(searchElement, fromIndex) {
|
|
1058
|
+
return this.toArray().indexOf(searchElement, fromIndex);
|
|
1059
|
+
}
|
|
1060
|
+
lastIndexOf(searchElement, fromIndex) {
|
|
1061
|
+
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
1062
|
+
}
|
|
1063
|
+
map(callback) {
|
|
1064
|
+
return this._items.map((entry, i) => callback(liveNodeToLson(entry), i));
|
|
1065
|
+
}
|
|
1066
|
+
some(predicate) {
|
|
1067
|
+
return this.toArray().some(predicate);
|
|
1068
|
+
}
|
|
1069
|
+
[Symbol.iterator]() {
|
|
1070
|
+
return new LiveListIterator(this._items);
|
|
1071
|
+
}
|
|
1072
|
+
_createAttachItemAndSort(op, key) {
|
|
1073
|
+
const newItem = creationOpToLiveNode(op);
|
|
1074
|
+
newItem._attach(op.id, nn(this._doc)),
|
|
1075
|
+
newItem._setParentLink(this, key),
|
|
1076
|
+
this._items.push(newItem),
|
|
1077
|
+
sortListItem(this._items);
|
|
1078
|
+
return { newItem: newItem, newIndex: this._indexOfPosition(key) };
|
|
1079
|
+
}
|
|
1080
|
+
_shiftItemPosition(index, key) {
|
|
1081
|
+
var _a;
|
|
1082
|
+
const shiftedPosition = makePosition(
|
|
1083
|
+
key,
|
|
1084
|
+
this._items.length > index + 1
|
|
1085
|
+
? null === (_a = this._items[index + 1]) || void 0 === _a
|
|
1086
|
+
? void 0
|
|
1087
|
+
: _a._getParentKeyOrThrow()
|
|
1088
|
+
: void 0
|
|
1089
|
+
);
|
|
1090
|
+
this._items[index]._setParentLink(this, shiftedPosition);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
class LiveListIterator {
|
|
1094
|
+
constructor(items) {
|
|
1095
|
+
this._innerIterator = items[Symbol.iterator]();
|
|
1096
|
+
}
|
|
1097
|
+
[Symbol.iterator]() {
|
|
1098
|
+
return this;
|
|
1099
|
+
}
|
|
1100
|
+
next() {
|
|
1101
|
+
const result = this._innerIterator.next();
|
|
1102
|
+
if (result.done) return { done: !0, value: void 0 };
|
|
1103
|
+
return { value: liveNodeToLson(result.value) };
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
function makeUpdate(liveList, deltaUpdates) {
|
|
1107
|
+
return { node: liveList, type: "LiveList", updates: deltaUpdates };
|
|
1108
|
+
}
|
|
1109
|
+
function setDelta(index, item) {
|
|
314
1110
|
return {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
_setChildKey(key, child, previousKey) {
|
|
319
|
-
var _a;
|
|
320
|
-
child._setParentLink(this, key);
|
|
321
|
-
const previousIndex = this._items.findIndex((entry => entry[0]._id === child._id)), index = this._items.findIndex((entry => entry[1] === key));
|
|
322
|
-
-1 !== index && (this._items[index][1] = makePosition(key, null === (_a = this._items[index + 1]) || void 0 === _a ? void 0 : _a[1]));
|
|
323
|
-
const item = this._items.find((item => item[0] === child));
|
|
324
|
-
item && (item[1] = key), this._items.sort(((itemA, itemB) => comparePosition(itemA[1], itemB[1])));
|
|
325
|
-
const newIndex = this._items.findIndex((entry => entry[0]._id === child._id));
|
|
326
|
-
return {
|
|
327
|
-
modified: {
|
|
328
|
-
node: this,
|
|
329
|
-
type: "LiveList",
|
|
330
|
-
updates: newIndex === previousIndex ? [] : [ {
|
|
331
|
-
index: newIndex,
|
|
332
|
-
item: child instanceof LiveRegister ? child.data : child,
|
|
333
|
-
previousIndex: previousIndex,
|
|
334
|
-
type: "move"
|
|
335
|
-
} ]
|
|
336
|
-
},
|
|
337
|
-
reverse: [ {
|
|
338
|
-
type: OpCode.SET_PARENT_KEY,
|
|
339
|
-
id: null == item ? void 0 : item[0]._id,
|
|
340
|
-
parentKey: previousKey
|
|
341
|
-
} ]
|
|
1111
|
+
index: index,
|
|
1112
|
+
type: "set",
|
|
1113
|
+
item: item instanceof LiveRegister ? item.data : item,
|
|
342
1114
|
};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
var _a;
|
|
1115
|
+
}
|
|
1116
|
+
function deleteDelta(index) {
|
|
1117
|
+
return { index: index, type: "delete" };
|
|
1118
|
+
}
|
|
1119
|
+
function insertDelta(index, item) {
|
|
349
1120
|
return {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
1121
|
+
index: index,
|
|
1122
|
+
type: "insert",
|
|
1123
|
+
item: item instanceof LiveRegister ? item.data : item,
|
|
353
1124
|
};
|
|
354
|
-
}
|
|
355
|
-
get length() {
|
|
356
|
-
return this._items.length;
|
|
357
|
-
}
|
|
358
|
-
push(element) {
|
|
359
|
-
return this.insert(element, this.length);
|
|
360
|
-
}
|
|
361
|
-
insert(element, index) {
|
|
362
|
-
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}`);
|
|
363
|
-
const position = makePosition(this._items[index - 1] ? this._items[index - 1][1] : void 0, this._items[index] ? this._items[index][1] : void 0), value = selfOrRegister(element);
|
|
364
|
-
value._setParentLink(this, position), this._items.push([ value, position ]), this._items.sort(((itemA, itemB) => comparePosition(itemA[1], itemB[1])));
|
|
365
|
-
const newIndex = this._items.findIndex((entry => entry[1] === position));
|
|
366
|
-
if (this._doc && this._id) {
|
|
367
|
-
const id = this._doc.generateId();
|
|
368
|
-
value._attach(id, this._doc);
|
|
369
|
-
const storageUpdates = new Map;
|
|
370
|
-
storageUpdates.set(this._id, {
|
|
371
|
-
node: this,
|
|
372
|
-
type: "LiveList",
|
|
373
|
-
updates: [ {
|
|
374
|
-
index: newIndex,
|
|
375
|
-
item: value instanceof LiveRegister ? value.data : value,
|
|
376
|
-
type: "insert"
|
|
377
|
-
} ]
|
|
378
|
-
}), this._doc.dispatch(value._serialize(this._id, position, this._doc), [ {
|
|
379
|
-
type: OpCode.DELETE_CRDT,
|
|
380
|
-
id: id
|
|
381
|
-
} ], storageUpdates);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
move(index, targetIndex) {
|
|
385
|
-
if (targetIndex < 0) throw new Error("targetIndex cannot be less than 0");
|
|
386
|
-
if (targetIndex >= this._items.length) throw new Error("targetIndex cannot be greater or equal than the list length");
|
|
387
|
-
if (index < 0) throw new Error("index cannot be less than 0");
|
|
388
|
-
if (index >= this._items.length) throw new Error("index cannot be greater or equal than the list length");
|
|
389
|
-
let beforePosition = null, afterPosition = null;
|
|
390
|
-
index < targetIndex ? (afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1][1],
|
|
391
|
-
beforePosition = this._items[targetIndex][1]) : (afterPosition = this._items[targetIndex][1],
|
|
392
|
-
beforePosition = 0 === targetIndex ? void 0 : this._items[targetIndex - 1][1]);
|
|
393
|
-
const position = makePosition(beforePosition, afterPosition), item = this._items[index], previousPosition = item[1];
|
|
394
|
-
item[1] = position, item[0]._setParentLink(this, position), this._items.sort(((itemA, itemB) => comparePosition(itemA[1], itemB[1])));
|
|
395
|
-
const newIndex = this._items.findIndex((entry => entry[1] === position));
|
|
396
|
-
if (this._doc && this._id) {
|
|
397
|
-
const storageUpdates = new Map;
|
|
398
|
-
storageUpdates.set(this._id, {
|
|
399
|
-
node: this,
|
|
400
|
-
type: "LiveList",
|
|
401
|
-
updates: [ {
|
|
402
|
-
index: newIndex,
|
|
403
|
-
previousIndex: index,
|
|
404
|
-
item: item[0],
|
|
405
|
-
type: "move"
|
|
406
|
-
} ]
|
|
407
|
-
}), this._doc.dispatch([ {
|
|
408
|
-
type: OpCode.SET_PARENT_KEY,
|
|
409
|
-
id: item[0]._id,
|
|
410
|
-
opId: this._doc.generateOpId(),
|
|
411
|
-
parentKey: position
|
|
412
|
-
} ], [ {
|
|
413
|
-
type: OpCode.SET_PARENT_KEY,
|
|
414
|
-
id: item[0]._id,
|
|
415
|
-
parentKey: previousPosition
|
|
416
|
-
} ], storageUpdates);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
delete(index) {
|
|
420
|
-
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}`);
|
|
421
|
-
const item = this._items[index];
|
|
422
|
-
if (item[0]._detach(), this._items.splice(index, 1), this._doc) {
|
|
423
|
-
const childRecordId = item[0]._id;
|
|
424
|
-
if (childRecordId) {
|
|
425
|
-
const storageUpdates = new Map;
|
|
426
|
-
storageUpdates.set(this._id, {
|
|
427
|
-
node: this,
|
|
428
|
-
type: "LiveList",
|
|
429
|
-
updates: [ {
|
|
430
|
-
index: index,
|
|
431
|
-
type: "delete"
|
|
432
|
-
} ]
|
|
433
|
-
}), this._doc.dispatch([ {
|
|
434
|
-
id: childRecordId,
|
|
435
|
-
opId: this._doc.generateOpId(),
|
|
436
|
-
type: OpCode.DELETE_CRDT
|
|
437
|
-
} ], item[0]._serialize(this._id, item[1]), storageUpdates);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
clear() {
|
|
442
|
-
if (this._doc) {
|
|
443
|
-
const ops = [], reverseOps = [], updateDelta = [];
|
|
444
|
-
let i = 0;
|
|
445
|
-
for (const item of this._items) {
|
|
446
|
-
item[0]._detach();
|
|
447
|
-
const childId = item[0]._id;
|
|
448
|
-
childId && (ops.push({
|
|
449
|
-
id: childId,
|
|
450
|
-
type: OpCode.DELETE_CRDT
|
|
451
|
-
}), reverseOps.push(...item[0]._serialize(this._id, item[1])), updateDelta.push({
|
|
452
|
-
index: i,
|
|
453
|
-
type: "delete"
|
|
454
|
-
})), i++;
|
|
455
|
-
}
|
|
456
|
-
this._items = [];
|
|
457
|
-
const storageUpdates = new Map;
|
|
458
|
-
storageUpdates.set(this._id, {
|
|
459
|
-
node: this,
|
|
460
|
-
type: "LiveList",
|
|
461
|
-
updates: updateDelta
|
|
462
|
-
}), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
463
|
-
} else {
|
|
464
|
-
for (const item of this._items) item[0]._detach();
|
|
465
|
-
this._items = [];
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
set(index, item) {
|
|
469
|
-
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}`);
|
|
470
|
-
const [existingItem, position] = this._items[index];
|
|
471
|
-
existingItem._detach();
|
|
472
|
-
const value = selfOrRegister(item);
|
|
473
|
-
if (value._setParentLink(this, position), this._items[index][0] = value, this._doc && this._id) {
|
|
474
|
-
const id = this._doc.generateId();
|
|
475
|
-
value._attach(id, this._doc);
|
|
476
|
-
const storageUpdates = new Map;
|
|
477
|
-
storageUpdates.set(this._id, {
|
|
478
|
-
node: this,
|
|
479
|
-
type: "LiveList",
|
|
480
|
-
updates: [ {
|
|
481
|
-
index: index,
|
|
482
|
-
item: value instanceof LiveRegister ? value.data : value,
|
|
483
|
-
type: "set"
|
|
484
|
-
} ]
|
|
485
|
-
}), this._doc.dispatch(value._serialize(this._id, position, this._doc, "set"), existingItem._serialize(this._id, position, void 0, "set"), storageUpdates);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
toArray() {
|
|
489
|
-
return this._items.map((entry => selfOrRegisterValue(entry[0])));
|
|
490
|
-
}
|
|
491
|
-
every(predicate) {
|
|
492
|
-
return this.toArray().every(predicate);
|
|
493
|
-
}
|
|
494
|
-
filter(predicate) {
|
|
495
|
-
return this.toArray().filter(predicate);
|
|
496
|
-
}
|
|
497
|
-
find(predicate) {
|
|
498
|
-
return this.toArray().find(predicate);
|
|
499
|
-
}
|
|
500
|
-
findIndex(predicate) {
|
|
501
|
-
return this.toArray().findIndex(predicate);
|
|
502
|
-
}
|
|
503
|
-
forEach(callbackfn) {
|
|
504
|
-
return this.toArray().forEach(callbackfn);
|
|
505
|
-
}
|
|
506
|
-
get(index) {
|
|
507
|
-
if (!(index < 0 || index >= this._items.length)) return selfOrRegisterValue(this._items[index][0]);
|
|
508
|
-
}
|
|
509
|
-
indexOf(searchElement, fromIndex) {
|
|
510
|
-
return this.toArray().indexOf(searchElement, fromIndex);
|
|
511
|
-
}
|
|
512
|
-
lastIndexOf(searchElement, fromIndex) {
|
|
513
|
-
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
514
|
-
}
|
|
515
|
-
map(callback) {
|
|
516
|
-
return this._items.map(((entry, i) => callback(selfOrRegisterValue(entry[0]), i)));
|
|
517
|
-
}
|
|
518
|
-
some(predicate) {
|
|
519
|
-
return this.toArray().some(predicate);
|
|
520
|
-
}
|
|
521
|
-
[Symbol.iterator]() {
|
|
522
|
-
return new LiveListIterator(this._items);
|
|
523
|
-
}
|
|
524
1125
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return this;
|
|
532
|
-
}
|
|
533
|
-
next() {
|
|
534
|
-
const result = this._innerIterator.next();
|
|
535
|
-
return result.done ? {
|
|
536
|
-
done: !0,
|
|
537
|
-
value: void 0
|
|
538
|
-
} : {
|
|
539
|
-
value: selfOrRegisterValue(result.value[0])
|
|
1126
|
+
function moveDelta(previousIndex, index, item) {
|
|
1127
|
+
return {
|
|
1128
|
+
index: index,
|
|
1129
|
+
type: "move",
|
|
1130
|
+
previousIndex: previousIndex,
|
|
1131
|
+
item: item instanceof LiveRegister ? item.data : item,
|
|
540
1132
|
};
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
const _emittedDeprecationWarnings = new Set;
|
|
545
|
-
|
|
546
|
-
function deprecate(message, key = message) {
|
|
547
|
-
"production" !== process.env.NODE_ENV && (_emittedDeprecationWarnings.has(key) || (_emittedDeprecationWarnings.add(key),
|
|
548
|
-
console.error(`DEPRECATION WARNING: ${message}`)));
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
function deprecateIf(condition, message, key = message) {
|
|
552
|
-
"production" !== process.env.NODE_ENV && condition && deprecate(message, key);
|
|
553
1133
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
throw usageError.name = "Usage error", usageError;
|
|
559
|
-
}
|
|
1134
|
+
function sortListItem(items) {
|
|
1135
|
+
items.sort((itemA, itemB) =>
|
|
1136
|
+
comparePosition(itemA._getParentKeyOrThrow(), itemB._getParentKeyOrThrow())
|
|
1137
|
+
);
|
|
560
1138
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
1139
|
+
function addIntentAndDeletedIdToOperation(ops, deletedId) {
|
|
1140
|
+
if (0 === ops.length)
|
|
1141
|
+
throw new Error(
|
|
1142
|
+
"Internal error. Serialized LiveStructure should have at least 1 operation"
|
|
1143
|
+
);
|
|
1144
|
+
const firstOp = ops[0];
|
|
1145
|
+
(firstOp.intent = "set"), (firstOp.deletedId = deletedId);
|
|
564
1146
|
}
|
|
565
|
-
|
|
566
1147
|
class LiveMap extends AbstractCrdt {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
_attachChild(op, _isLocal) {
|
|
611
|
-
if (null == this._doc) throw new Error("Can't attach child if doc is not present");
|
|
612
|
-
const {id: id, parentKey: parentKey} = op, key = parentKey, child = creationOpToLiveStructure(op);
|
|
613
|
-
if (void 0 !== this._doc.getItem(id)) return {
|
|
614
|
-
modified: !1
|
|
615
|
-
};
|
|
616
|
-
const previousValue = this._map.get(key);
|
|
617
|
-
let reverse;
|
|
618
|
-
return previousValue ? (reverse = previousValue._serialize(this._id, key), previousValue._detach()) : reverse = [ {
|
|
619
|
-
type: OpCode.DELETE_CRDT,
|
|
620
|
-
id: id
|
|
621
|
-
} ], child._setParentLink(this, key), child._attach(id, this._doc), this._map.set(key, child),
|
|
622
|
-
{
|
|
623
|
-
modified: {
|
|
624
|
-
node: this,
|
|
625
|
-
type: "LiveMap",
|
|
626
|
-
updates: {
|
|
627
|
-
[key]: {
|
|
628
|
-
type: "update"
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
},
|
|
632
|
-
reverse: reverse
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
_detach() {
|
|
636
|
-
super._detach();
|
|
637
|
-
for (const item of this._map.values()) item._detach();
|
|
638
|
-
}
|
|
639
|
-
_detachChild(child) {
|
|
640
|
-
const reverse = child._serialize(this._id, child._parentKey, this._doc);
|
|
641
|
-
for (const [key, value] of this._map) value === child && this._map.delete(key);
|
|
642
|
-
child._detach();
|
|
643
|
-
return {
|
|
644
|
-
modified: {
|
|
645
|
-
node: this,
|
|
646
|
-
type: "LiveMap",
|
|
647
|
-
updates: {
|
|
648
|
-
[child._parentKey]: {
|
|
649
|
-
type: "delete"
|
|
650
|
-
}
|
|
1148
|
+
constructor(entries) {
|
|
1149
|
+
if (
|
|
1150
|
+
(super(),
|
|
1151
|
+
errorIf(
|
|
1152
|
+
null === entries,
|
|
1153
|
+
"Support for calling `new LiveMap(null)` will be removed in @liveblocks/client 0.18. Please call as `new LiveMap()`, or `new LiveMap([])`."
|
|
1154
|
+
),
|
|
1155
|
+
entries)
|
|
1156
|
+
) {
|
|
1157
|
+
const mappedEntries = [];
|
|
1158
|
+
for (const entry of entries) {
|
|
1159
|
+
const value = lsonToLiveNode(entry[1]);
|
|
1160
|
+
value._setParentLink(this, entry[0]),
|
|
1161
|
+
mappedEntries.push([entry[0], value]);
|
|
1162
|
+
}
|
|
1163
|
+
this._map = new Map(mappedEntries);
|
|
1164
|
+
} else this._map = new Map();
|
|
1165
|
+
}
|
|
1166
|
+
_serialize(parentId, parentKey, doc) {
|
|
1167
|
+
if (null == this._id)
|
|
1168
|
+
throw new Error("Cannot serialize item is not attached");
|
|
1169
|
+
const ops = [],
|
|
1170
|
+
op = {
|
|
1171
|
+
id: this._id,
|
|
1172
|
+
opId: null == doc ? void 0 : doc.generateOpId(),
|
|
1173
|
+
type: OpCode.CREATE_MAP,
|
|
1174
|
+
parentId: parentId,
|
|
1175
|
+
parentKey: parentKey,
|
|
1176
|
+
};
|
|
1177
|
+
ops.push(op);
|
|
1178
|
+
for (const [key, value] of this._map)
|
|
1179
|
+
ops.push(...value._serialize(this._id, key, doc));
|
|
1180
|
+
return ops;
|
|
1181
|
+
}
|
|
1182
|
+
static _deserialize([id, _item], parentToChildren, doc) {
|
|
1183
|
+
const map = new LiveMap();
|
|
1184
|
+
map._attach(id, doc);
|
|
1185
|
+
const children = parentToChildren.get(id);
|
|
1186
|
+
if (null == children) return map;
|
|
1187
|
+
for (const [id, crdt] of children) {
|
|
1188
|
+
const child = deserialize([id, crdt], parentToChildren, doc);
|
|
1189
|
+
child._setParentLink(map, crdt.parentKey),
|
|
1190
|
+
map._map.set(crdt.parentKey, child);
|
|
651
1191
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
1192
|
+
return map;
|
|
1193
|
+
}
|
|
1194
|
+
_attach(id, doc) {
|
|
1195
|
+
super._attach(id, doc);
|
|
1196
|
+
for (const [_key, value] of this._map)
|
|
1197
|
+
isLiveNode(value) && value._attach(doc.generateId(), doc);
|
|
1198
|
+
}
|
|
1199
|
+
_attachChild(op) {
|
|
1200
|
+
if (null == this._doc)
|
|
1201
|
+
throw new Error("Can't attach child if doc is not present");
|
|
1202
|
+
const { id: id, parentKey: key } = op,
|
|
1203
|
+
child = creationOpToLiveNode(op);
|
|
1204
|
+
if (void 0 !== this._doc.getItem(id)) return { modified: !1 };
|
|
1205
|
+
const previousValue = this._map.get(key);
|
|
1206
|
+
let reverse;
|
|
1207
|
+
if (previousValue) {
|
|
1208
|
+
const thisId = nn(this._id);
|
|
1209
|
+
(reverse = previousValue._serialize(thisId, key)),
|
|
1210
|
+
previousValue._detach();
|
|
1211
|
+
} else reverse = [{ type: OpCode.DELETE_CRDT, id: id }];
|
|
1212
|
+
return (
|
|
1213
|
+
child._setParentLink(this, key),
|
|
1214
|
+
child._attach(id, this._doc),
|
|
1215
|
+
this._map.set(key, child),
|
|
1216
|
+
{
|
|
1217
|
+
modified: {
|
|
1218
|
+
node: this,
|
|
1219
|
+
type: "LiveMap",
|
|
1220
|
+
updates: { [key]: { type: "update" } },
|
|
1221
|
+
},
|
|
1222
|
+
reverse: reverse,
|
|
1223
|
+
}
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
_detach() {
|
|
1227
|
+
super._detach();
|
|
1228
|
+
for (const item of this._map.values()) item._detach();
|
|
1229
|
+
}
|
|
1230
|
+
_detachChild(child) {
|
|
1231
|
+
const id = nn(this._id),
|
|
1232
|
+
parentKey = nn(child._parentKey),
|
|
1233
|
+
reverse = child._serialize(id, parentKey, this._doc);
|
|
1234
|
+
for (const [key, value] of this._map)
|
|
1235
|
+
value === child && this._map.delete(key);
|
|
1236
|
+
child._detach();
|
|
1237
|
+
return {
|
|
1238
|
+
modified: {
|
|
1239
|
+
node: this,
|
|
1240
|
+
type: "LiveMap",
|
|
1241
|
+
updates: { [parentKey]: { type: "delete" } },
|
|
1242
|
+
},
|
|
1243
|
+
reverse: reverse,
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
_toSerializedCrdt() {
|
|
1247
|
+
if ("HasParent" !== this.parent.type)
|
|
1248
|
+
throw new Error("Cannot serialize LiveMap if parent is missing");
|
|
1249
|
+
return {
|
|
1250
|
+
type: CrdtType.MAP,
|
|
1251
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
1252
|
+
parentKey: this.parent.key,
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
get(key) {
|
|
1256
|
+
const value = this._map.get(key);
|
|
1257
|
+
if (null != value) return liveNodeToLson(value);
|
|
1258
|
+
}
|
|
1259
|
+
set(key, value) {
|
|
1260
|
+
const oldValue = this._map.get(key);
|
|
1261
|
+
oldValue && oldValue._detach();
|
|
1262
|
+
const item = lsonToLiveNode(value);
|
|
1263
|
+
if (
|
|
1264
|
+
(item._setParentLink(this, key),
|
|
1265
|
+
this._map.set(key, item),
|
|
1266
|
+
this._doc && this._id)
|
|
1267
|
+
) {
|
|
1268
|
+
const id = this._doc.generateId();
|
|
1269
|
+
item._attach(id, this._doc);
|
|
1270
|
+
const storageUpdates = new Map();
|
|
1271
|
+
storageUpdates.set(this._id, {
|
|
1272
|
+
node: this,
|
|
1273
|
+
type: "LiveMap",
|
|
1274
|
+
updates: { [key]: { type: "update" } },
|
|
1275
|
+
}),
|
|
1276
|
+
this._doc.dispatch(
|
|
1277
|
+
item._serialize(this._id, key, this._doc),
|
|
1278
|
+
oldValue
|
|
1279
|
+
? oldValue._serialize(this._id, key)
|
|
1280
|
+
: [{ type: OpCode.DELETE_CRDT, id: id }],
|
|
1281
|
+
storageUpdates
|
|
1282
|
+
);
|
|
683
1283
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
1284
|
+
}
|
|
1285
|
+
get size() {
|
|
1286
|
+
return this._map.size;
|
|
1287
|
+
}
|
|
1288
|
+
has(key) {
|
|
1289
|
+
return this._map.has(key);
|
|
1290
|
+
}
|
|
1291
|
+
delete(key) {
|
|
1292
|
+
const item = this._map.get(key);
|
|
1293
|
+
if (null == item) return !1;
|
|
1294
|
+
if ((item._detach(), this._map.delete(key), this._doc && item._id)) {
|
|
1295
|
+
const thisId = nn(this._id),
|
|
1296
|
+
storageUpdates = new Map();
|
|
1297
|
+
storageUpdates.set(thisId, {
|
|
1298
|
+
node: this,
|
|
1299
|
+
type: "LiveMap",
|
|
1300
|
+
updates: { [key]: { type: "delete" } },
|
|
1301
|
+
}),
|
|
1302
|
+
this._doc.dispatch(
|
|
1303
|
+
[
|
|
1304
|
+
{
|
|
1305
|
+
type: OpCode.DELETE_CRDT,
|
|
1306
|
+
id: item._id,
|
|
1307
|
+
opId: this._doc.generateOpId(),
|
|
1308
|
+
},
|
|
1309
|
+
],
|
|
1310
|
+
item._serialize(thisId, key),
|
|
1311
|
+
storageUpdates
|
|
1312
|
+
);
|
|
708
1313
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
} ], item._serialize(this._id, key), storageUpdates);
|
|
714
|
-
}
|
|
715
|
-
return !0;
|
|
716
|
-
}
|
|
717
|
-
entries() {
|
|
718
|
-
const innerIterator = this._map.entries();
|
|
719
|
-
return {
|
|
720
|
-
[Symbol.iterator]: function() {
|
|
721
|
-
return this;
|
|
722
|
-
},
|
|
723
|
-
next() {
|
|
724
|
-
const iteratorValue = innerIterator.next();
|
|
725
|
-
if (iteratorValue.done) return {
|
|
726
|
-
done: !0,
|
|
727
|
-
value: void 0
|
|
728
|
-
};
|
|
1314
|
+
return !0;
|
|
1315
|
+
}
|
|
1316
|
+
entries() {
|
|
1317
|
+
const innerIterator = this._map.entries();
|
|
729
1318
|
return {
|
|
730
|
-
|
|
1319
|
+
[Symbol.iterator]() {
|
|
1320
|
+
return this;
|
|
1321
|
+
},
|
|
1322
|
+
next() {
|
|
1323
|
+
const iteratorValue = innerIterator.next();
|
|
1324
|
+
if (iteratorValue.done) return { done: !0, value: void 0 };
|
|
1325
|
+
return {
|
|
1326
|
+
value: [
|
|
1327
|
+
iteratorValue.value[0],
|
|
1328
|
+
liveNodeToLson(iteratorValue.value[1]),
|
|
1329
|
+
],
|
|
1330
|
+
};
|
|
1331
|
+
},
|
|
731
1332
|
};
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
done: !0,
|
|
751
|
-
value: void 0
|
|
752
|
-
} : {
|
|
753
|
-
value: selfOrRegisterValue(iteratorValue.value)
|
|
1333
|
+
}
|
|
1334
|
+
[Symbol.iterator]() {
|
|
1335
|
+
return this.entries();
|
|
1336
|
+
}
|
|
1337
|
+
keys() {
|
|
1338
|
+
return this._map.keys();
|
|
1339
|
+
}
|
|
1340
|
+
values() {
|
|
1341
|
+
const innerIterator = this._map.values();
|
|
1342
|
+
return {
|
|
1343
|
+
[Symbol.iterator]() {
|
|
1344
|
+
return this;
|
|
1345
|
+
},
|
|
1346
|
+
next() {
|
|
1347
|
+
const iteratorValue = innerIterator.next();
|
|
1348
|
+
if (iteratorValue.done) return { done: !0, value: void 0 };
|
|
1349
|
+
return { value: liveNodeToLson(iteratorValue.value) };
|
|
1350
|
+
},
|
|
754
1351
|
};
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
for (const entry of this) callback(entry[1], entry[0], this);
|
|
760
|
-
}
|
|
1352
|
+
}
|
|
1353
|
+
forEach(callback) {
|
|
1354
|
+
for (const entry of this) callback(entry[1], entry[0], this);
|
|
1355
|
+
}
|
|
761
1356
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
1357
|
+
class LiveObject extends AbstractCrdt {
|
|
1358
|
+
constructor(obj = {}) {
|
|
1359
|
+
super(), (this._propToLastUpdate = new Map());
|
|
1360
|
+
for (const key in obj) {
|
|
1361
|
+
const value = obj[key];
|
|
1362
|
+
void 0 !== value && isLiveNode(value) && value._setParentLink(this, key);
|
|
1363
|
+
}
|
|
1364
|
+
this._map = new Map(Object.entries(obj));
|
|
1365
|
+
}
|
|
1366
|
+
_serialize(parentId, parentKey, doc) {
|
|
1367
|
+
if (null == this._id)
|
|
1368
|
+
throw new Error("Cannot serialize item is not attached");
|
|
1369
|
+
const opId = null == doc ? void 0 : doc.generateOpId(),
|
|
1370
|
+
ops = [],
|
|
1371
|
+
op =
|
|
1372
|
+
void 0 !== parentId && void 0 !== parentKey
|
|
1373
|
+
? {
|
|
1374
|
+
type: OpCode.CREATE_OBJECT,
|
|
1375
|
+
id: this._id,
|
|
1376
|
+
opId: opId,
|
|
1377
|
+
parentId: parentId,
|
|
1378
|
+
parentKey: parentKey,
|
|
1379
|
+
data: {},
|
|
1380
|
+
}
|
|
1381
|
+
: { type: OpCode.CREATE_OBJECT, id: this._id, opId: opId, data: {} };
|
|
1382
|
+
ops.push(op);
|
|
1383
|
+
for (const [key, value] of this._map)
|
|
1384
|
+
isLiveNode(value)
|
|
1385
|
+
? ops.push(...value._serialize(this._id, key, doc))
|
|
1386
|
+
: (op.data[key] = value);
|
|
1387
|
+
return ops;
|
|
1388
|
+
}
|
|
1389
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
1390
|
+
const liveObj = new LiveObject(item.data);
|
|
1391
|
+
return (
|
|
1392
|
+
liveObj._attach(id, doc),
|
|
1393
|
+
this._deserializeChildren(liveObj, parentToChildren, doc)
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
static _deserializeChildren(liveObj, parentToChildren, doc) {
|
|
1397
|
+
const children = parentToChildren.get(nn(liveObj._id));
|
|
1398
|
+
if (null == children) return liveObj;
|
|
1399
|
+
for (const [id, crdt] of children) {
|
|
1400
|
+
const child = deserializeToLson([id, crdt], parentToChildren, doc);
|
|
1401
|
+
isLiveStructure(child) && child._setParentLink(liveObj, crdt.parentKey),
|
|
1402
|
+
liveObj._map.set(crdt.parentKey, child);
|
|
1403
|
+
}
|
|
1404
|
+
return liveObj;
|
|
1405
|
+
}
|
|
1406
|
+
_attach(id, doc) {
|
|
1407
|
+
super._attach(id, doc);
|
|
1408
|
+
for (const [_key, value] of this._map)
|
|
1409
|
+
isLiveNode(value) && value._attach(doc.generateId(), doc);
|
|
1410
|
+
}
|
|
1411
|
+
_attachChild(op, source) {
|
|
1412
|
+
if (null == this._doc)
|
|
1413
|
+
throw new Error("Can't attach child if doc is not present");
|
|
1414
|
+
const { id: id, opId: opId, parentKey: key } = op,
|
|
1415
|
+
child = creationOpToLson(op);
|
|
1416
|
+
if (void 0 !== this._doc.getItem(id))
|
|
1417
|
+
return (
|
|
1418
|
+
this._propToLastUpdate.get(key) === opId &&
|
|
1419
|
+
this._propToLastUpdate.delete(key),
|
|
1420
|
+
{ modified: !1 }
|
|
1421
|
+
);
|
|
1422
|
+
if (source === OpSource.UNDOREDO_RECONNECT)
|
|
1423
|
+
this._propToLastUpdate.set(key, nn(opId));
|
|
1424
|
+
else if (void 0 !== this._propToLastUpdate.get(key))
|
|
1425
|
+
return this._propToLastUpdate.get(key) === opId
|
|
1426
|
+
? (this._propToLastUpdate.delete(key), { modified: !1 })
|
|
1427
|
+
: { modified: !1 };
|
|
1428
|
+
const thisId = nn(this._id),
|
|
1429
|
+
previousValue = this._map.get(key);
|
|
1430
|
+
let reverse;
|
|
1431
|
+
return (
|
|
1432
|
+
isLiveNode(previousValue)
|
|
1433
|
+
? ((reverse = previousValue._serialize(thisId, key)),
|
|
1434
|
+
previousValue._detach())
|
|
1435
|
+
: (reverse =
|
|
1436
|
+
void 0 === previousValue
|
|
1437
|
+
? [{ type: OpCode.DELETE_OBJECT_KEY, id: thisId, key: key }]
|
|
1438
|
+
: [
|
|
1439
|
+
{
|
|
1440
|
+
type: OpCode.UPDATE_OBJECT,
|
|
1441
|
+
id: thisId,
|
|
1442
|
+
data: { [key]: previousValue },
|
|
1443
|
+
},
|
|
1444
|
+
]),
|
|
1445
|
+
this._map.set(key, child),
|
|
1446
|
+
isLiveStructure(child) &&
|
|
1447
|
+
(child._setParentLink(this, key), child._attach(id, this._doc)),
|
|
1448
|
+
{
|
|
1449
|
+
reverse: reverse,
|
|
1450
|
+
modified: {
|
|
1451
|
+
node: this,
|
|
1452
|
+
type: "LiveObject",
|
|
1453
|
+
updates: { [key]: { type: "update" } },
|
|
1454
|
+
},
|
|
1455
|
+
}
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
_detachChild(child) {
|
|
1459
|
+
if (child) {
|
|
1460
|
+
const id = nn(this._id),
|
|
1461
|
+
parentKey = nn(child._parentKey),
|
|
1462
|
+
reverse = child._serialize(id, parentKey, this._doc);
|
|
1463
|
+
for (const [key, value] of this._map)
|
|
1464
|
+
value === child && this._map.delete(key);
|
|
1465
|
+
child._detach();
|
|
1466
|
+
return {
|
|
1467
|
+
modified: {
|
|
1468
|
+
node: this,
|
|
1469
|
+
type: "LiveObject",
|
|
1470
|
+
updates: { [parentKey]: { type: "delete" } },
|
|
1471
|
+
},
|
|
1472
|
+
reverse: reverse,
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
return { modified: !1 };
|
|
1476
|
+
}
|
|
1477
|
+
_detach() {
|
|
1478
|
+
super._detach();
|
|
1479
|
+
for (const value of this._map.values())
|
|
1480
|
+
isLiveNode(value) && value._detach();
|
|
1481
|
+
}
|
|
1482
|
+
_apply(op, isLocal) {
|
|
1483
|
+
return op.type === OpCode.UPDATE_OBJECT
|
|
1484
|
+
? this._applyUpdate(op, isLocal)
|
|
1485
|
+
: op.type === OpCode.DELETE_OBJECT_KEY
|
|
1486
|
+
? this._applyDeleteObjectKey(op)
|
|
1487
|
+
: super._apply(op, isLocal);
|
|
1488
|
+
}
|
|
1489
|
+
_toSerializedCrdt() {
|
|
1490
|
+
const data = {};
|
|
1491
|
+
for (const [key, value] of this._map)
|
|
1492
|
+
isLiveNode(value) || (data[key] = value);
|
|
1493
|
+
return "HasParent" === this.parent.type && this.parent.node._id
|
|
1494
|
+
? {
|
|
1495
|
+
type: CrdtType.OBJECT,
|
|
1496
|
+
parentId: this.parent.node._id,
|
|
1497
|
+
parentKey: this.parent.key,
|
|
1498
|
+
data: data,
|
|
1499
|
+
}
|
|
1500
|
+
: { type: CrdtType.OBJECT, data: data };
|
|
1501
|
+
}
|
|
1502
|
+
_applyUpdate(op, isLocal) {
|
|
1503
|
+
let isModified = !1;
|
|
1504
|
+
const id = nn(this._id),
|
|
1505
|
+
reverse = [],
|
|
1506
|
+
reverseUpdate = { type: OpCode.UPDATE_OBJECT, id: id, data: {} };
|
|
1507
|
+
reverse.push(reverseUpdate);
|
|
1508
|
+
for (const key in op.data) {
|
|
1509
|
+
const oldValue = this._map.get(key);
|
|
1510
|
+
isLiveNode(oldValue)
|
|
1511
|
+
? (reverse.push(...oldValue._serialize(id, key)), oldValue._detach())
|
|
1512
|
+
: void 0 !== oldValue
|
|
1513
|
+
? (reverseUpdate.data[key] = oldValue)
|
|
1514
|
+
: void 0 === oldValue &&
|
|
1515
|
+
reverse.push({ type: OpCode.DELETE_OBJECT_KEY, id: id, key: key });
|
|
1516
|
+
}
|
|
1517
|
+
const updateDelta = {};
|
|
1518
|
+
for (const key in op.data) {
|
|
1519
|
+
const value = op.data[key];
|
|
1520
|
+
if (void 0 === value) continue;
|
|
1521
|
+
if (isLocal) this._propToLastUpdate.set(key, nn(op.opId));
|
|
1522
|
+
else {
|
|
1523
|
+
if (null != this._propToLastUpdate.get(key)) {
|
|
1524
|
+
if (this._propToLastUpdate.get(key) === op.opId) {
|
|
1525
|
+
this._propToLastUpdate.delete(key);
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
continue;
|
|
1529
|
+
}
|
|
1530
|
+
isModified = !0;
|
|
1531
|
+
}
|
|
1532
|
+
const oldValue = this._map.get(key);
|
|
1533
|
+
isLiveNode(oldValue) && oldValue._detach(),
|
|
1534
|
+
(isModified = !0),
|
|
1535
|
+
(updateDelta[key] = { type: "update" }),
|
|
1536
|
+
this._map.set(key, value);
|
|
1537
|
+
}
|
|
1538
|
+
return (
|
|
1539
|
+
0 !== Object.keys(reverseUpdate.data).length &&
|
|
1540
|
+
reverse.unshift(reverseUpdate),
|
|
1541
|
+
isModified
|
|
1542
|
+
? {
|
|
1543
|
+
modified: { node: this, type: "LiveObject", updates: updateDelta },
|
|
1544
|
+
reverse: reverse,
|
|
1545
|
+
}
|
|
1546
|
+
: { modified: !1 }
|
|
1547
|
+
);
|
|
1548
|
+
}
|
|
1549
|
+
_applyDeleteObjectKey(op) {
|
|
1550
|
+
const key = op.key;
|
|
1551
|
+
if (!1 === this._map.has(key)) return { modified: !1 };
|
|
1552
|
+
if (void 0 !== this._propToLastUpdate.get(key)) return { modified: !1 };
|
|
1553
|
+
const oldValue = this._map.get(key),
|
|
1554
|
+
id = nn(this._id);
|
|
1555
|
+
let reverse = [];
|
|
1556
|
+
return (
|
|
1557
|
+
isLiveNode(oldValue)
|
|
1558
|
+
? ((reverse = oldValue._serialize(id, op.key)), oldValue._detach())
|
|
1559
|
+
: void 0 !== oldValue &&
|
|
1560
|
+
(reverse = [
|
|
1561
|
+
{ type: OpCode.UPDATE_OBJECT, id: id, data: { [key]: oldValue } },
|
|
1562
|
+
]),
|
|
1563
|
+
this._map.delete(key),
|
|
1564
|
+
{
|
|
1565
|
+
modified: {
|
|
1566
|
+
node: this,
|
|
1567
|
+
type: "LiveObject",
|
|
1568
|
+
updates: { [op.key]: { type: "delete" } },
|
|
1569
|
+
},
|
|
1570
|
+
reverse: reverse,
|
|
1571
|
+
}
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
toObject() {
|
|
1575
|
+
return (function (iterable) {
|
|
1576
|
+
const obj = {};
|
|
1577
|
+
for (const [key, val] of iterable) obj[key] = val;
|
|
1578
|
+
return obj;
|
|
1579
|
+
})(this._map);
|
|
1580
|
+
}
|
|
1581
|
+
set(key, value) {
|
|
1582
|
+
this.update({ [key]: value });
|
|
1583
|
+
}
|
|
1584
|
+
get(key) {
|
|
1585
|
+
return this._map.get(key);
|
|
1586
|
+
}
|
|
1587
|
+
delete(key) {
|
|
1588
|
+
const keyAsString = key,
|
|
1589
|
+
oldValue = this._map.get(keyAsString);
|
|
1590
|
+
if (void 0 === oldValue) return;
|
|
1591
|
+
if (null == this._doc || null == this._id)
|
|
1592
|
+
return (
|
|
1593
|
+
isLiveNode(oldValue) && oldValue._detach(),
|
|
1594
|
+
void this._map.delete(keyAsString)
|
|
1595
|
+
);
|
|
1596
|
+
let reverse;
|
|
1597
|
+
isLiveNode(oldValue)
|
|
1598
|
+
? (oldValue._detach(),
|
|
1599
|
+
(reverse = oldValue._serialize(this._id, keyAsString)))
|
|
1600
|
+
: (reverse = [
|
|
1601
|
+
{
|
|
1602
|
+
type: OpCode.UPDATE_OBJECT,
|
|
1603
|
+
data: { [keyAsString]: oldValue },
|
|
1604
|
+
id: this._id,
|
|
1605
|
+
},
|
|
1606
|
+
]),
|
|
1607
|
+
this._map.delete(keyAsString);
|
|
1608
|
+
const storageUpdates = new Map();
|
|
1609
|
+
storageUpdates.set(this._id, {
|
|
1610
|
+
node: this,
|
|
1611
|
+
type: "LiveObject",
|
|
1612
|
+
updates: { [key]: { type: "delete" } },
|
|
1613
|
+
}),
|
|
1614
|
+
this._doc.dispatch(
|
|
1615
|
+
[
|
|
1616
|
+
{
|
|
1617
|
+
type: OpCode.DELETE_OBJECT_KEY,
|
|
1618
|
+
key: keyAsString,
|
|
1619
|
+
id: this._id,
|
|
1620
|
+
opId: this._doc.generateOpId(),
|
|
1621
|
+
},
|
|
1622
|
+
],
|
|
1623
|
+
reverse,
|
|
1624
|
+
storageUpdates
|
|
1625
|
+
);
|
|
1626
|
+
}
|
|
1627
|
+
update(overrides) {
|
|
1628
|
+
if (null == this._doc || null == this._id) {
|
|
1629
|
+
for (const key in overrides) {
|
|
1630
|
+
const newValue = overrides[key];
|
|
1631
|
+
if (void 0 === newValue) continue;
|
|
1632
|
+
const oldValue = this._map.get(key);
|
|
1633
|
+
isLiveNode(oldValue) && oldValue._detach(),
|
|
1634
|
+
isLiveNode(newValue) && newValue._setParentLink(this, key),
|
|
1635
|
+
this._map.set(key, newValue);
|
|
1636
|
+
}
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
const ops = [],
|
|
1640
|
+
reverseOps = [],
|
|
1641
|
+
opId = this._doc.generateOpId(),
|
|
1642
|
+
updatedProps = {},
|
|
1643
|
+
reverseUpdateOp = { id: this._id, type: OpCode.UPDATE_OBJECT, data: {} },
|
|
1644
|
+
updateDelta = {};
|
|
1645
|
+
for (const key in overrides) {
|
|
1646
|
+
const newValue = overrides[key];
|
|
1647
|
+
if (void 0 === newValue) continue;
|
|
1648
|
+
const oldValue = this._map.get(key);
|
|
1649
|
+
if (
|
|
1650
|
+
(isLiveNode(oldValue)
|
|
1651
|
+
? (reverseOps.push(...oldValue._serialize(this._id, key)),
|
|
1652
|
+
oldValue._detach())
|
|
1653
|
+
: void 0 === oldValue
|
|
1654
|
+
? reverseOps.push({
|
|
1655
|
+
type: OpCode.DELETE_OBJECT_KEY,
|
|
1656
|
+
id: this._id,
|
|
1657
|
+
key: key,
|
|
1658
|
+
})
|
|
1659
|
+
: (reverseUpdateOp.data[key] = oldValue),
|
|
1660
|
+
isLiveNode(newValue))
|
|
1661
|
+
) {
|
|
1662
|
+
newValue._setParentLink(this, key),
|
|
1663
|
+
newValue._attach(this._doc.generateId(), this._doc);
|
|
1664
|
+
const newAttachChildOps = newValue._serialize(this._id, key, this._doc),
|
|
1665
|
+
createCrdtOp = newAttachChildOps.find(
|
|
1666
|
+
(op) => op.parentId === this._id
|
|
1667
|
+
);
|
|
1668
|
+
createCrdtOp && this._propToLastUpdate.set(key, nn(createCrdtOp.opId)),
|
|
1669
|
+
ops.push(...newAttachChildOps);
|
|
1670
|
+
} else
|
|
1671
|
+
(updatedProps[key] = newValue), this._propToLastUpdate.set(key, opId);
|
|
1672
|
+
this._map.set(key, newValue), (updateDelta[key] = { type: "update" });
|
|
1673
|
+
}
|
|
1674
|
+
0 !== Object.keys(reverseUpdateOp.data).length &&
|
|
1675
|
+
reverseOps.unshift(reverseUpdateOp),
|
|
1676
|
+
0 !== Object.keys(updatedProps).length &&
|
|
1677
|
+
ops.unshift({
|
|
1678
|
+
opId: opId,
|
|
1679
|
+
id: this._id,
|
|
1680
|
+
type: OpCode.UPDATE_OBJECT,
|
|
1681
|
+
data: updatedProps,
|
|
1682
|
+
});
|
|
1683
|
+
const storageUpdates = new Map();
|
|
1684
|
+
storageUpdates.set(this._id, {
|
|
1685
|
+
node: this,
|
|
1686
|
+
type: "LiveObject",
|
|
1687
|
+
updates: updateDelta,
|
|
1688
|
+
}),
|
|
1689
|
+
this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
1690
|
+
}
|
|
765
1691
|
}
|
|
766
|
-
|
|
767
1692
|
function remove(array, item) {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1693
|
+
for (let i = 0; i < array.length; i++)
|
|
1694
|
+
if (array[i] === item) {
|
|
1695
|
+
array.splice(i, 1);
|
|
1696
|
+
break;
|
|
1697
|
+
}
|
|
772
1698
|
}
|
|
773
|
-
|
|
774
1699
|
function compact(items) {
|
|
775
|
-
|
|
1700
|
+
return items.filter((item) => null != item);
|
|
776
1701
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1702
|
+
function creationOpToLiveNode(op) {
|
|
1703
|
+
return lsonToLiveNode(creationOpToLson(op));
|
|
1704
|
+
}
|
|
1705
|
+
function creationOpToLson(op) {
|
|
1706
|
+
switch (op.type) {
|
|
1707
|
+
case OpCode.CREATE_REGISTER:
|
|
1708
|
+
return op.data;
|
|
1709
|
+
case OpCode.CREATE_OBJECT:
|
|
1710
|
+
return new LiveObject(op.data);
|
|
1711
|
+
case OpCode.CREATE_MAP:
|
|
1712
|
+
return new LiveMap();
|
|
1713
|
+
case OpCode.CREATE_LIST:
|
|
1714
|
+
return new LiveList();
|
|
1715
|
+
default:
|
|
1716
|
+
return assertNever(0, "Unknown creation Op");
|
|
1717
|
+
}
|
|
792
1718
|
}
|
|
793
|
-
|
|
794
1719
|
function isSameNodeOrChildOf(node, parent) {
|
|
795
|
-
|
|
1720
|
+
return (
|
|
1721
|
+
node === parent ||
|
|
1722
|
+
("HasParent" === node.parent.type &&
|
|
1723
|
+
isSameNodeOrChildOf(node.parent.node, parent))
|
|
1724
|
+
);
|
|
796
1725
|
}
|
|
797
|
-
|
|
798
1726
|
function deserialize([id, crdt], parentToChildren, doc) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1727
|
+
switch (crdt.type) {
|
|
1728
|
+
case CrdtType.OBJECT:
|
|
1729
|
+
return LiveObject._deserialize([id, crdt], parentToChildren, doc);
|
|
1730
|
+
case CrdtType.LIST:
|
|
1731
|
+
return LiveList._deserialize([id, crdt], parentToChildren, doc);
|
|
1732
|
+
case CrdtType.MAP:
|
|
1733
|
+
return LiveMap._deserialize([id, crdt], parentToChildren, doc);
|
|
1734
|
+
case CrdtType.REGISTER:
|
|
1735
|
+
return LiveRegister._deserialize([id, crdt], parentToChildren, doc);
|
|
1736
|
+
default:
|
|
1737
|
+
throw new Error("Unexpected CRDT type");
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
function deserializeToLson([id, crdt], parentToChildren, doc) {
|
|
1741
|
+
switch (crdt.type) {
|
|
1742
|
+
case CrdtType.OBJECT:
|
|
1743
|
+
return LiveObject._deserialize([id, crdt], parentToChildren, doc);
|
|
1744
|
+
case CrdtType.LIST:
|
|
1745
|
+
return LiveList._deserialize([id, crdt], parentToChildren, doc);
|
|
1746
|
+
case CrdtType.MAP:
|
|
1747
|
+
return LiveMap._deserialize([id, crdt], parentToChildren, doc);
|
|
1748
|
+
case CrdtType.REGISTER:
|
|
1749
|
+
return crdt.data;
|
|
1750
|
+
default:
|
|
1751
|
+
throw new Error("Unexpected CRDT type");
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
function isLiveStructure(value) {
|
|
1755
|
+
return (
|
|
1756
|
+
isLiveList(value) ||
|
|
1757
|
+
(function (value) {
|
|
1758
|
+
return value instanceof LiveMap;
|
|
1759
|
+
})(value) ||
|
|
1760
|
+
isLiveObject(value)
|
|
1761
|
+
);
|
|
1762
|
+
}
|
|
1763
|
+
function isLiveNode(value) {
|
|
1764
|
+
return (
|
|
1765
|
+
isLiveStructure(value) ||
|
|
1766
|
+
(function (value) {
|
|
1767
|
+
return value instanceof LiveRegister;
|
|
1768
|
+
})(value)
|
|
1769
|
+
);
|
|
815
1770
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
return obj instanceof LiveObject || obj instanceof LiveMap || obj instanceof LiveList || obj instanceof LiveRegister;
|
|
1771
|
+
function isLiveList(value) {
|
|
1772
|
+
return value instanceof LiveList;
|
|
819
1773
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
return obj instanceof LiveRegister ? obj.data : obj;
|
|
1774
|
+
function isLiveObject(value) {
|
|
1775
|
+
return value instanceof LiveObject;
|
|
823
1776
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
1777
|
+
function liveNodeToLson(obj) {
|
|
1778
|
+
return obj instanceof LiveRegister
|
|
1779
|
+
? obj.data
|
|
1780
|
+
: obj instanceof LiveList ||
|
|
1781
|
+
obj instanceof LiveMap ||
|
|
1782
|
+
obj instanceof LiveObject
|
|
1783
|
+
? obj
|
|
1784
|
+
: assertNever(0, "Unknown AbstractCrdt");
|
|
1785
|
+
}
|
|
1786
|
+
function lsonToLiveNode(value) {
|
|
1787
|
+
return value instanceof LiveObject ||
|
|
1788
|
+
value instanceof LiveMap ||
|
|
1789
|
+
value instanceof LiveList
|
|
1790
|
+
? value
|
|
1791
|
+
: new LiveRegister(value);
|
|
829
1792
|
}
|
|
830
|
-
|
|
831
1793
|
function getTreesDiffOperations(currentItems, newItems) {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1794
|
+
const ops = [];
|
|
1795
|
+
return (
|
|
1796
|
+
currentItems.forEach((_, id) => {
|
|
1797
|
+
newItems.get(id) || ops.push({ type: OpCode.DELETE_CRDT, id: id });
|
|
1798
|
+
}),
|
|
1799
|
+
newItems.forEach((crdt, id) => {
|
|
1800
|
+
const currentCrdt = currentItems.get(id);
|
|
1801
|
+
if (currentCrdt)
|
|
1802
|
+
crdt.type === CrdtType.OBJECT &&
|
|
1803
|
+
((currentCrdt.type === CrdtType.OBJECT &&
|
|
1804
|
+
JSON.stringify(crdt.data) === JSON.stringify(currentCrdt.data)) ||
|
|
1805
|
+
ops.push({ type: OpCode.UPDATE_OBJECT, id: id, data: crdt.data })),
|
|
1806
|
+
crdt.parentKey !== currentCrdt.parentKey &&
|
|
1807
|
+
ops.push({
|
|
1808
|
+
type: OpCode.SET_PARENT_KEY,
|
|
1809
|
+
id: id,
|
|
1810
|
+
parentKey: nn(crdt.parentKey, "Parent key must not be missing"),
|
|
1811
|
+
});
|
|
1812
|
+
else
|
|
1813
|
+
switch (crdt.type) {
|
|
1814
|
+
case CrdtType.REGISTER:
|
|
1815
|
+
ops.push({
|
|
1816
|
+
type: OpCode.CREATE_REGISTER,
|
|
1817
|
+
id: id,
|
|
1818
|
+
parentId: crdt.parentId,
|
|
1819
|
+
parentKey: crdt.parentKey,
|
|
1820
|
+
data: crdt.data,
|
|
1821
|
+
});
|
|
1822
|
+
break;
|
|
1823
|
+
case CrdtType.LIST:
|
|
1824
|
+
ops.push({
|
|
1825
|
+
type: OpCode.CREATE_LIST,
|
|
1826
|
+
id: id,
|
|
1827
|
+
parentId: crdt.parentId,
|
|
1828
|
+
parentKey: crdt.parentKey,
|
|
1829
|
+
});
|
|
1830
|
+
break;
|
|
1831
|
+
case CrdtType.OBJECT:
|
|
1832
|
+
ops.push(
|
|
1833
|
+
crdt.parentId
|
|
1834
|
+
? {
|
|
1835
|
+
type: OpCode.CREATE_OBJECT,
|
|
1836
|
+
id: id,
|
|
1837
|
+
parentId: crdt.parentId,
|
|
1838
|
+
parentKey: crdt.parentKey,
|
|
1839
|
+
data: crdt.data,
|
|
1840
|
+
}
|
|
1841
|
+
: { type: OpCode.CREATE_OBJECT, id: id, data: crdt.data }
|
|
1842
|
+
);
|
|
1843
|
+
break;
|
|
1844
|
+
case CrdtType.MAP:
|
|
1845
|
+
ops.push({
|
|
1846
|
+
type: OpCode.CREATE_MAP,
|
|
1847
|
+
id: id,
|
|
1848
|
+
parentId: crdt.parentId,
|
|
1849
|
+
parentKey: crdt.parentKey,
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
}),
|
|
1853
|
+
ops
|
|
1854
|
+
);
|
|
891
1855
|
}
|
|
892
|
-
|
|
893
1856
|
function mergeStorageUpdates(first, second) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1857
|
+
return first
|
|
1858
|
+
? "LiveObject" === first.type && "LiveObject" === second.type
|
|
1859
|
+
? (function (first, second) {
|
|
1860
|
+
const updates = first.updates;
|
|
1861
|
+
for (const [key, value] of entries(second.updates))
|
|
1862
|
+
updates[key] = value;
|
|
1863
|
+
return Object.assign(Object.assign({}, second), { updates: updates });
|
|
1864
|
+
})(first, second)
|
|
1865
|
+
: "LiveMap" === first.type && "LiveMap" === second.type
|
|
1866
|
+
? (function (first, second) {
|
|
1867
|
+
const updates = first.updates;
|
|
1868
|
+
for (const [key, value] of entries(second.updates))
|
|
1869
|
+
updates[key] = value;
|
|
1870
|
+
return Object.assign(Object.assign({}, second), { updates: updates });
|
|
1871
|
+
})(first, second)
|
|
1872
|
+
: "LiveList" === first.type && "LiveList" === second.type
|
|
1873
|
+
? (function (first, second) {
|
|
1874
|
+
const updates = first.updates;
|
|
1875
|
+
return Object.assign(Object.assign({}, second), {
|
|
1876
|
+
updates: updates.concat(second.updates),
|
|
1877
|
+
});
|
|
1878
|
+
})(first, second)
|
|
1879
|
+
: second
|
|
1880
|
+
: second;
|
|
912
1881
|
}
|
|
913
|
-
|
|
914
1882
|
function isPlain(value) {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1883
|
+
const type = typeof value;
|
|
1884
|
+
return (
|
|
1885
|
+
null == value ||
|
|
1886
|
+
"string" === type ||
|
|
1887
|
+
"boolean" === type ||
|
|
1888
|
+
"number" === type ||
|
|
1889
|
+
Array.isArray(value) ||
|
|
1890
|
+
isPlainObject(value)
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1893
|
+
function isPlainObject(blob) {
|
|
1894
|
+
return (
|
|
1895
|
+
null !== blob &&
|
|
1896
|
+
"object" == typeof blob &&
|
|
1897
|
+
"[object Object]" === Object.prototype.toString.call(blob)
|
|
1898
|
+
);
|
|
924
1899
|
}
|
|
925
|
-
|
|
926
1900
|
function findNonSerializableValue(value, path = "") {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
value
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
const nonSerializableNestedValue = findNonSerializableValue(nestedValue, nestedPath);
|
|
940
|
-
if (nonSerializableNestedValue) return nonSerializableNestedValue;
|
|
1901
|
+
if (!isPlain) return { path: path || "root", value: value };
|
|
1902
|
+
if ("object" != typeof value || null === value) return !1;
|
|
1903
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
1904
|
+
const nestedPath = path ? path + "." + key : key;
|
|
1905
|
+
if (!isPlain(nestedValue)) return { path: nestedPath, value: nestedValue };
|
|
1906
|
+
if ("object" == typeof nestedValue) {
|
|
1907
|
+
const nonSerializableNestedValue = findNonSerializableValue(
|
|
1908
|
+
nestedValue,
|
|
1909
|
+
nestedPath
|
|
1910
|
+
);
|
|
1911
|
+
if (nonSerializableNestedValue) return nonSerializableNestedValue;
|
|
1912
|
+
}
|
|
941
1913
|
}
|
|
942
|
-
|
|
943
|
-
return !1;
|
|
1914
|
+
return !1;
|
|
944
1915
|
}
|
|
945
|
-
|
|
946
|
-
function isTokenValid(token) {
|
|
947
|
-
const tokenParts = token.split(".");
|
|
948
|
-
if (3 !== tokenParts.length) return !1;
|
|
949
|
-
const data = tryParseJson(atob(tokenParts[1]));
|
|
950
|
-
if (void 0 === data || !isJsonObject(data) || "number" != typeof data.exp) return !1;
|
|
951
|
-
return !(Date.now() / 1e3 > data.exp - 300);
|
|
952
|
-
}
|
|
953
|
-
|
|
954
1916
|
function entries(obj) {
|
|
955
|
-
|
|
1917
|
+
return Object.entries(obj);
|
|
956
1918
|
}
|
|
957
|
-
|
|
958
1919
|
function tryParseJson(rawMessage) {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1920
|
+
try {
|
|
1921
|
+
return JSON.parse(rawMessage);
|
|
1922
|
+
} catch (e) {
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
964
1925
|
}
|
|
965
|
-
|
|
966
1926
|
function b64decode(b64value) {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1927
|
+
try {
|
|
1928
|
+
const formattedValue = b64value.replace(/-/g, "+").replace(/_/g, "/");
|
|
1929
|
+
return decodeURIComponent(
|
|
1930
|
+
atob(formattedValue)
|
|
1931
|
+
.split("")
|
|
1932
|
+
.map(function (c) {
|
|
1933
|
+
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
|
1934
|
+
})
|
|
1935
|
+
.join("")
|
|
1936
|
+
);
|
|
1937
|
+
} catch (err) {
|
|
1938
|
+
return atob(b64value);
|
|
1939
|
+
}
|
|
975
1940
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
if (
|
|
1034
|
-
|
|
1035
|
-
modified: !1
|
|
1036
|
-
}) : {
|
|
1037
|
-
modified: !1
|
|
1038
|
-
};
|
|
1039
|
-
const previousValue = this._map.get(key);
|
|
1040
|
-
let reverse;
|
|
1041
|
-
return isCrdt(previousValue) ? (reverse = previousValue._serialize(this._id, key),
|
|
1042
|
-
previousValue._detach()) : reverse = void 0 === previousValue ? [ {
|
|
1043
|
-
type: OpCode.DELETE_OBJECT_KEY,
|
|
1044
|
-
id: this._id,
|
|
1045
|
-
key: key
|
|
1046
|
-
} ] : [ {
|
|
1047
|
-
type: OpCode.UPDATE_OBJECT,
|
|
1048
|
-
id: this._id,
|
|
1049
|
-
data: {
|
|
1050
|
-
[key]: previousValue
|
|
1051
|
-
}
|
|
1052
|
-
} ], this._map.set(key, child), child._setParentLink(this, key), child._attach(id, this._doc),
|
|
1053
|
-
{
|
|
1054
|
-
reverse: reverse,
|
|
1055
|
-
modified: {
|
|
1056
|
-
node: this,
|
|
1057
|
-
type: "LiveObject",
|
|
1058
|
-
updates: {
|
|
1059
|
-
[key]: {
|
|
1060
|
-
type: "update"
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
_detachChild(child) {
|
|
1067
|
-
if (child) {
|
|
1068
|
-
const reverse = child._serialize(this._id, child._parentKey, this._doc);
|
|
1069
|
-
for (const [key, value] of this._map) value === child && this._map.delete(key);
|
|
1070
|
-
child._detach();
|
|
1071
|
-
return {
|
|
1072
|
-
modified: {
|
|
1073
|
-
node: this,
|
|
1074
|
-
type: "LiveObject",
|
|
1075
|
-
updates: {
|
|
1076
|
-
[child._parentKey]: {
|
|
1077
|
-
type: "delete"
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
},
|
|
1081
|
-
reverse: reverse
|
|
1082
|
-
};
|
|
1941
|
+
const SCOPES = [
|
|
1942
|
+
"websocket:presence",
|
|
1943
|
+
"websocket:storage",
|
|
1944
|
+
"room:read",
|
|
1945
|
+
"room:write",
|
|
1946
|
+
"rooms:read",
|
|
1947
|
+
"rooms:write",
|
|
1948
|
+
];
|
|
1949
|
+
function isTokenExpired(token) {
|
|
1950
|
+
const now = Date.now() / 1e3;
|
|
1951
|
+
return now > token.exp - 300 || now < token.iat + 300;
|
|
1952
|
+
}
|
|
1953
|
+
function isScope(value) {
|
|
1954
|
+
return SCOPES.includes(value);
|
|
1955
|
+
}
|
|
1956
|
+
function isStringList(value) {
|
|
1957
|
+
return Array.isArray(value) && value.every((i) => "string" == typeof i);
|
|
1958
|
+
}
|
|
1959
|
+
function isAppOnlyAuthToken(data) {
|
|
1960
|
+
return (
|
|
1961
|
+
"string" == typeof data.appId &&
|
|
1962
|
+
void 0 === data.roomId &&
|
|
1963
|
+
isStringList(data.scopes)
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
function isRoomAuthToken(data) {
|
|
1967
|
+
return (
|
|
1968
|
+
"string" == typeof data.appId &&
|
|
1969
|
+
"string" == typeof data.roomId &&
|
|
1970
|
+
"number" == typeof data.actor &&
|
|
1971
|
+
(void 0 === data.id || "string" == typeof data.id) &&
|
|
1972
|
+
isStringList(data.scopes) &&
|
|
1973
|
+
(void 0 === data.maxConnectionsPerRoom ||
|
|
1974
|
+
"number" == typeof data.maxConnectionsPerRoom)
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
function isAuthToken(data) {
|
|
1978
|
+
return isAppOnlyAuthToken(data) || isRoomAuthToken(data);
|
|
1979
|
+
}
|
|
1980
|
+
function parseJwtToken(token) {
|
|
1981
|
+
const tokenParts = token.split(".");
|
|
1982
|
+
if (3 !== tokenParts.length)
|
|
1983
|
+
throw new Error("Authentication error: invalid JWT token");
|
|
1984
|
+
const data = tryParseJson(b64decode(tokenParts[1]));
|
|
1985
|
+
if (
|
|
1986
|
+
data &&
|
|
1987
|
+
(function (data) {
|
|
1988
|
+
if (!isPlainObject(data)) return !1;
|
|
1989
|
+
const { iat: iat, exp: exp } = data;
|
|
1990
|
+
return "number" == typeof iat && "number" == typeof exp;
|
|
1991
|
+
})(data)
|
|
1992
|
+
)
|
|
1993
|
+
return data;
|
|
1994
|
+
throw new Error("Authentication error: missing JWT metadata");
|
|
1995
|
+
}
|
|
1996
|
+
function parseRoomAuthToken(tokenString) {
|
|
1997
|
+
const data = parseJwtToken(tokenString);
|
|
1998
|
+
if (data && isRoomAuthToken(data)) {
|
|
1999
|
+
return __rest(data, ["maxConnections"]);
|
|
1083
2000
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
for (const [key, value] of this._map) value instanceof AbstractCrdt == !1 && (data[key] = value);
|
|
1102
|
-
return void 0 !== (null === (_a = this._parent) || void 0 === _a ? void 0 : _a._id) && void 0 !== this._parentKey ? {
|
|
1103
|
-
type: CrdtType.OBJECT,
|
|
1104
|
-
parentId: this._parent._id,
|
|
1105
|
-
parentKey: this._parentKey,
|
|
1106
|
-
data: data
|
|
1107
|
-
} : {
|
|
1108
|
-
type: CrdtType.OBJECT,
|
|
1109
|
-
data: data
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
_applyUpdate(op, isLocal) {
|
|
1113
|
-
let isModified = !1;
|
|
1114
|
-
const reverse = [], reverseUpdate = {
|
|
1115
|
-
type: OpCode.UPDATE_OBJECT,
|
|
1116
|
-
id: this._id,
|
|
1117
|
-
data: {}
|
|
1118
|
-
};
|
|
1119
|
-
reverse.push(reverseUpdate);
|
|
1120
|
-
for (const key in op.data) {
|
|
1121
|
-
const oldValue = this._map.get(key);
|
|
1122
|
-
oldValue instanceof AbstractCrdt ? (reverse.push(...oldValue._serialize(this._id, key)),
|
|
1123
|
-
oldValue._detach()) : void 0 !== oldValue ? reverseUpdate.data[key] = oldValue : void 0 === oldValue && reverse.push({
|
|
1124
|
-
type: OpCode.DELETE_OBJECT_KEY,
|
|
1125
|
-
id: this._id,
|
|
1126
|
-
key: key
|
|
1127
|
-
});
|
|
1128
|
-
}
|
|
1129
|
-
const updateDelta = {};
|
|
1130
|
-
for (const key in op.data) {
|
|
1131
|
-
if (isLocal) this._propToLastUpdate.set(key, op.opId); else {
|
|
1132
|
-
if (null != this._propToLastUpdate.get(key)) {
|
|
1133
|
-
if (this._propToLastUpdate.get(key) === op.opId) {
|
|
1134
|
-
this._propToLastUpdate.delete(key);
|
|
1135
|
-
continue;
|
|
1136
|
-
}
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
isModified = !0;
|
|
1140
|
-
}
|
|
1141
|
-
const oldValue = this._map.get(key);
|
|
1142
|
-
isCrdt(oldValue) && oldValue._detach(), isModified = !0, updateDelta[key] = {
|
|
1143
|
-
type: "update"
|
|
1144
|
-
}, this._map.set(key, op.data[key]);
|
|
1145
|
-
}
|
|
1146
|
-
return 0 !== Object.keys(reverseUpdate.data).length && reverse.unshift(reverseUpdate),
|
|
1147
|
-
isModified ? {
|
|
1148
|
-
modified: {
|
|
1149
|
-
node: this,
|
|
1150
|
-
type: "LiveObject",
|
|
1151
|
-
updates: updateDelta
|
|
1152
|
-
},
|
|
1153
|
-
reverse: reverse
|
|
1154
|
-
} : {
|
|
1155
|
-
modified: !1
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
_applyDeleteObjectKey(op) {
|
|
1159
|
-
const key = op.key;
|
|
1160
|
-
if (!1 === this._map.has(key)) return {
|
|
1161
|
-
modified: !1
|
|
1162
|
-
};
|
|
1163
|
-
if (void 0 !== this._propToLastUpdate.get(key)) return {
|
|
1164
|
-
modified: !1
|
|
1165
|
-
};
|
|
1166
|
-
const oldValue = this._map.get(key);
|
|
1167
|
-
let reverse = [];
|
|
1168
|
-
return isCrdt(oldValue) ? (reverse = oldValue._serialize(this._id, op.key), oldValue._detach()) : void 0 !== oldValue && (reverse = [ {
|
|
1169
|
-
type: OpCode.UPDATE_OBJECT,
|
|
1170
|
-
id: this._id,
|
|
1171
|
-
data: {
|
|
1172
|
-
[key]: oldValue
|
|
1173
|
-
}
|
|
1174
|
-
} ]), this._map.delete(key), {
|
|
1175
|
-
modified: {
|
|
1176
|
-
node: this,
|
|
1177
|
-
type: "LiveObject",
|
|
1178
|
-
updates: {
|
|
1179
|
-
[op.key]: {
|
|
1180
|
-
type: "delete"
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
},
|
|
1184
|
-
reverse: reverse
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
toObject() {
|
|
1188
|
-
return function(iterable) {
|
|
1189
|
-
const obj = {};
|
|
1190
|
-
for (const [key, val] of iterable) obj[key] = val;
|
|
1191
|
-
return obj;
|
|
1192
|
-
}(this._map);
|
|
1193
|
-
}
|
|
1194
|
-
set(key, value) {
|
|
1195
|
-
this.update({
|
|
1196
|
-
[key]: value
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
get(key) {
|
|
1200
|
-
return this._map.get(key);
|
|
1201
|
-
}
|
|
1202
|
-
delete(key) {
|
|
1203
|
-
const keyAsString = key, oldValue = this._map.get(keyAsString);
|
|
1204
|
-
if (void 0 === oldValue) return;
|
|
1205
|
-
if (null == this._doc || null == this._id) return oldValue instanceof AbstractCrdt && oldValue._detach(),
|
|
1206
|
-
void this._map.delete(keyAsString);
|
|
1207
|
-
let reverse;
|
|
1208
|
-
oldValue instanceof AbstractCrdt ? (oldValue._detach(), reverse = oldValue._serialize(this._id, keyAsString)) : reverse = [ {
|
|
1209
|
-
type: OpCode.UPDATE_OBJECT,
|
|
1210
|
-
data: {
|
|
1211
|
-
[keyAsString]: oldValue
|
|
1212
|
-
},
|
|
1213
|
-
id: this._id
|
|
1214
|
-
} ], this._map.delete(keyAsString);
|
|
1215
|
-
const storageUpdates = new Map;
|
|
1216
|
-
storageUpdates.set(this._id, {
|
|
1217
|
-
node: this,
|
|
1218
|
-
type: "LiveObject",
|
|
1219
|
-
updates: {
|
|
1220
|
-
[key]: {
|
|
1221
|
-
type: "delete"
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}), this._doc.dispatch([ {
|
|
1225
|
-
type: OpCode.DELETE_OBJECT_KEY,
|
|
1226
|
-
key: keyAsString,
|
|
1227
|
-
id: this._id,
|
|
1228
|
-
opId: this._doc.generateOpId()
|
|
1229
|
-
} ], reverse, storageUpdates);
|
|
1230
|
-
}
|
|
1231
|
-
update(overrides) {
|
|
1232
|
-
if (null == this._doc || null == this._id) {
|
|
1233
|
-
for (const key in overrides) {
|
|
1234
|
-
const oldValue = this._map.get(key);
|
|
1235
|
-
oldValue instanceof AbstractCrdt && oldValue._detach();
|
|
1236
|
-
const newValue = overrides[key];
|
|
1237
|
-
newValue instanceof AbstractCrdt && newValue._setParentLink(this, key), this._map.set(key, newValue);
|
|
1238
|
-
}
|
|
1239
|
-
return;
|
|
1240
|
-
}
|
|
1241
|
-
const ops = [], reverseOps = [], opId = this._doc.generateOpId(), updatedProps = {}, reverseUpdateOp = {
|
|
1242
|
-
id: this._id,
|
|
1243
|
-
type: OpCode.UPDATE_OBJECT,
|
|
1244
|
-
data: {}
|
|
1245
|
-
}, updateDelta = {};
|
|
1246
|
-
for (const key in overrides) {
|
|
1247
|
-
const oldValue = this._map.get(key);
|
|
1248
|
-
oldValue instanceof AbstractCrdt ? (reverseOps.push(...oldValue._serialize(this._id, key)),
|
|
1249
|
-
oldValue._detach()) : void 0 === oldValue ? reverseOps.push({
|
|
1250
|
-
type: OpCode.DELETE_OBJECT_KEY,
|
|
1251
|
-
id: this._id,
|
|
1252
|
-
key: key
|
|
1253
|
-
}) : reverseUpdateOp.data[key] = oldValue;
|
|
1254
|
-
const newValue = overrides[key];
|
|
1255
|
-
if (newValue instanceof AbstractCrdt) {
|
|
1256
|
-
newValue._setParentLink(this, key), newValue._attach(this._doc.generateId(), this._doc);
|
|
1257
|
-
const newAttachChildOps = newValue._serialize(this._id, key, this._doc), createCrdtOp = newAttachChildOps.find((op => op.parentId === this._id));
|
|
1258
|
-
createCrdtOp && this._propToLastUpdate.set(key, createCrdtOp.opId), ops.push(...newAttachChildOps);
|
|
1259
|
-
} else updatedProps[key] = newValue, this._propToLastUpdate.set(key, opId);
|
|
1260
|
-
this._map.set(key, newValue), updateDelta[key] = {
|
|
1261
|
-
type: "update"
|
|
1262
|
-
};
|
|
1263
|
-
}
|
|
1264
|
-
0 !== Object.keys(reverseUpdateOp.data).length && reverseOps.unshift(reverseUpdateOp),
|
|
1265
|
-
0 !== Object.keys(updatedProps).length && ops.unshift({
|
|
1266
|
-
opId: opId,
|
|
1267
|
-
id: this._id,
|
|
1268
|
-
type: OpCode.UPDATE_OBJECT,
|
|
1269
|
-
data: updatedProps
|
|
1270
|
-
});
|
|
1271
|
-
const storageUpdates = new Map;
|
|
1272
|
-
storageUpdates.set(this._id, {
|
|
1273
|
-
node: this,
|
|
1274
|
-
type: "LiveObject",
|
|
1275
|
-
updates: updateDelta
|
|
1276
|
-
}), this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
1277
|
-
}
|
|
2001
|
+
throw new Error(
|
|
2002
|
+
"Authentication error: we expected a room token but did not get one. Hint: if you are using a callback, ensure the room is passed when creating the token. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientCallback"
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
function isJsonScalar(data) {
|
|
2006
|
+
return (
|
|
2007
|
+
null === data ||
|
|
2008
|
+
"string" == typeof data ||
|
|
2009
|
+
"number" == typeof data ||
|
|
2010
|
+
"boolean" == typeof data
|
|
2011
|
+
);
|
|
2012
|
+
}
|
|
2013
|
+
function isJsonArray(data) {
|
|
2014
|
+
return Array.isArray(data);
|
|
2015
|
+
}
|
|
2016
|
+
function isJsonObject(data) {
|
|
2017
|
+
return !isJsonScalar(data) && !isJsonArray(data);
|
|
1278
2018
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
2019
|
+
export {
|
|
2020
|
+
isRoomAuthToken as A,
|
|
2021
|
+
isScope as B,
|
|
2022
|
+
ClientMsgCode as C,
|
|
2023
|
+
deprecate as D,
|
|
2024
|
+
deprecateIf as E,
|
|
2025
|
+
throwUsageError as F,
|
|
2026
|
+
comparePosition as G,
|
|
2027
|
+
makePosition as H,
|
|
2028
|
+
CrdtType as I,
|
|
2029
|
+
isJsonScalar as J,
|
|
2030
|
+
isChildCrdt as K,
|
|
2031
|
+
LiveObject as L,
|
|
2032
|
+
b64decode as M,
|
|
2033
|
+
OpSource as O,
|
|
2034
|
+
ServerMsgCode as S,
|
|
2035
|
+
WebsocketCloseCodes as W,
|
|
2036
|
+
__rest as _,
|
|
2037
|
+
isRoomEventName as a,
|
|
2038
|
+
isPlainObject as b,
|
|
2039
|
+
isTokenExpired as c,
|
|
2040
|
+
isSameNodeOrChildOf as d,
|
|
2041
|
+
OpCode as e,
|
|
2042
|
+
isLiveList as f,
|
|
2043
|
+
getTreesDiffOperations as g,
|
|
2044
|
+
isJsonArray as h,
|
|
2045
|
+
isLiveNode as i,
|
|
2046
|
+
compact as j,
|
|
2047
|
+
isRootCrdt as k,
|
|
2048
|
+
isJsonObject as l,
|
|
2049
|
+
mergeStorageUpdates as m,
|
|
2050
|
+
nn as n,
|
|
2051
|
+
errorIf as o,
|
|
2052
|
+
parseRoomAuthToken as p,
|
|
2053
|
+
LiveList as q,
|
|
2054
|
+
remove as r,
|
|
2055
|
+
LiveMap as s,
|
|
2056
|
+
tryParseJson as t,
|
|
2057
|
+
LiveRegister as u,
|
|
2058
|
+
findNonSerializableValue as v,
|
|
2059
|
+
isLiveObject as w,
|
|
2060
|
+
assertNever as x,
|
|
2061
|
+
isAppOnlyAuthToken as y,
|
|
2062
|
+
isAuthToken as z,
|
|
2063
|
+
};
|