@liveblocks/client 0.15.0-alpha.1 → 0.15.0-alpha.4
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/lib/esm/index.js +3006 -5
- package/lib/esm/index.mjs +3006 -0
- package/lib/esm/internal.js +149 -0
- package/lib/esm/internal.mjs +149 -0
- package/lib/{esm/types.d.ts → index.d.ts} +262 -52
- package/lib/index.js +4378 -0
- package/lib/{esm/live.d.ts → internal.d.ts} +46 -34
- package/lib/internal.js +193 -0
- package/package.json +35 -10
- package/lib/cjs/AbstractCrdt.d.ts +0 -67
- package/lib/cjs/AbstractCrdt.js +0 -95
- package/lib/cjs/LiveList.d.ts +0 -144
- package/lib/cjs/LiveList.js +0 -499
- package/lib/cjs/LiveMap.d.ts +0 -91
- package/lib/cjs/LiveMap.js +0 -322
- package/lib/cjs/LiveObject.d.ts +0 -80
- package/lib/cjs/LiveObject.js +0 -453
- package/lib/cjs/LiveRegister.d.ts +0 -29
- package/lib/cjs/LiveRegister.js +0 -88
- package/lib/cjs/authentication.d.ts +0 -3
- package/lib/cjs/authentication.js +0 -71
- package/lib/cjs/client.d.ts +0 -27
- package/lib/cjs/client.js +0 -80
- package/lib/cjs/immutable.d.ts +0 -9
- package/lib/cjs/immutable.js +0 -272
- package/lib/cjs/index.d.ts +0 -6
- package/lib/cjs/index.js +0 -18
- package/lib/cjs/live.d.ts +0 -181
- package/lib/cjs/live.js +0 -49
- package/lib/cjs/position.d.ts +0 -6
- package/lib/cjs/position.js +0 -113
- package/lib/cjs/room.d.ts +0 -159
- package/lib/cjs/room.js +0 -1094
- package/lib/cjs/types.d.ts +0 -484
- package/lib/cjs/types.js +0 -2
- package/lib/cjs/utils.d.ts +0 -11
- package/lib/cjs/utils.js +0 -175
- package/lib/esm/AbstractCrdt.d.ts +0 -67
- package/lib/esm/AbstractCrdt.js +0 -91
- package/lib/esm/LiveList.d.ts +0 -144
- package/lib/esm/LiveList.js +0 -495
- package/lib/esm/LiveMap.d.ts +0 -91
- package/lib/esm/LiveMap.js +0 -318
- package/lib/esm/LiveObject.d.ts +0 -80
- package/lib/esm/LiveObject.js +0 -449
- package/lib/esm/LiveRegister.d.ts +0 -29
- package/lib/esm/LiveRegister.js +0 -84
- package/lib/esm/authentication.d.ts +0 -3
- package/lib/esm/authentication.js +0 -66
- package/lib/esm/client.d.ts +0 -27
- package/lib/esm/client.js +0 -76
- package/lib/esm/immutable.d.ts +0 -9
- package/lib/esm/immutable.js +0 -263
- package/lib/esm/index.d.ts +0 -6
- package/lib/esm/live.js +0 -46
- package/lib/esm/position.d.ts +0 -6
- package/lib/esm/position.js +0 -106
- package/lib/esm/room.d.ts +0 -159
- package/lib/esm/room.js +0 -1069
- package/lib/esm/types.js +0 -1
- package/lib/esm/utils.d.ts +0 -11
- package/lib/esm/utils.js +0 -164
package/lib/esm/index.js
CHANGED
|
@@ -1,5 +1,3006 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
var ServerMessageType = /* @__PURE__ */ ((ServerMessageType2) => {
|
|
2
|
+
ServerMessageType2[ServerMessageType2["UpdatePresence"] = 100] = "UpdatePresence";
|
|
3
|
+
ServerMessageType2[ServerMessageType2["UserJoined"] = 101] = "UserJoined";
|
|
4
|
+
ServerMessageType2[ServerMessageType2["UserLeft"] = 102] = "UserLeft";
|
|
5
|
+
ServerMessageType2[ServerMessageType2["Event"] = 103] = "Event";
|
|
6
|
+
ServerMessageType2[ServerMessageType2["RoomState"] = 104] = "RoomState";
|
|
7
|
+
ServerMessageType2[ServerMessageType2["InitialStorageState"] = 200] = "InitialStorageState";
|
|
8
|
+
ServerMessageType2[ServerMessageType2["UpdateStorage"] = 201] = "UpdateStorage";
|
|
9
|
+
return ServerMessageType2;
|
|
10
|
+
})(ServerMessageType || {});
|
|
11
|
+
var ClientMessageType = /* @__PURE__ */ ((ClientMessageType2) => {
|
|
12
|
+
ClientMessageType2[ClientMessageType2["UpdatePresence"] = 100] = "UpdatePresence";
|
|
13
|
+
ClientMessageType2[ClientMessageType2["ClientEvent"] = 103] = "ClientEvent";
|
|
14
|
+
ClientMessageType2[ClientMessageType2["FetchStorage"] = 200] = "FetchStorage";
|
|
15
|
+
ClientMessageType2[ClientMessageType2["UpdateStorage"] = 201] = "UpdateStorage";
|
|
16
|
+
return ClientMessageType2;
|
|
17
|
+
})(ClientMessageType || {});
|
|
18
|
+
var CrdtType = /* @__PURE__ */ ((CrdtType2) => {
|
|
19
|
+
CrdtType2[CrdtType2["Object"] = 0] = "Object";
|
|
20
|
+
CrdtType2[CrdtType2["List"] = 1] = "List";
|
|
21
|
+
CrdtType2[CrdtType2["Map"] = 2] = "Map";
|
|
22
|
+
CrdtType2[CrdtType2["Register"] = 3] = "Register";
|
|
23
|
+
return CrdtType2;
|
|
24
|
+
})(CrdtType || {});
|
|
25
|
+
var OpType = /* @__PURE__ */ ((OpType2) => {
|
|
26
|
+
OpType2[OpType2["Init"] = 0] = "Init";
|
|
27
|
+
OpType2[OpType2["SetParentKey"] = 1] = "SetParentKey";
|
|
28
|
+
OpType2[OpType2["CreateList"] = 2] = "CreateList";
|
|
29
|
+
OpType2[OpType2["UpdateObject"] = 3] = "UpdateObject";
|
|
30
|
+
OpType2[OpType2["CreateObject"] = 4] = "CreateObject";
|
|
31
|
+
OpType2[OpType2["DeleteCrdt"] = 5] = "DeleteCrdt";
|
|
32
|
+
OpType2[OpType2["DeleteObjectKey"] = 6] = "DeleteObjectKey";
|
|
33
|
+
OpType2[OpType2["CreateMap"] = 7] = "CreateMap";
|
|
34
|
+
OpType2[OpType2["CreateRegister"] = 8] = "CreateRegister";
|
|
35
|
+
return OpType2;
|
|
36
|
+
})(OpType || {});
|
|
37
|
+
|
|
38
|
+
var __accessCheck$4 = (obj, member, msg) => {
|
|
39
|
+
if (!member.has(obj))
|
|
40
|
+
throw TypeError("Cannot " + msg);
|
|
41
|
+
};
|
|
42
|
+
var __privateGet$4 = (obj, member, getter) => {
|
|
43
|
+
__accessCheck$4(obj, member, "read from private field");
|
|
44
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
45
|
+
};
|
|
46
|
+
var __privateAdd$4 = (obj, member, value) => {
|
|
47
|
+
if (member.has(obj))
|
|
48
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
49
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
50
|
+
};
|
|
51
|
+
var __privateSet$4 = (obj, member, value, setter) => {
|
|
52
|
+
__accessCheck$4(obj, member, "write to private field");
|
|
53
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
54
|
+
return value;
|
|
55
|
+
};
|
|
56
|
+
var _parent, _doc, _id, _parentKey;
|
|
57
|
+
class AbstractCrdt {
|
|
58
|
+
constructor() {
|
|
59
|
+
__privateAdd$4(this, _parent, void 0);
|
|
60
|
+
__privateAdd$4(this, _doc, void 0);
|
|
61
|
+
__privateAdd$4(this, _id, void 0);
|
|
62
|
+
__privateAdd$4(this, _parentKey, void 0);
|
|
63
|
+
}
|
|
64
|
+
get _doc() {
|
|
65
|
+
return __privateGet$4(this, _doc);
|
|
66
|
+
}
|
|
67
|
+
get roomId() {
|
|
68
|
+
return __privateGet$4(this, _doc) ? __privateGet$4(this, _doc).roomId : null;
|
|
69
|
+
}
|
|
70
|
+
get _id() {
|
|
71
|
+
return __privateGet$4(this, _id);
|
|
72
|
+
}
|
|
73
|
+
get _parent() {
|
|
74
|
+
return __privateGet$4(this, _parent);
|
|
75
|
+
}
|
|
76
|
+
get _parentKey() {
|
|
77
|
+
return __privateGet$4(this, _parentKey);
|
|
78
|
+
}
|
|
79
|
+
_apply(op, isLocal) {
|
|
80
|
+
switch (op.type) {
|
|
81
|
+
case OpType.DeleteCrdt: {
|
|
82
|
+
if (this._parent != null && this._parentKey != null) {
|
|
83
|
+
return this._parent._detachChild(this);
|
|
84
|
+
}
|
|
85
|
+
return { modified: false };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { modified: false };
|
|
89
|
+
}
|
|
90
|
+
_setParentLink(parent, key) {
|
|
91
|
+
if (__privateGet$4(this, _parent) != null && __privateGet$4(this, _parent) !== parent) {
|
|
92
|
+
throw new Error("Cannot attach parent if it already exist");
|
|
93
|
+
}
|
|
94
|
+
__privateSet$4(this, _parentKey, key);
|
|
95
|
+
__privateSet$4(this, _parent, parent);
|
|
96
|
+
}
|
|
97
|
+
_attach(id, doc) {
|
|
98
|
+
if (__privateGet$4(this, _id) || __privateGet$4(this, _doc)) {
|
|
99
|
+
throw new Error("Cannot attach if CRDT is already attached");
|
|
100
|
+
}
|
|
101
|
+
doc.addItem(id, this);
|
|
102
|
+
__privateSet$4(this, _id, id);
|
|
103
|
+
__privateSet$4(this, _doc, doc);
|
|
104
|
+
}
|
|
105
|
+
_detach() {
|
|
106
|
+
if (__privateGet$4(this, _doc) && __privateGet$4(this, _id)) {
|
|
107
|
+
__privateGet$4(this, _doc).deleteItem(__privateGet$4(this, _id));
|
|
108
|
+
}
|
|
109
|
+
__privateSet$4(this, _parent, void 0);
|
|
110
|
+
__privateSet$4(this, _doc, void 0);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_parent = new WeakMap();
|
|
114
|
+
_doc = new WeakMap();
|
|
115
|
+
_id = new WeakMap();
|
|
116
|
+
_parentKey = new WeakMap();
|
|
117
|
+
|
|
118
|
+
const min = 32;
|
|
119
|
+
const max = 126;
|
|
120
|
+
function makePosition(before, after) {
|
|
121
|
+
if (before == null && after == null) {
|
|
122
|
+
return pos([min + 1]);
|
|
123
|
+
}
|
|
124
|
+
if (before != null && after == null) {
|
|
125
|
+
return getNextPosition(before);
|
|
126
|
+
}
|
|
127
|
+
if (before == null && after != null) {
|
|
128
|
+
return getPreviousPosition(after);
|
|
129
|
+
}
|
|
130
|
+
return pos(makePositionFromCodes(posCodes(before), posCodes(after)));
|
|
131
|
+
}
|
|
132
|
+
function getPreviousPosition(after) {
|
|
133
|
+
const result = [];
|
|
134
|
+
const afterCodes = posCodes(after);
|
|
135
|
+
for (let i = 0; i < afterCodes.length; i++) {
|
|
136
|
+
const code = afterCodes[i];
|
|
137
|
+
if (code <= min + 1) {
|
|
138
|
+
result.push(min);
|
|
139
|
+
if (afterCodes.length - 1 === i) {
|
|
140
|
+
result.push(max);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
result.push(code - 1);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return pos(result);
|
|
149
|
+
}
|
|
150
|
+
function getNextPosition(before) {
|
|
151
|
+
const result = [];
|
|
152
|
+
const beforeCodes = posCodes(before);
|
|
153
|
+
for (let i = 0; i < beforeCodes.length; i++) {
|
|
154
|
+
const code = beforeCodes[i];
|
|
155
|
+
if (code === max) {
|
|
156
|
+
result.push(code);
|
|
157
|
+
if (beforeCodes.length - 1 === i) {
|
|
158
|
+
result.push(min + 1);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
result.push(code + 1);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return pos(result);
|
|
167
|
+
}
|
|
168
|
+
function makePositionFromCodes(before, after) {
|
|
169
|
+
let index = 0;
|
|
170
|
+
const result = [];
|
|
171
|
+
while (true) {
|
|
172
|
+
const beforeDigit = before[index] || min;
|
|
173
|
+
const afterDigit = after[index] || max;
|
|
174
|
+
if (beforeDigit > afterDigit) {
|
|
175
|
+
throw new Error(`Impossible to generate position between ${before} and ${after}`);
|
|
176
|
+
}
|
|
177
|
+
if (beforeDigit === afterDigit) {
|
|
178
|
+
result.push(beforeDigit);
|
|
179
|
+
index++;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (afterDigit - beforeDigit === 1) {
|
|
183
|
+
result.push(beforeDigit);
|
|
184
|
+
result.push(...makePositionFromCodes(before.slice(index + 1), []));
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
const mid = afterDigit + beforeDigit >> 1;
|
|
188
|
+
result.push(mid);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
function posCodes(str) {
|
|
194
|
+
const codes = [];
|
|
195
|
+
for (let i = 0; i < str.length; i++) {
|
|
196
|
+
codes.push(str.charCodeAt(i));
|
|
197
|
+
}
|
|
198
|
+
return codes;
|
|
199
|
+
}
|
|
200
|
+
function pos(codes) {
|
|
201
|
+
return String.fromCharCode(...codes);
|
|
202
|
+
}
|
|
203
|
+
function compare(posA, posB) {
|
|
204
|
+
const aCodes = posCodes(posA);
|
|
205
|
+
const bCodes = posCodes(posB);
|
|
206
|
+
const maxLength = Math.max(aCodes.length, bCodes.length);
|
|
207
|
+
for (let i = 0; i < maxLength; i++) {
|
|
208
|
+
const a = aCodes[i] == null ? min : aCodes[i];
|
|
209
|
+
const b = bCodes[i] == null ? min : bCodes[i];
|
|
210
|
+
if (a === b) {
|
|
211
|
+
continue;
|
|
212
|
+
} else {
|
|
213
|
+
return a - b;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
throw new Error(`Impossible to compare similar position "${posA}" and "${posB}"`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
var __accessCheck$3 = (obj, member, msg) => {
|
|
220
|
+
if (!member.has(obj))
|
|
221
|
+
throw TypeError("Cannot " + msg);
|
|
222
|
+
};
|
|
223
|
+
var __privateGet$3 = (obj, member, getter) => {
|
|
224
|
+
__accessCheck$3(obj, member, "read from private field");
|
|
225
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
226
|
+
};
|
|
227
|
+
var __privateAdd$3 = (obj, member, value) => {
|
|
228
|
+
if (member.has(obj))
|
|
229
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
230
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
231
|
+
};
|
|
232
|
+
var __privateSet$3 = (obj, member, value, setter) => {
|
|
233
|
+
__accessCheck$3(obj, member, "write to private field");
|
|
234
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
235
|
+
return value;
|
|
236
|
+
};
|
|
237
|
+
var _data;
|
|
238
|
+
const _LiveRegister = class extends AbstractCrdt {
|
|
239
|
+
constructor(data) {
|
|
240
|
+
super();
|
|
241
|
+
__privateAdd$3(this, _data, void 0);
|
|
242
|
+
__privateSet$3(this, _data, data);
|
|
243
|
+
}
|
|
244
|
+
get data() {
|
|
245
|
+
return __privateGet$3(this, _data);
|
|
246
|
+
}
|
|
247
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
248
|
+
if (item.type !== CrdtType.Register) {
|
|
249
|
+
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
|
|
250
|
+
}
|
|
251
|
+
const register = new _LiveRegister(item.data);
|
|
252
|
+
register._attach(id, doc);
|
|
253
|
+
return register;
|
|
254
|
+
}
|
|
255
|
+
_serialize(parentId, parentKey, doc) {
|
|
256
|
+
if (this._id == null || parentId == null || parentKey == null) {
|
|
257
|
+
throw new Error("Cannot serialize register if parentId or parentKey is undefined");
|
|
258
|
+
}
|
|
259
|
+
return [
|
|
260
|
+
{
|
|
261
|
+
type: OpType.CreateRegister,
|
|
262
|
+
opId: doc == null ? void 0 : doc.generateOpId(),
|
|
263
|
+
id: this._id,
|
|
264
|
+
parentId,
|
|
265
|
+
parentKey,
|
|
266
|
+
data: this.data
|
|
267
|
+
}
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
_toSerializedCrdt() {
|
|
271
|
+
var _a;
|
|
272
|
+
return {
|
|
273
|
+
type: CrdtType.Register,
|
|
274
|
+
parentId: (_a = this._parent) == null ? void 0 : _a._id,
|
|
275
|
+
parentKey: this._parentKey,
|
|
276
|
+
data: this.data
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
_attachChild(id, key, crdt, opId, isLocal) {
|
|
280
|
+
throw new Error("Method not implemented.");
|
|
281
|
+
}
|
|
282
|
+
_detachChild(crdt) {
|
|
283
|
+
throw new Error("Method not implemented.");
|
|
284
|
+
}
|
|
285
|
+
_apply(op, isLocal) {
|
|
286
|
+
return super._apply(op, isLocal);
|
|
287
|
+
}
|
|
288
|
+
_getType() {
|
|
289
|
+
return "LiveRegister";
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
let LiveRegister = _LiveRegister;
|
|
293
|
+
_data = new WeakMap();
|
|
294
|
+
|
|
295
|
+
var __accessCheck$2 = (obj, member, msg) => {
|
|
296
|
+
if (!member.has(obj))
|
|
297
|
+
throw TypeError("Cannot " + msg);
|
|
298
|
+
};
|
|
299
|
+
var __privateGet$2 = (obj, member, getter) => {
|
|
300
|
+
__accessCheck$2(obj, member, "read from private field");
|
|
301
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
302
|
+
};
|
|
303
|
+
var __privateAdd$2 = (obj, member, value) => {
|
|
304
|
+
if (member.has(obj))
|
|
305
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
306
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
307
|
+
};
|
|
308
|
+
var __privateSet$2 = (obj, member, value, setter) => {
|
|
309
|
+
__accessCheck$2(obj, member, "write to private field");
|
|
310
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
311
|
+
return value;
|
|
312
|
+
};
|
|
313
|
+
var _items, _innerIterator;
|
|
314
|
+
const _LiveList = class extends AbstractCrdt {
|
|
315
|
+
constructor(items = []) {
|
|
316
|
+
super();
|
|
317
|
+
__privateAdd$2(this, _items, []);
|
|
318
|
+
let position = void 0;
|
|
319
|
+
for (let i = 0; i < items.length; i++) {
|
|
320
|
+
const newPosition = makePosition(position);
|
|
321
|
+
const item = selfOrRegister(items[i]);
|
|
322
|
+
__privateGet$2(this, _items).push([item, newPosition]);
|
|
323
|
+
position = newPosition;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
327
|
+
const list = new _LiveList([]);
|
|
328
|
+
list._attach(id, doc);
|
|
329
|
+
const children = parentToChildren.get(id);
|
|
330
|
+
if (children == null) {
|
|
331
|
+
return list;
|
|
332
|
+
}
|
|
333
|
+
for (const entry of children) {
|
|
334
|
+
const child = deserialize(entry, parentToChildren, doc);
|
|
335
|
+
child._setParentLink(list, entry[1].parentKey);
|
|
336
|
+
__privateGet$2(list, _items).push([child, entry[1].parentKey]);
|
|
337
|
+
__privateGet$2(list, _items).sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
338
|
+
}
|
|
339
|
+
return list;
|
|
340
|
+
}
|
|
341
|
+
_serialize(parentId, parentKey, doc) {
|
|
342
|
+
if (this._id == null) {
|
|
343
|
+
throw new Error("Cannot serialize item is not attached");
|
|
344
|
+
}
|
|
345
|
+
if (parentId == null || parentKey == null) {
|
|
346
|
+
throw new Error("Cannot serialize list if parentId or parentKey is undefined");
|
|
347
|
+
}
|
|
348
|
+
const ops = [];
|
|
349
|
+
const op = {
|
|
350
|
+
id: this._id,
|
|
351
|
+
opId: doc == null ? void 0 : doc.generateOpId(),
|
|
352
|
+
type: OpType.CreateList,
|
|
353
|
+
parentId,
|
|
354
|
+
parentKey
|
|
355
|
+
};
|
|
356
|
+
ops.push(op);
|
|
357
|
+
for (const [value, key] of __privateGet$2(this, _items)) {
|
|
358
|
+
ops.push(...value._serialize(this._id, key, doc));
|
|
359
|
+
}
|
|
360
|
+
return ops;
|
|
361
|
+
}
|
|
362
|
+
_indexOfPosition(position) {
|
|
363
|
+
return __privateGet$2(this, _items).findIndex((item) => item[1] === position);
|
|
364
|
+
}
|
|
365
|
+
_attach(id, doc) {
|
|
366
|
+
super._attach(id, doc);
|
|
367
|
+
for (const [item, position] of __privateGet$2(this, _items)) {
|
|
368
|
+
item._attach(doc.generateId(), doc);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
_detach() {
|
|
372
|
+
super._detach();
|
|
373
|
+
for (const [value] of __privateGet$2(this, _items)) {
|
|
374
|
+
value._detach();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
378
|
+
var _a;
|
|
379
|
+
if (this._doc == null) {
|
|
380
|
+
throw new Error("Can't attach child if doc is not present");
|
|
381
|
+
}
|
|
382
|
+
if (this._doc.getItem(id) !== void 0) {
|
|
383
|
+
return { modified: false };
|
|
384
|
+
}
|
|
385
|
+
child._attach(id, this._doc);
|
|
386
|
+
child._setParentLink(this, key);
|
|
387
|
+
const index = __privateGet$2(this, _items).findIndex((entry) => entry[1] === key);
|
|
388
|
+
let newKey = key;
|
|
389
|
+
if (index !== -1) {
|
|
390
|
+
if (isLocal) {
|
|
391
|
+
let before = __privateGet$2(this, _items)[index] ? __privateGet$2(this, _items)[index][1] : void 0;
|
|
392
|
+
let after = __privateGet$2(this, _items)[index + 1] ? __privateGet$2(this, _items)[index + 1][1] : void 0;
|
|
393
|
+
newKey = makePosition(before, after);
|
|
394
|
+
child._setParentLink(this, newKey);
|
|
395
|
+
} else {
|
|
396
|
+
__privateGet$2(this, _items)[index][1] = makePosition(key, (_a = __privateGet$2(this, _items)[index + 1]) == null ? void 0 : _a[1]);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
__privateGet$2(this, _items).push([child, newKey]);
|
|
400
|
+
__privateGet$2(this, _items).sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
401
|
+
const newIndex = __privateGet$2(this, _items).findIndex((entry) => entry[1] === newKey);
|
|
402
|
+
return {
|
|
403
|
+
reverse: [{ type: OpType.DeleteCrdt, id }],
|
|
404
|
+
modified: {
|
|
405
|
+
node: this,
|
|
406
|
+
type: "LiveList",
|
|
407
|
+
updates: [
|
|
408
|
+
{
|
|
409
|
+
index: newIndex,
|
|
410
|
+
type: "insert",
|
|
411
|
+
item: child instanceof LiveRegister ? child.data : child
|
|
412
|
+
}
|
|
413
|
+
]
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
_detachChild(child) {
|
|
418
|
+
if (child) {
|
|
419
|
+
const reverse = child._serialize(this._id, child._parentKey, this._doc);
|
|
420
|
+
const indexToDelete = __privateGet$2(this, _items).findIndex((item) => item[0] === child);
|
|
421
|
+
__privateGet$2(this, _items).splice(indexToDelete, 1);
|
|
422
|
+
child._detach();
|
|
423
|
+
const storageUpdate = {
|
|
424
|
+
node: this,
|
|
425
|
+
type: "LiveList",
|
|
426
|
+
updates: [{ index: indexToDelete, type: "delete" }]
|
|
427
|
+
};
|
|
428
|
+
return { modified: storageUpdate, reverse };
|
|
429
|
+
}
|
|
430
|
+
return { modified: false };
|
|
431
|
+
}
|
|
432
|
+
_setChildKey(key, child, previousKey) {
|
|
433
|
+
var _a;
|
|
434
|
+
child._setParentLink(this, key);
|
|
435
|
+
const previousIndex = __privateGet$2(this, _items).findIndex((entry) => entry[0]._id === child._id);
|
|
436
|
+
const index = __privateGet$2(this, _items).findIndex((entry) => entry[1] === key);
|
|
437
|
+
if (index !== -1) {
|
|
438
|
+
__privateGet$2(this, _items)[index][1] = makePosition(key, (_a = __privateGet$2(this, _items)[index + 1]) == null ? void 0 : _a[1]);
|
|
439
|
+
}
|
|
440
|
+
const item = __privateGet$2(this, _items).find((item2) => item2[0] === child);
|
|
441
|
+
if (item) {
|
|
442
|
+
item[1] = key;
|
|
443
|
+
}
|
|
444
|
+
__privateGet$2(this, _items).sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
445
|
+
const newIndex = __privateGet$2(this, _items).findIndex((entry) => entry[0]._id === child._id);
|
|
446
|
+
const updatesDelta = newIndex === previousIndex ? [] : [
|
|
447
|
+
{
|
|
448
|
+
index: newIndex,
|
|
449
|
+
item: child instanceof LiveRegister ? child.data : child,
|
|
450
|
+
previousIndex,
|
|
451
|
+
type: "move"
|
|
452
|
+
}
|
|
453
|
+
];
|
|
454
|
+
return {
|
|
455
|
+
modified: {
|
|
456
|
+
node: this,
|
|
457
|
+
type: "LiveList",
|
|
458
|
+
updates: updatesDelta
|
|
459
|
+
},
|
|
460
|
+
reverse: [
|
|
461
|
+
{
|
|
462
|
+
type: OpType.SetParentKey,
|
|
463
|
+
id: item == null ? void 0 : item[0]._id,
|
|
464
|
+
parentKey: previousKey
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
_apply(op, isLocal) {
|
|
470
|
+
return super._apply(op, isLocal);
|
|
471
|
+
}
|
|
472
|
+
_getType() {
|
|
473
|
+
return "LiveList";
|
|
474
|
+
}
|
|
475
|
+
_toSerializedCrdt() {
|
|
476
|
+
var _a;
|
|
477
|
+
return {
|
|
478
|
+
type: CrdtType.List,
|
|
479
|
+
parentId: (_a = this._parent) == null ? void 0 : _a._id,
|
|
480
|
+
parentKey: this._parentKey
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
get length() {
|
|
484
|
+
return __privateGet$2(this, _items).length;
|
|
485
|
+
}
|
|
486
|
+
push(element) {
|
|
487
|
+
return this.insert(element, this.length);
|
|
488
|
+
}
|
|
489
|
+
insert(element, index) {
|
|
490
|
+
if (index < 0 || index > __privateGet$2(this, _items).length) {
|
|
491
|
+
throw new Error(`Cannot insert list item at index "${index}". index should be between 0 and ${__privateGet$2(this, _items).length}`);
|
|
492
|
+
}
|
|
493
|
+
let before = __privateGet$2(this, _items)[index - 1] ? __privateGet$2(this, _items)[index - 1][1] : void 0;
|
|
494
|
+
let after = __privateGet$2(this, _items)[index] ? __privateGet$2(this, _items)[index][1] : void 0;
|
|
495
|
+
const position = makePosition(before, after);
|
|
496
|
+
const value = selfOrRegister(element);
|
|
497
|
+
value._setParentLink(this, position);
|
|
498
|
+
__privateGet$2(this, _items).push([value, position]);
|
|
499
|
+
__privateGet$2(this, _items).sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
500
|
+
const newIndex = __privateGet$2(this, _items).findIndex((entry) => entry[1] === position);
|
|
501
|
+
if (this._doc && this._id) {
|
|
502
|
+
const id = this._doc.generateId();
|
|
503
|
+
value._attach(id, this._doc);
|
|
504
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
505
|
+
storageUpdates.set(this._id, {
|
|
506
|
+
node: this,
|
|
507
|
+
type: "LiveList",
|
|
508
|
+
updates: [
|
|
509
|
+
{
|
|
510
|
+
index: newIndex,
|
|
511
|
+
item: value instanceof LiveRegister ? value.data : value,
|
|
512
|
+
type: "insert"
|
|
513
|
+
}
|
|
514
|
+
]
|
|
515
|
+
});
|
|
516
|
+
this._doc.dispatch(value._serialize(this._id, position, this._doc), [{ type: OpType.DeleteCrdt, id }], storageUpdates);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
move(index, targetIndex) {
|
|
520
|
+
if (targetIndex < 0) {
|
|
521
|
+
throw new Error("targetIndex cannot be less than 0");
|
|
522
|
+
}
|
|
523
|
+
if (targetIndex >= __privateGet$2(this, _items).length) {
|
|
524
|
+
throw new Error("targetIndex cannot be greater or equal than the list length");
|
|
525
|
+
}
|
|
526
|
+
if (index < 0) {
|
|
527
|
+
throw new Error("index cannot be less than 0");
|
|
528
|
+
}
|
|
529
|
+
if (index >= __privateGet$2(this, _items).length) {
|
|
530
|
+
throw new Error("index cannot be greater or equal than the list length");
|
|
531
|
+
}
|
|
532
|
+
let beforePosition = null;
|
|
533
|
+
let afterPosition = null;
|
|
534
|
+
if (index < targetIndex) {
|
|
535
|
+
afterPosition = targetIndex === __privateGet$2(this, _items).length - 1 ? void 0 : __privateGet$2(this, _items)[targetIndex + 1][1];
|
|
536
|
+
beforePosition = __privateGet$2(this, _items)[targetIndex][1];
|
|
537
|
+
} else {
|
|
538
|
+
afterPosition = __privateGet$2(this, _items)[targetIndex][1];
|
|
539
|
+
beforePosition = targetIndex === 0 ? void 0 : __privateGet$2(this, _items)[targetIndex - 1][1];
|
|
540
|
+
}
|
|
541
|
+
const position = makePosition(beforePosition, afterPosition);
|
|
542
|
+
const item = __privateGet$2(this, _items)[index];
|
|
543
|
+
const previousPosition = item[1];
|
|
544
|
+
item[1] = position;
|
|
545
|
+
item[0]._setParentLink(this, position);
|
|
546
|
+
__privateGet$2(this, _items).sort((itemA, itemB) => compare(itemA[1], itemB[1]));
|
|
547
|
+
const newIndex = __privateGet$2(this, _items).findIndex((entry) => entry[1] === position);
|
|
548
|
+
if (this._doc && this._id) {
|
|
549
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
550
|
+
storageUpdates.set(this._id, {
|
|
551
|
+
node: this,
|
|
552
|
+
type: "LiveList",
|
|
553
|
+
updates: [
|
|
554
|
+
{
|
|
555
|
+
index: newIndex,
|
|
556
|
+
previousIndex: index,
|
|
557
|
+
item: item[0],
|
|
558
|
+
type: "move"
|
|
559
|
+
}
|
|
560
|
+
]
|
|
561
|
+
});
|
|
562
|
+
this._doc.dispatch([
|
|
563
|
+
{
|
|
564
|
+
type: OpType.SetParentKey,
|
|
565
|
+
id: item[0]._id,
|
|
566
|
+
opId: this._doc.generateOpId(),
|
|
567
|
+
parentKey: position
|
|
568
|
+
}
|
|
569
|
+
], [
|
|
570
|
+
{
|
|
571
|
+
type: OpType.SetParentKey,
|
|
572
|
+
id: item[0]._id,
|
|
573
|
+
parentKey: previousPosition
|
|
574
|
+
}
|
|
575
|
+
], storageUpdates);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
delete(index) {
|
|
579
|
+
if (index < 0 || index >= __privateGet$2(this, _items).length) {
|
|
580
|
+
throw new Error(`Cannot delete list item at index "${index}". index should be between 0 and ${__privateGet$2(this, _items).length - 1}`);
|
|
581
|
+
}
|
|
582
|
+
const item = __privateGet$2(this, _items)[index];
|
|
583
|
+
item[0]._detach();
|
|
584
|
+
__privateGet$2(this, _items).splice(index, 1);
|
|
585
|
+
if (this._doc) {
|
|
586
|
+
const childRecordId = item[0]._id;
|
|
587
|
+
if (childRecordId) {
|
|
588
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
589
|
+
storageUpdates.set(this._id, {
|
|
590
|
+
node: this,
|
|
591
|
+
type: "LiveList",
|
|
592
|
+
updates: [{ index, type: "delete" }]
|
|
593
|
+
});
|
|
594
|
+
this._doc.dispatch([
|
|
595
|
+
{
|
|
596
|
+
id: childRecordId,
|
|
597
|
+
opId: this._doc.generateOpId(),
|
|
598
|
+
type: OpType.DeleteCrdt
|
|
599
|
+
}
|
|
600
|
+
], item[0]._serialize(this._id, item[1]), storageUpdates);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
clear() {
|
|
605
|
+
if (this._doc) {
|
|
606
|
+
let ops = [];
|
|
607
|
+
let reverseOps = [];
|
|
608
|
+
let updateDelta = [];
|
|
609
|
+
let i = 0;
|
|
610
|
+
for (const item of __privateGet$2(this, _items)) {
|
|
611
|
+
item[0]._detach();
|
|
612
|
+
const childId = item[0]._id;
|
|
613
|
+
if (childId) {
|
|
614
|
+
ops.push({ id: childId, type: OpType.DeleteCrdt });
|
|
615
|
+
reverseOps.push(...item[0]._serialize(this._id, item[1]));
|
|
616
|
+
updateDelta.push({ index: i, type: "delete" });
|
|
617
|
+
}
|
|
618
|
+
i++;
|
|
619
|
+
}
|
|
620
|
+
__privateSet$2(this, _items, []);
|
|
621
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
622
|
+
storageUpdates.set(this._id, {
|
|
623
|
+
node: this,
|
|
624
|
+
type: "LiveList",
|
|
625
|
+
updates: updateDelta
|
|
626
|
+
});
|
|
627
|
+
this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
628
|
+
} else {
|
|
629
|
+
for (const item of __privateGet$2(this, _items)) {
|
|
630
|
+
item[0]._detach();
|
|
631
|
+
}
|
|
632
|
+
__privateSet$2(this, _items, []);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
toArray() {
|
|
636
|
+
return __privateGet$2(this, _items).map((entry) => selfOrRegisterValue(entry[0]));
|
|
637
|
+
}
|
|
638
|
+
every(predicate) {
|
|
639
|
+
return this.toArray().every(predicate);
|
|
640
|
+
}
|
|
641
|
+
filter(predicate) {
|
|
642
|
+
return this.toArray().filter(predicate);
|
|
643
|
+
}
|
|
644
|
+
find(predicate) {
|
|
645
|
+
return this.toArray().find(predicate);
|
|
646
|
+
}
|
|
647
|
+
findIndex(predicate) {
|
|
648
|
+
return this.toArray().findIndex(predicate);
|
|
649
|
+
}
|
|
650
|
+
forEach(callbackfn) {
|
|
651
|
+
return this.toArray().forEach(callbackfn);
|
|
652
|
+
}
|
|
653
|
+
get(index) {
|
|
654
|
+
if (index < 0 || index >= __privateGet$2(this, _items).length) {
|
|
655
|
+
return void 0;
|
|
656
|
+
}
|
|
657
|
+
return selfOrRegisterValue(__privateGet$2(this, _items)[index][0]);
|
|
658
|
+
}
|
|
659
|
+
indexOf(searchElement, fromIndex) {
|
|
660
|
+
return this.toArray().indexOf(searchElement, fromIndex);
|
|
661
|
+
}
|
|
662
|
+
lastIndexOf(searchElement, fromIndex) {
|
|
663
|
+
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
664
|
+
}
|
|
665
|
+
map(callback) {
|
|
666
|
+
return __privateGet$2(this, _items).map((entry, i) => callback(selfOrRegisterValue(entry[0]), i));
|
|
667
|
+
}
|
|
668
|
+
some(predicate) {
|
|
669
|
+
return this.toArray().some(predicate);
|
|
670
|
+
}
|
|
671
|
+
[Symbol.iterator]() {
|
|
672
|
+
return new LiveListIterator(__privateGet$2(this, _items));
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
let LiveList = _LiveList;
|
|
676
|
+
_items = new WeakMap();
|
|
677
|
+
class LiveListIterator {
|
|
678
|
+
constructor(items) {
|
|
679
|
+
__privateAdd$2(this, _innerIterator, void 0);
|
|
680
|
+
__privateSet$2(this, _innerIterator, items[Symbol.iterator]());
|
|
681
|
+
}
|
|
682
|
+
[Symbol.iterator]() {
|
|
683
|
+
return this;
|
|
684
|
+
}
|
|
685
|
+
next() {
|
|
686
|
+
const result = __privateGet$2(this, _innerIterator).next();
|
|
687
|
+
if (result.done) {
|
|
688
|
+
return {
|
|
689
|
+
done: true,
|
|
690
|
+
value: void 0
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
return {
|
|
694
|
+
value: selfOrRegisterValue(result.value[0])
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
_innerIterator = new WeakMap();
|
|
699
|
+
|
|
700
|
+
var __accessCheck$1 = (obj, member, msg) => {
|
|
701
|
+
if (!member.has(obj))
|
|
702
|
+
throw TypeError("Cannot " + msg);
|
|
703
|
+
};
|
|
704
|
+
var __privateGet$1 = (obj, member, getter) => {
|
|
705
|
+
__accessCheck$1(obj, member, "read from private field");
|
|
706
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
707
|
+
};
|
|
708
|
+
var __privateAdd$1 = (obj, member, value) => {
|
|
709
|
+
if (member.has(obj))
|
|
710
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
711
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
712
|
+
};
|
|
713
|
+
var __privateSet$1 = (obj, member, value, setter) => {
|
|
714
|
+
__accessCheck$1(obj, member, "write to private field");
|
|
715
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
716
|
+
return value;
|
|
717
|
+
};
|
|
718
|
+
var _map$1;
|
|
719
|
+
const _LiveMap = class extends AbstractCrdt {
|
|
720
|
+
constructor(entries) {
|
|
721
|
+
super();
|
|
722
|
+
__privateAdd$1(this, _map$1, void 0);
|
|
723
|
+
if (entries) {
|
|
724
|
+
const mappedEntries = [];
|
|
725
|
+
for (const entry of entries) {
|
|
726
|
+
const value = selfOrRegister(entry[1]);
|
|
727
|
+
value._setParentLink(this, entry[0]);
|
|
728
|
+
mappedEntries.push([entry[0], value]);
|
|
729
|
+
}
|
|
730
|
+
__privateSet$1(this, _map$1, new Map(mappedEntries));
|
|
731
|
+
} else {
|
|
732
|
+
__privateSet$1(this, _map$1, /* @__PURE__ */ new Map());
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
_serialize(parentId, parentKey, doc) {
|
|
736
|
+
if (this._id == null) {
|
|
737
|
+
throw new Error("Cannot serialize item is not attached");
|
|
738
|
+
}
|
|
739
|
+
if (parentId == null || parentKey == null) {
|
|
740
|
+
throw new Error("Cannot serialize map if parentId or parentKey is undefined");
|
|
741
|
+
}
|
|
742
|
+
const ops = [];
|
|
743
|
+
const op = {
|
|
744
|
+
id: this._id,
|
|
745
|
+
opId: doc == null ? void 0 : doc.generateOpId(),
|
|
746
|
+
type: OpType.CreateMap,
|
|
747
|
+
parentId,
|
|
748
|
+
parentKey
|
|
749
|
+
};
|
|
750
|
+
ops.push(op);
|
|
751
|
+
for (const [key, value] of __privateGet$1(this, _map$1)) {
|
|
752
|
+
ops.push(...value._serialize(this._id, key, doc));
|
|
753
|
+
}
|
|
754
|
+
return ops;
|
|
755
|
+
}
|
|
756
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
757
|
+
if (item.type !== CrdtType.Map) {
|
|
758
|
+
throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
|
|
759
|
+
}
|
|
760
|
+
const map = new _LiveMap();
|
|
761
|
+
map._attach(id, doc);
|
|
762
|
+
const children = parentToChildren.get(id);
|
|
763
|
+
if (children == null) {
|
|
764
|
+
return map;
|
|
765
|
+
}
|
|
766
|
+
for (const entry of children) {
|
|
767
|
+
const crdt = entry[1];
|
|
768
|
+
if (crdt.parentKey == null) {
|
|
769
|
+
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
770
|
+
}
|
|
771
|
+
const child = deserialize(entry, parentToChildren, doc);
|
|
772
|
+
child._setParentLink(map, crdt.parentKey);
|
|
773
|
+
__privateGet$1(map, _map$1).set(crdt.parentKey, child);
|
|
774
|
+
}
|
|
775
|
+
return map;
|
|
776
|
+
}
|
|
777
|
+
_attach(id, doc) {
|
|
778
|
+
super._attach(id, doc);
|
|
779
|
+
for (const [key, value] of __privateGet$1(this, _map$1)) {
|
|
780
|
+
if (isCrdt(value)) {
|
|
781
|
+
value._attach(doc.generateId(), doc);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
786
|
+
if (this._doc == null) {
|
|
787
|
+
throw new Error("Can't attach child if doc is not present");
|
|
788
|
+
}
|
|
789
|
+
if (this._doc.getItem(id) !== void 0) {
|
|
790
|
+
return { modified: false };
|
|
791
|
+
}
|
|
792
|
+
const previousValue = __privateGet$1(this, _map$1).get(key);
|
|
793
|
+
let reverse;
|
|
794
|
+
if (previousValue) {
|
|
795
|
+
reverse = previousValue._serialize(this._id, key);
|
|
796
|
+
previousValue._detach();
|
|
797
|
+
} else {
|
|
798
|
+
reverse = [{ type: OpType.DeleteCrdt, id }];
|
|
799
|
+
}
|
|
800
|
+
child._setParentLink(this, key);
|
|
801
|
+
child._attach(id, this._doc);
|
|
802
|
+
__privateGet$1(this, _map$1).set(key, child);
|
|
803
|
+
return {
|
|
804
|
+
modified: {
|
|
805
|
+
node: this,
|
|
806
|
+
type: "LiveMap",
|
|
807
|
+
updates: { [key]: { type: "update" } }
|
|
808
|
+
},
|
|
809
|
+
reverse
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
_detach() {
|
|
813
|
+
super._detach();
|
|
814
|
+
for (const item of __privateGet$1(this, _map$1).values()) {
|
|
815
|
+
item._detach();
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
_detachChild(child) {
|
|
819
|
+
const reverse = child._serialize(this._id, child._parentKey, this._doc);
|
|
820
|
+
for (const [key, value] of __privateGet$1(this, _map$1)) {
|
|
821
|
+
if (value === child) {
|
|
822
|
+
__privateGet$1(this, _map$1).delete(key);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
child._detach();
|
|
826
|
+
const storageUpdate = {
|
|
827
|
+
node: this,
|
|
828
|
+
type: "LiveMap",
|
|
829
|
+
updates: { [child._parentKey]: { type: "delete" } }
|
|
830
|
+
};
|
|
831
|
+
return { modified: storageUpdate, reverse };
|
|
832
|
+
}
|
|
833
|
+
_getType() {
|
|
834
|
+
return "LiveMap";
|
|
835
|
+
}
|
|
836
|
+
_toSerializedCrdt() {
|
|
837
|
+
var _a;
|
|
838
|
+
return {
|
|
839
|
+
type: CrdtType.Map,
|
|
840
|
+
parentId: (_a = this._parent) == null ? void 0 : _a._id,
|
|
841
|
+
parentKey: this._parentKey
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
get(key) {
|
|
845
|
+
const value = __privateGet$1(this, _map$1).get(key);
|
|
846
|
+
if (value == void 0) {
|
|
847
|
+
return void 0;
|
|
848
|
+
}
|
|
849
|
+
return selfOrRegisterValue(value);
|
|
850
|
+
}
|
|
851
|
+
set(key, value) {
|
|
852
|
+
const oldValue = __privateGet$1(this, _map$1).get(key);
|
|
853
|
+
if (oldValue) {
|
|
854
|
+
oldValue._detach();
|
|
855
|
+
}
|
|
856
|
+
const item = selfOrRegister(value);
|
|
857
|
+
item._setParentLink(this, key);
|
|
858
|
+
__privateGet$1(this, _map$1).set(key, item);
|
|
859
|
+
if (this._doc && this._id) {
|
|
860
|
+
const id = this._doc.generateId();
|
|
861
|
+
item._attach(id, this._doc);
|
|
862
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
863
|
+
storageUpdates.set(this._id, {
|
|
864
|
+
node: this,
|
|
865
|
+
type: "LiveMap",
|
|
866
|
+
updates: { [key]: { type: "update" } }
|
|
867
|
+
});
|
|
868
|
+
this._doc.dispatch(item._serialize(this._id, key, this._doc), oldValue ? oldValue._serialize(this._id, key) : [{ type: OpType.DeleteCrdt, id }], storageUpdates);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
get size() {
|
|
872
|
+
return __privateGet$1(this, _map$1).size;
|
|
873
|
+
}
|
|
874
|
+
has(key) {
|
|
875
|
+
return __privateGet$1(this, _map$1).has(key);
|
|
876
|
+
}
|
|
877
|
+
delete(key) {
|
|
878
|
+
const item = __privateGet$1(this, _map$1).get(key);
|
|
879
|
+
if (item == null) {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
item._detach();
|
|
883
|
+
if (this._doc && item._id) {
|
|
884
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
885
|
+
storageUpdates.set(this._id, {
|
|
886
|
+
node: this,
|
|
887
|
+
type: "LiveMap",
|
|
888
|
+
updates: { [key]: { type: "delete" } }
|
|
889
|
+
});
|
|
890
|
+
this._doc.dispatch([
|
|
891
|
+
{
|
|
892
|
+
type: OpType.DeleteCrdt,
|
|
893
|
+
id: item._id,
|
|
894
|
+
opId: this._doc.generateOpId()
|
|
895
|
+
}
|
|
896
|
+
], item._serialize(this._id, key), storageUpdates);
|
|
897
|
+
}
|
|
898
|
+
__privateGet$1(this, _map$1).delete(key);
|
|
899
|
+
return true;
|
|
900
|
+
}
|
|
901
|
+
entries() {
|
|
902
|
+
const innerIterator = __privateGet$1(this, _map$1).entries();
|
|
903
|
+
return {
|
|
904
|
+
[Symbol.iterator]: function() {
|
|
905
|
+
return this;
|
|
906
|
+
},
|
|
907
|
+
next() {
|
|
908
|
+
const iteratorValue = innerIterator.next();
|
|
909
|
+
if (iteratorValue.done) {
|
|
910
|
+
return {
|
|
911
|
+
done: true,
|
|
912
|
+
value: void 0
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
const entry = iteratorValue.value;
|
|
916
|
+
return {
|
|
917
|
+
value: [entry[0], selfOrRegisterValue(iteratorValue.value[1])]
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
[Symbol.iterator]() {
|
|
923
|
+
return this.entries();
|
|
924
|
+
}
|
|
925
|
+
keys() {
|
|
926
|
+
return __privateGet$1(this, _map$1).keys();
|
|
927
|
+
}
|
|
928
|
+
values() {
|
|
929
|
+
const innerIterator = __privateGet$1(this, _map$1).values();
|
|
930
|
+
return {
|
|
931
|
+
[Symbol.iterator]: function() {
|
|
932
|
+
return this;
|
|
933
|
+
},
|
|
934
|
+
next() {
|
|
935
|
+
const iteratorValue = innerIterator.next();
|
|
936
|
+
if (iteratorValue.done) {
|
|
937
|
+
return {
|
|
938
|
+
done: true,
|
|
939
|
+
value: void 0
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
return {
|
|
943
|
+
value: selfOrRegisterValue(iteratorValue.value)
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
forEach(callback) {
|
|
949
|
+
for (const entry of this) {
|
|
950
|
+
callback(entry[1], entry[0], this);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
let LiveMap = _LiveMap;
|
|
955
|
+
_map$1 = new WeakMap();
|
|
956
|
+
|
|
957
|
+
var __defProp$2 = Object.defineProperty;
|
|
958
|
+
var __defProps$2 = Object.defineProperties;
|
|
959
|
+
var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
|
|
960
|
+
var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
|
|
961
|
+
var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
|
|
962
|
+
var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
|
|
963
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
964
|
+
var __spreadValues$2 = (a, b) => {
|
|
965
|
+
for (var prop in b || (b = {}))
|
|
966
|
+
if (__hasOwnProp$2.call(b, prop))
|
|
967
|
+
__defNormalProp$2(a, prop, b[prop]);
|
|
968
|
+
if (__getOwnPropSymbols$2)
|
|
969
|
+
for (var prop of __getOwnPropSymbols$2(b)) {
|
|
970
|
+
if (__propIsEnum$2.call(b, prop))
|
|
971
|
+
__defNormalProp$2(a, prop, b[prop]);
|
|
972
|
+
}
|
|
973
|
+
return a;
|
|
974
|
+
};
|
|
975
|
+
var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
|
|
976
|
+
function remove(array, item) {
|
|
977
|
+
for (let i = 0; i < array.length; i++) {
|
|
978
|
+
if (array[i] === item) {
|
|
979
|
+
array.splice(i, 1);
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function isSameNodeOrChildOf(node, parent) {
|
|
985
|
+
if (node === parent) {
|
|
986
|
+
return true;
|
|
987
|
+
}
|
|
988
|
+
if (node._parent) {
|
|
989
|
+
return isSameNodeOrChildOf(node._parent, parent);
|
|
990
|
+
}
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
function deserialize(entry, parentToChildren, doc) {
|
|
994
|
+
switch (entry[1].type) {
|
|
995
|
+
case CrdtType.Object: {
|
|
996
|
+
return LiveObject._deserialize(entry, parentToChildren, doc);
|
|
997
|
+
}
|
|
998
|
+
case CrdtType.List: {
|
|
999
|
+
return LiveList._deserialize(entry, parentToChildren, doc);
|
|
1000
|
+
}
|
|
1001
|
+
case CrdtType.Map: {
|
|
1002
|
+
return LiveMap._deserialize(entry, parentToChildren, doc);
|
|
1003
|
+
}
|
|
1004
|
+
case CrdtType.Register: {
|
|
1005
|
+
return LiveRegister._deserialize(entry, parentToChildren, doc);
|
|
1006
|
+
}
|
|
1007
|
+
default: {
|
|
1008
|
+
throw new Error("Unexpected CRDT type");
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
function isCrdt(obj) {
|
|
1013
|
+
return obj instanceof LiveObject || obj instanceof LiveMap || obj instanceof LiveList || obj instanceof LiveRegister;
|
|
1014
|
+
}
|
|
1015
|
+
function selfOrRegisterValue(obj) {
|
|
1016
|
+
if (obj instanceof LiveRegister) {
|
|
1017
|
+
return obj.data;
|
|
1018
|
+
}
|
|
1019
|
+
return obj;
|
|
1020
|
+
}
|
|
1021
|
+
function selfOrRegister(obj) {
|
|
1022
|
+
if (obj instanceof LiveObject || obj instanceof LiveMap || obj instanceof LiveList) {
|
|
1023
|
+
return obj;
|
|
1024
|
+
} else if (obj instanceof LiveRegister) {
|
|
1025
|
+
throw new Error("Internal error. LiveRegister should not be created from selfOrRegister");
|
|
1026
|
+
} else {
|
|
1027
|
+
return new LiveRegister(obj);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
function getTreesDiffOperations(currentItems, newItems) {
|
|
1031
|
+
const ops = [];
|
|
1032
|
+
currentItems.forEach((_, id) => {
|
|
1033
|
+
if (!newItems.get(id)) {
|
|
1034
|
+
ops.push({
|
|
1035
|
+
type: OpType.DeleteCrdt,
|
|
1036
|
+
id
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
newItems.forEach((crdt, id) => {
|
|
1041
|
+
const currentCrdt = currentItems.get(id);
|
|
1042
|
+
if (currentCrdt) {
|
|
1043
|
+
if (crdt.type === CrdtType.Object) {
|
|
1044
|
+
if (JSON.stringify(crdt.data) !== JSON.stringify(currentCrdt.data)) {
|
|
1045
|
+
ops.push({
|
|
1046
|
+
type: OpType.UpdateObject,
|
|
1047
|
+
id,
|
|
1048
|
+
data: crdt.data
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (crdt.parentKey !== currentCrdt.parentKey) {
|
|
1053
|
+
ops.push({
|
|
1054
|
+
type: OpType.SetParentKey,
|
|
1055
|
+
id,
|
|
1056
|
+
parentKey: crdt.parentKey
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
} else {
|
|
1060
|
+
switch (crdt.type) {
|
|
1061
|
+
case CrdtType.Register:
|
|
1062
|
+
ops.push({
|
|
1063
|
+
type: OpType.CreateRegister,
|
|
1064
|
+
id,
|
|
1065
|
+
parentId: crdt.parentId,
|
|
1066
|
+
parentKey: crdt.parentKey,
|
|
1067
|
+
data: crdt.data
|
|
1068
|
+
});
|
|
1069
|
+
break;
|
|
1070
|
+
case CrdtType.List:
|
|
1071
|
+
ops.push({
|
|
1072
|
+
type: OpType.CreateList,
|
|
1073
|
+
id,
|
|
1074
|
+
parentId: crdt.parentId,
|
|
1075
|
+
parentKey: crdt.parentKey
|
|
1076
|
+
});
|
|
1077
|
+
break;
|
|
1078
|
+
case CrdtType.Object:
|
|
1079
|
+
ops.push({
|
|
1080
|
+
type: OpType.CreateObject,
|
|
1081
|
+
id,
|
|
1082
|
+
parentId: crdt.parentId,
|
|
1083
|
+
parentKey: crdt.parentKey,
|
|
1084
|
+
data: crdt.data
|
|
1085
|
+
});
|
|
1086
|
+
break;
|
|
1087
|
+
case CrdtType.Map:
|
|
1088
|
+
ops.push({
|
|
1089
|
+
type: OpType.CreateMap,
|
|
1090
|
+
id,
|
|
1091
|
+
parentId: crdt.parentId,
|
|
1092
|
+
parentKey: crdt.parentKey
|
|
1093
|
+
});
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
return ops;
|
|
1099
|
+
}
|
|
1100
|
+
function mergeStorageUpdates(first, second) {
|
|
1101
|
+
if (!first) {
|
|
1102
|
+
return second;
|
|
1103
|
+
}
|
|
1104
|
+
if (second.type === "LiveObject") {
|
|
1105
|
+
const updates = first.updates;
|
|
1106
|
+
for (const [key, value] of Object.entries(second.updates)) {
|
|
1107
|
+
updates[key] = value;
|
|
1108
|
+
}
|
|
1109
|
+
return __spreadProps$2(__spreadValues$2({}, second), {
|
|
1110
|
+
updates
|
|
1111
|
+
});
|
|
1112
|
+
} else if (second.type === "LiveMap") {
|
|
1113
|
+
const updates = first.updates;
|
|
1114
|
+
for (const [key, value] of Object.entries(second.updates)) {
|
|
1115
|
+
updates[key] = value;
|
|
1116
|
+
}
|
|
1117
|
+
return __spreadProps$2(__spreadValues$2({}, second), {
|
|
1118
|
+
updates
|
|
1119
|
+
});
|
|
1120
|
+
} else if (second.type === "LiveList") {
|
|
1121
|
+
const updates = first.updates;
|
|
1122
|
+
return __spreadProps$2(__spreadValues$2({}, second), {
|
|
1123
|
+
updates: updates.concat(second.updates)
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
return second;
|
|
1127
|
+
}
|
|
1128
|
+
function isPlain(value) {
|
|
1129
|
+
const type = typeof value;
|
|
1130
|
+
return type === "undefined" || value === null || type === "string" || type === "boolean" || type === "number" || Array.isArray(value) || isPlainObject$1(value);
|
|
1131
|
+
}
|
|
1132
|
+
function isPlainObject$1(value) {
|
|
1133
|
+
if (typeof value !== "object" || value === null)
|
|
1134
|
+
return false;
|
|
1135
|
+
let proto = Object.getPrototypeOf(value);
|
|
1136
|
+
if (proto === null)
|
|
1137
|
+
return true;
|
|
1138
|
+
let baseProto = proto;
|
|
1139
|
+
while (Object.getPrototypeOf(baseProto) !== null) {
|
|
1140
|
+
baseProto = Object.getPrototypeOf(baseProto);
|
|
1141
|
+
}
|
|
1142
|
+
return proto === baseProto;
|
|
1143
|
+
}
|
|
1144
|
+
function findNonSerializableValue(value, path = "") {
|
|
1145
|
+
if (!isPlain) {
|
|
1146
|
+
return {
|
|
1147
|
+
path: path || "root",
|
|
1148
|
+
value
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
if (typeof value !== "object" || value === null) {
|
|
1152
|
+
return false;
|
|
1153
|
+
}
|
|
1154
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
1155
|
+
const nestedPath = path ? path + "." + key : key;
|
|
1156
|
+
if (!isPlain(nestedValue)) {
|
|
1157
|
+
return {
|
|
1158
|
+
path: nestedPath,
|
|
1159
|
+
value: nestedValue
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
if (typeof nestedValue === "object") {
|
|
1163
|
+
const nonSerializableNestedValue = findNonSerializableValue(nestedValue, nestedPath);
|
|
1164
|
+
if (nonSerializableNestedValue) {
|
|
1165
|
+
return nonSerializableNestedValue;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return false;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
var __accessCheck = (obj, member, msg) => {
|
|
1173
|
+
if (!member.has(obj))
|
|
1174
|
+
throw TypeError("Cannot " + msg);
|
|
1175
|
+
};
|
|
1176
|
+
var __privateGet = (obj, member, getter) => {
|
|
1177
|
+
__accessCheck(obj, member, "read from private field");
|
|
1178
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
1179
|
+
};
|
|
1180
|
+
var __privateAdd = (obj, member, value) => {
|
|
1181
|
+
if (member.has(obj))
|
|
1182
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
1183
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
1184
|
+
};
|
|
1185
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
1186
|
+
__accessCheck(obj, member, "write to private field");
|
|
1187
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
1188
|
+
return value;
|
|
1189
|
+
};
|
|
1190
|
+
var __privateMethod = (obj, member, method) => {
|
|
1191
|
+
__accessCheck(obj, member, "access private method");
|
|
1192
|
+
return method;
|
|
1193
|
+
};
|
|
1194
|
+
var _map, _propToLastUpdate, _applyUpdate, applyUpdate_fn, _applyDeleteObjectKey, applyDeleteObjectKey_fn;
|
|
1195
|
+
const _LiveObject = class extends AbstractCrdt {
|
|
1196
|
+
constructor(object = {}) {
|
|
1197
|
+
super();
|
|
1198
|
+
__privateAdd(this, _applyUpdate);
|
|
1199
|
+
__privateAdd(this, _applyDeleteObjectKey);
|
|
1200
|
+
__privateAdd(this, _map, void 0);
|
|
1201
|
+
__privateAdd(this, _propToLastUpdate, /* @__PURE__ */ new Map());
|
|
1202
|
+
for (const key in object) {
|
|
1203
|
+
const value = object[key];
|
|
1204
|
+
if (value instanceof AbstractCrdt) {
|
|
1205
|
+
value._setParentLink(this, key);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
__privateSet(this, _map, new Map(Object.entries(object)));
|
|
1209
|
+
}
|
|
1210
|
+
_serialize(parentId, parentKey, doc) {
|
|
1211
|
+
if (this._id == null) {
|
|
1212
|
+
throw new Error("Cannot serialize item is not attached");
|
|
1213
|
+
}
|
|
1214
|
+
const ops = [];
|
|
1215
|
+
const op = {
|
|
1216
|
+
id: this._id,
|
|
1217
|
+
opId: doc == null ? void 0 : doc.generateOpId(),
|
|
1218
|
+
type: OpType.CreateObject,
|
|
1219
|
+
parentId,
|
|
1220
|
+
parentKey,
|
|
1221
|
+
data: {}
|
|
1222
|
+
};
|
|
1223
|
+
ops.push(op);
|
|
1224
|
+
for (const [key, value] of __privateGet(this, _map)) {
|
|
1225
|
+
if (value instanceof AbstractCrdt) {
|
|
1226
|
+
ops.push(...value._serialize(this._id, key, doc));
|
|
1227
|
+
} else {
|
|
1228
|
+
op.data[key] = value;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return ops;
|
|
1232
|
+
}
|
|
1233
|
+
static _deserialize([id, item], parentToChildren, doc) {
|
|
1234
|
+
if (item.type !== CrdtType.Object) {
|
|
1235
|
+
throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
|
|
1236
|
+
}
|
|
1237
|
+
const object = new _LiveObject(item.data);
|
|
1238
|
+
object._attach(id, doc);
|
|
1239
|
+
return this._deserializeChildren(object, parentToChildren, doc);
|
|
1240
|
+
}
|
|
1241
|
+
static _deserializeChildren(object, parentToChildren, doc) {
|
|
1242
|
+
const children = parentToChildren.get(object._id);
|
|
1243
|
+
if (children == null) {
|
|
1244
|
+
return object;
|
|
1245
|
+
}
|
|
1246
|
+
for (const entry of children) {
|
|
1247
|
+
const crdt = entry[1];
|
|
1248
|
+
if (crdt.parentKey == null) {
|
|
1249
|
+
throw new Error("Tried to deserialize a crdt but it does not have a parentKey and is not the root");
|
|
1250
|
+
}
|
|
1251
|
+
const child = deserialize(entry, parentToChildren, doc);
|
|
1252
|
+
child._setParentLink(object, crdt.parentKey);
|
|
1253
|
+
__privateGet(object, _map).set(crdt.parentKey, child);
|
|
1254
|
+
}
|
|
1255
|
+
return object;
|
|
1256
|
+
}
|
|
1257
|
+
_attach(id, doc) {
|
|
1258
|
+
super._attach(id, doc);
|
|
1259
|
+
for (const [key, value] of __privateGet(this, _map)) {
|
|
1260
|
+
if (value instanceof AbstractCrdt) {
|
|
1261
|
+
value._attach(doc.generateId(), doc);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
_attachChild(id, key, child, opId, isLocal) {
|
|
1266
|
+
if (this._doc == null) {
|
|
1267
|
+
throw new Error("Can't attach child if doc is not present");
|
|
1268
|
+
}
|
|
1269
|
+
if (this._doc.getItem(id) !== void 0) {
|
|
1270
|
+
if (__privateGet(this, _propToLastUpdate).get(key) === opId) {
|
|
1271
|
+
__privateGet(this, _propToLastUpdate).delete(key);
|
|
1272
|
+
}
|
|
1273
|
+
return { modified: false };
|
|
1274
|
+
}
|
|
1275
|
+
if (isLocal) {
|
|
1276
|
+
__privateGet(this, _propToLastUpdate).set(key, opId);
|
|
1277
|
+
} else if (__privateGet(this, _propToLastUpdate).get(key) === void 0) ; else if (__privateGet(this, _propToLastUpdate).get(key) === opId) {
|
|
1278
|
+
__privateGet(this, _propToLastUpdate).delete(key);
|
|
1279
|
+
return { modified: false };
|
|
1280
|
+
} else {
|
|
1281
|
+
return { modified: false };
|
|
1282
|
+
}
|
|
1283
|
+
const previousValue = __privateGet(this, _map).get(key);
|
|
1284
|
+
let reverse;
|
|
1285
|
+
if (isCrdt(previousValue)) {
|
|
1286
|
+
reverse = previousValue._serialize(this._id, key);
|
|
1287
|
+
previousValue._detach();
|
|
1288
|
+
} else if (previousValue === void 0) {
|
|
1289
|
+
reverse = [
|
|
1290
|
+
{ type: OpType.DeleteObjectKey, id: this._id, key }
|
|
1291
|
+
];
|
|
1292
|
+
} else {
|
|
1293
|
+
reverse = [
|
|
1294
|
+
{
|
|
1295
|
+
type: OpType.UpdateObject,
|
|
1296
|
+
id: this._id,
|
|
1297
|
+
data: { [key]: previousValue }
|
|
1298
|
+
}
|
|
1299
|
+
];
|
|
1300
|
+
}
|
|
1301
|
+
__privateGet(this, _map).set(key, child);
|
|
1302
|
+
child._setParentLink(this, key);
|
|
1303
|
+
child._attach(id, this._doc);
|
|
1304
|
+
return {
|
|
1305
|
+
reverse,
|
|
1306
|
+
modified: {
|
|
1307
|
+
node: this,
|
|
1308
|
+
type: "LiveObject",
|
|
1309
|
+
updates: { [key]: { type: "update" } }
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
_detachChild(child) {
|
|
1314
|
+
if (child) {
|
|
1315
|
+
const reverse = child._serialize(this._id, child._parentKey, this._doc);
|
|
1316
|
+
for (const [key, value] of __privateGet(this, _map)) {
|
|
1317
|
+
if (value === child) {
|
|
1318
|
+
__privateGet(this, _map).delete(key);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
child._detach();
|
|
1322
|
+
const storageUpdate = {
|
|
1323
|
+
node: this,
|
|
1324
|
+
type: "LiveObject",
|
|
1325
|
+
updates: {
|
|
1326
|
+
[child._parentKey]: { type: "delete" }
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
return { modified: storageUpdate, reverse };
|
|
1330
|
+
}
|
|
1331
|
+
return { modified: false };
|
|
1332
|
+
}
|
|
1333
|
+
_detachChildren() {
|
|
1334
|
+
for (const [key, value] of __privateGet(this, _map)) {
|
|
1335
|
+
__privateGet(this, _map).delete(key);
|
|
1336
|
+
value._detach();
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
_detach() {
|
|
1340
|
+
super._detach();
|
|
1341
|
+
for (const value of __privateGet(this, _map).values()) {
|
|
1342
|
+
if (isCrdt(value)) {
|
|
1343
|
+
value._detach();
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
_apply(op, isLocal) {
|
|
1348
|
+
if (op.type === OpType.UpdateObject) {
|
|
1349
|
+
return __privateMethod(this, _applyUpdate, applyUpdate_fn).call(this, op, isLocal);
|
|
1350
|
+
} else if (op.type === OpType.DeleteObjectKey) {
|
|
1351
|
+
return __privateMethod(this, _applyDeleteObjectKey, applyDeleteObjectKey_fn).call(this, op);
|
|
1352
|
+
}
|
|
1353
|
+
return super._apply(op, isLocal);
|
|
1354
|
+
}
|
|
1355
|
+
_toSerializedCrdt() {
|
|
1356
|
+
var _a;
|
|
1357
|
+
return {
|
|
1358
|
+
type: CrdtType.Object,
|
|
1359
|
+
parentId: (_a = this._parent) == null ? void 0 : _a._id,
|
|
1360
|
+
parentKey: this._parentKey,
|
|
1361
|
+
data: this.toObject()
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
_getType() {
|
|
1365
|
+
return "LiveObject";
|
|
1366
|
+
}
|
|
1367
|
+
toObject() {
|
|
1368
|
+
return Object.fromEntries(__privateGet(this, _map));
|
|
1369
|
+
}
|
|
1370
|
+
set(key, value) {
|
|
1371
|
+
this.update({ [key]: value });
|
|
1372
|
+
}
|
|
1373
|
+
get(key) {
|
|
1374
|
+
return __privateGet(this, _map).get(key);
|
|
1375
|
+
}
|
|
1376
|
+
delete(key) {
|
|
1377
|
+
const keyAsString = key;
|
|
1378
|
+
const oldValue = __privateGet(this, _map).get(keyAsString);
|
|
1379
|
+
if (oldValue === void 0) {
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
if (this._doc == null || this._id == null) {
|
|
1383
|
+
if (oldValue instanceof AbstractCrdt) {
|
|
1384
|
+
oldValue._detach();
|
|
1385
|
+
}
|
|
1386
|
+
__privateGet(this, _map).delete(keyAsString);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
let reverse;
|
|
1390
|
+
if (oldValue instanceof AbstractCrdt) {
|
|
1391
|
+
oldValue._detach();
|
|
1392
|
+
reverse = oldValue._serialize(this._id, keyAsString);
|
|
1393
|
+
} else {
|
|
1394
|
+
reverse = [
|
|
1395
|
+
{
|
|
1396
|
+
type: OpType.UpdateObject,
|
|
1397
|
+
data: { [keyAsString]: oldValue },
|
|
1398
|
+
id: this._id
|
|
1399
|
+
}
|
|
1400
|
+
];
|
|
1401
|
+
}
|
|
1402
|
+
__privateGet(this, _map).delete(keyAsString);
|
|
1403
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
1404
|
+
storageUpdates.set(this._id, {
|
|
1405
|
+
node: this,
|
|
1406
|
+
type: "LiveObject",
|
|
1407
|
+
updates: { [key]: { type: "delete" } }
|
|
1408
|
+
});
|
|
1409
|
+
this._doc.dispatch([
|
|
1410
|
+
{
|
|
1411
|
+
type: OpType.DeleteObjectKey,
|
|
1412
|
+
key: keyAsString,
|
|
1413
|
+
id: this._id,
|
|
1414
|
+
opId: this._doc.generateOpId()
|
|
1415
|
+
}
|
|
1416
|
+
], reverse, storageUpdates);
|
|
1417
|
+
}
|
|
1418
|
+
update(overrides) {
|
|
1419
|
+
if (this._doc == null || this._id == null) {
|
|
1420
|
+
for (const key in overrides) {
|
|
1421
|
+
const oldValue = __privateGet(this, _map).get(key);
|
|
1422
|
+
if (oldValue instanceof AbstractCrdt) {
|
|
1423
|
+
oldValue._detach();
|
|
1424
|
+
}
|
|
1425
|
+
const newValue = overrides[key];
|
|
1426
|
+
if (newValue instanceof AbstractCrdt) {
|
|
1427
|
+
newValue._setParentLink(this, key);
|
|
1428
|
+
}
|
|
1429
|
+
__privateGet(this, _map).set(key, newValue);
|
|
1430
|
+
}
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
const ops = [];
|
|
1434
|
+
const reverseOps = [];
|
|
1435
|
+
const opId = this._doc.generateOpId();
|
|
1436
|
+
const updatedProps = {};
|
|
1437
|
+
const reverseUpdateOp = {
|
|
1438
|
+
id: this._id,
|
|
1439
|
+
type: OpType.UpdateObject,
|
|
1440
|
+
data: {}
|
|
1441
|
+
};
|
|
1442
|
+
const updateDelta = {};
|
|
1443
|
+
for (const key in overrides) {
|
|
1444
|
+
const oldValue = __privateGet(this, _map).get(key);
|
|
1445
|
+
if (oldValue instanceof AbstractCrdt) {
|
|
1446
|
+
reverseOps.push(...oldValue._serialize(this._id, key));
|
|
1447
|
+
oldValue._detach();
|
|
1448
|
+
} else if (oldValue === void 0) {
|
|
1449
|
+
reverseOps.push({ type: OpType.DeleteObjectKey, id: this._id, key });
|
|
1450
|
+
} else {
|
|
1451
|
+
reverseUpdateOp.data[key] = oldValue;
|
|
1452
|
+
}
|
|
1453
|
+
const newValue = overrides[key];
|
|
1454
|
+
if (newValue instanceof AbstractCrdt) {
|
|
1455
|
+
newValue._setParentLink(this, key);
|
|
1456
|
+
newValue._attach(this._doc.generateId(), this._doc);
|
|
1457
|
+
const newAttachChildOps = newValue._serialize(this._id, key, this._doc);
|
|
1458
|
+
const createCrdtOp = newAttachChildOps.find((op) => op.parentId === this._id);
|
|
1459
|
+
if (createCrdtOp) {
|
|
1460
|
+
__privateGet(this, _propToLastUpdate).set(key, createCrdtOp.opId);
|
|
1461
|
+
}
|
|
1462
|
+
ops.push(...newAttachChildOps);
|
|
1463
|
+
} else {
|
|
1464
|
+
updatedProps[key] = newValue;
|
|
1465
|
+
__privateGet(this, _propToLastUpdate).set(key, opId);
|
|
1466
|
+
}
|
|
1467
|
+
__privateGet(this, _map).set(key, newValue);
|
|
1468
|
+
updateDelta[key] = { type: "update" };
|
|
1469
|
+
}
|
|
1470
|
+
if (Object.keys(reverseUpdateOp.data).length !== 0) {
|
|
1471
|
+
reverseOps.unshift(reverseUpdateOp);
|
|
1472
|
+
}
|
|
1473
|
+
if (Object.keys(updatedProps).length !== 0) {
|
|
1474
|
+
ops.unshift({
|
|
1475
|
+
opId,
|
|
1476
|
+
id: this._id,
|
|
1477
|
+
type: OpType.UpdateObject,
|
|
1478
|
+
data: updatedProps
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
1482
|
+
storageUpdates.set(this._id, {
|
|
1483
|
+
node: this,
|
|
1484
|
+
type: "LiveObject",
|
|
1485
|
+
updates: updateDelta
|
|
1486
|
+
});
|
|
1487
|
+
this._doc.dispatch(ops, reverseOps, storageUpdates);
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
let LiveObject = _LiveObject;
|
|
1491
|
+
_map = new WeakMap();
|
|
1492
|
+
_propToLastUpdate = new WeakMap();
|
|
1493
|
+
_applyUpdate = new WeakSet();
|
|
1494
|
+
applyUpdate_fn = function(op, isLocal) {
|
|
1495
|
+
let isModified = false;
|
|
1496
|
+
const reverse = [];
|
|
1497
|
+
const reverseUpdate = {
|
|
1498
|
+
type: OpType.UpdateObject,
|
|
1499
|
+
id: this._id,
|
|
1500
|
+
data: {}
|
|
1501
|
+
};
|
|
1502
|
+
reverse.push(reverseUpdate);
|
|
1503
|
+
for (const key in op.data) {
|
|
1504
|
+
const oldValue = __privateGet(this, _map).get(key);
|
|
1505
|
+
if (oldValue instanceof AbstractCrdt) {
|
|
1506
|
+
reverse.push(...oldValue._serialize(this._id, key));
|
|
1507
|
+
oldValue._detach();
|
|
1508
|
+
} else if (oldValue !== void 0) {
|
|
1509
|
+
reverseUpdate.data[key] = oldValue;
|
|
1510
|
+
} else if (oldValue === void 0) {
|
|
1511
|
+
reverse.push({ type: OpType.DeleteObjectKey, id: this._id, key });
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
let updateDelta = {};
|
|
1515
|
+
for (const key in op.data) {
|
|
1516
|
+
if (isLocal) {
|
|
1517
|
+
__privateGet(this, _propToLastUpdate).set(key, op.opId);
|
|
1518
|
+
} else if (__privateGet(this, _propToLastUpdate).get(key) == null) {
|
|
1519
|
+
isModified = true;
|
|
1520
|
+
} else if (__privateGet(this, _propToLastUpdate).get(key) === op.opId) {
|
|
1521
|
+
__privateGet(this, _propToLastUpdate).delete(key);
|
|
1522
|
+
continue;
|
|
1523
|
+
} else {
|
|
1524
|
+
continue;
|
|
1525
|
+
}
|
|
1526
|
+
const oldValue = __privateGet(this, _map).get(key);
|
|
1527
|
+
if (isCrdt(oldValue)) {
|
|
1528
|
+
oldValue._detach();
|
|
1529
|
+
}
|
|
1530
|
+
isModified = true;
|
|
1531
|
+
updateDelta[key] = { type: "update" };
|
|
1532
|
+
__privateGet(this, _map).set(key, op.data[key]);
|
|
1533
|
+
}
|
|
1534
|
+
if (Object.keys(reverseUpdate.data).length !== 0) {
|
|
1535
|
+
reverse.unshift(reverseUpdate);
|
|
1536
|
+
}
|
|
1537
|
+
return isModified ? {
|
|
1538
|
+
modified: {
|
|
1539
|
+
node: this,
|
|
1540
|
+
type: "LiveObject",
|
|
1541
|
+
updates: updateDelta
|
|
1542
|
+
},
|
|
1543
|
+
reverse
|
|
1544
|
+
} : { modified: false };
|
|
1545
|
+
};
|
|
1546
|
+
_applyDeleteObjectKey = new WeakSet();
|
|
1547
|
+
applyDeleteObjectKey_fn = function(op) {
|
|
1548
|
+
const key = op.key;
|
|
1549
|
+
if (__privateGet(this, _map).has(key) === false) {
|
|
1550
|
+
return { modified: false };
|
|
1551
|
+
}
|
|
1552
|
+
if (__privateGet(this, _propToLastUpdate).get(key) !== void 0) {
|
|
1553
|
+
return { modified: false };
|
|
1554
|
+
}
|
|
1555
|
+
const oldValue = __privateGet(this, _map).get(key);
|
|
1556
|
+
let reverse = [];
|
|
1557
|
+
if (isCrdt(oldValue)) {
|
|
1558
|
+
reverse = oldValue._serialize(this._id, op.key);
|
|
1559
|
+
oldValue._detach();
|
|
1560
|
+
} else if (oldValue !== void 0) {
|
|
1561
|
+
reverse = [
|
|
1562
|
+
{
|
|
1563
|
+
type: OpType.UpdateObject,
|
|
1564
|
+
id: this._id,
|
|
1565
|
+
data: { [key]: oldValue }
|
|
1566
|
+
}
|
|
1567
|
+
];
|
|
1568
|
+
}
|
|
1569
|
+
__privateGet(this, _map).delete(key);
|
|
1570
|
+
return {
|
|
1571
|
+
modified: {
|
|
1572
|
+
node: this,
|
|
1573
|
+
type: "LiveObject",
|
|
1574
|
+
updates: { [op.key]: { type: "delete" } }
|
|
1575
|
+
},
|
|
1576
|
+
reverse
|
|
1577
|
+
};
|
|
1578
|
+
};
|
|
1579
|
+
|
|
1580
|
+
var __defProp$1 = Object.defineProperty;
|
|
1581
|
+
var __defProps$1 = Object.defineProperties;
|
|
1582
|
+
var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
|
|
1583
|
+
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
|
|
1584
|
+
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
1585
|
+
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
|
|
1586
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1587
|
+
var __spreadValues$1 = (a, b) => {
|
|
1588
|
+
for (var prop in b || (b = {}))
|
|
1589
|
+
if (__hasOwnProp$1.call(b, prop))
|
|
1590
|
+
__defNormalProp$1(a, prop, b[prop]);
|
|
1591
|
+
if (__getOwnPropSymbols$1)
|
|
1592
|
+
for (var prop of __getOwnPropSymbols$1(b)) {
|
|
1593
|
+
if (__propIsEnum$1.call(b, prop))
|
|
1594
|
+
__defNormalProp$1(a, prop, b[prop]);
|
|
1595
|
+
}
|
|
1596
|
+
return a;
|
|
1597
|
+
};
|
|
1598
|
+
var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
|
|
1599
|
+
const BACKOFF_RETRY_DELAYS = [250, 500, 1e3, 2e3, 4e3, 8e3, 1e4];
|
|
1600
|
+
const HEARTBEAT_INTERVAL = 3e4;
|
|
1601
|
+
const PONG_TIMEOUT = 2e3;
|
|
1602
|
+
function isValidRoomEventType(value) {
|
|
1603
|
+
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "connection";
|
|
1604
|
+
}
|
|
1605
|
+
function makeIdFactory(connectionId) {
|
|
1606
|
+
let count = 0;
|
|
1607
|
+
return () => `${connectionId}:${count++}`;
|
|
1608
|
+
}
|
|
1609
|
+
function makeOthers(presenceMap) {
|
|
1610
|
+
const array = Object.values(presenceMap);
|
|
1611
|
+
return {
|
|
1612
|
+
get count() {
|
|
1613
|
+
return array.length;
|
|
1614
|
+
},
|
|
1615
|
+
[Symbol.iterator]() {
|
|
1616
|
+
return array[Symbol.iterator]();
|
|
1617
|
+
},
|
|
1618
|
+
map(callback) {
|
|
1619
|
+
return array.map(callback);
|
|
1620
|
+
},
|
|
1621
|
+
toArray() {
|
|
1622
|
+
return array;
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
function makeStateMachine(state, context, mockedEffects) {
|
|
1627
|
+
const effects = mockedEffects || {
|
|
1628
|
+
async authenticate(auth, createWebSocket) {
|
|
1629
|
+
try {
|
|
1630
|
+
const { token } = await auth(context.room);
|
|
1631
|
+
const parsedToken = parseToken(token);
|
|
1632
|
+
const socket = createWebSocket(token);
|
|
1633
|
+
authenticationSuccess(parsedToken, socket);
|
|
1634
|
+
} catch (er) {
|
|
1635
|
+
authenticationFailure(er);
|
|
1636
|
+
}
|
|
1637
|
+
},
|
|
1638
|
+
send(messageOrMessages) {
|
|
1639
|
+
if (state.socket == null) {
|
|
1640
|
+
throw new Error("Can't send message if socket is null");
|
|
1641
|
+
}
|
|
1642
|
+
state.socket.send(JSON.stringify(messageOrMessages));
|
|
1643
|
+
},
|
|
1644
|
+
delayFlush(delay) {
|
|
1645
|
+
return setTimeout(tryFlushing, delay);
|
|
1646
|
+
},
|
|
1647
|
+
startHeartbeatInterval() {
|
|
1648
|
+
return setInterval(heartbeat, HEARTBEAT_INTERVAL);
|
|
1649
|
+
},
|
|
1650
|
+
schedulePongTimeout() {
|
|
1651
|
+
return setTimeout(pongTimeout, PONG_TIMEOUT);
|
|
1652
|
+
},
|
|
1653
|
+
scheduleReconnect(delay) {
|
|
1654
|
+
return setTimeout(connect, delay);
|
|
1655
|
+
}
|
|
1656
|
+
};
|
|
1657
|
+
function genericSubscribe(callback) {
|
|
1658
|
+
state.listeners.storage.push(callback);
|
|
1659
|
+
return () => remove(state.listeners.storage, callback);
|
|
1660
|
+
}
|
|
1661
|
+
function crdtSubscribe(crdt, innerCallback, options) {
|
|
1662
|
+
const cb = (updates) => {
|
|
1663
|
+
const relatedUpdates = [];
|
|
1664
|
+
for (const update of updates) {
|
|
1665
|
+
if ((options == null ? void 0 : options.isDeep) && isSameNodeOrChildOf(update.node, crdt)) {
|
|
1666
|
+
relatedUpdates.push(update);
|
|
1667
|
+
} else if (update.node._id === crdt._id) {
|
|
1668
|
+
innerCallback(update.node);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
if ((options == null ? void 0 : options.isDeep) && relatedUpdates.length > 0) {
|
|
1672
|
+
innerCallback(relatedUpdates);
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
return genericSubscribe(cb);
|
|
1676
|
+
}
|
|
1677
|
+
function createOrUpdateRootFromMessage(message) {
|
|
1678
|
+
if (message.items.length === 0) {
|
|
1679
|
+
throw new Error("Internal error: cannot load storage without items");
|
|
1680
|
+
}
|
|
1681
|
+
if (state.root) {
|
|
1682
|
+
updateRoot(message.items);
|
|
1683
|
+
} else {
|
|
1684
|
+
state.root = load(message.items);
|
|
1685
|
+
}
|
|
1686
|
+
for (const key in state.defaultStorageRoot) {
|
|
1687
|
+
if (state.root.get(key) == null) {
|
|
1688
|
+
state.root.set(key, state.defaultStorageRoot[key]);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
function buildRootAndParentToChildren(items) {
|
|
1693
|
+
const parentToChildren = /* @__PURE__ */ new Map();
|
|
1694
|
+
let root = null;
|
|
1695
|
+
for (const tuple of items) {
|
|
1696
|
+
const parentId = tuple[1].parentId;
|
|
1697
|
+
if (parentId == null) {
|
|
1698
|
+
root = tuple;
|
|
1699
|
+
} else {
|
|
1700
|
+
const children = parentToChildren.get(parentId);
|
|
1701
|
+
if (children != null) {
|
|
1702
|
+
children.push(tuple);
|
|
1703
|
+
} else {
|
|
1704
|
+
parentToChildren.set(parentId, [tuple]);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
if (root == null) {
|
|
1709
|
+
throw new Error("Root can't be null");
|
|
1710
|
+
}
|
|
1711
|
+
return [root, parentToChildren];
|
|
1712
|
+
}
|
|
1713
|
+
function updateRoot(items) {
|
|
1714
|
+
if (!state.root) {
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
const currentItems = /* @__PURE__ */ new Map();
|
|
1718
|
+
state.items.forEach((liveCrdt, id) => {
|
|
1719
|
+
currentItems.set(id, liveCrdt._toSerializedCrdt());
|
|
1720
|
+
});
|
|
1721
|
+
const ops = getTreesDiffOperations(currentItems, new Map(items));
|
|
1722
|
+
const result = apply(ops, false);
|
|
1723
|
+
notify(result.updates);
|
|
1724
|
+
}
|
|
1725
|
+
function load(items) {
|
|
1726
|
+
const [root, parentToChildren] = buildRootAndParentToChildren(items);
|
|
1727
|
+
return LiveObject._deserialize(root, parentToChildren, {
|
|
1728
|
+
getItem,
|
|
1729
|
+
addItem,
|
|
1730
|
+
deleteItem,
|
|
1731
|
+
generateId,
|
|
1732
|
+
generateOpId,
|
|
1733
|
+
dispatch: storageDispatch,
|
|
1734
|
+
roomId: context.room
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
function addItem(id, item) {
|
|
1738
|
+
state.items.set(id, item);
|
|
1739
|
+
}
|
|
1740
|
+
function deleteItem(id) {
|
|
1741
|
+
state.items.delete(id);
|
|
1742
|
+
}
|
|
1743
|
+
function getItem(id) {
|
|
1744
|
+
return state.items.get(id);
|
|
1745
|
+
}
|
|
1746
|
+
function addToUndoStack(historyItem) {
|
|
1747
|
+
if (state.undoStack.length >= 50) {
|
|
1748
|
+
state.undoStack.shift();
|
|
1749
|
+
}
|
|
1750
|
+
if (state.isHistoryPaused) {
|
|
1751
|
+
state.pausedHistory.unshift(...historyItem);
|
|
1752
|
+
} else {
|
|
1753
|
+
state.undoStack.push(historyItem);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
function storageDispatch(ops, reverse, storageUpdates) {
|
|
1757
|
+
if (state.isBatching) {
|
|
1758
|
+
state.batch.ops.push(...ops);
|
|
1759
|
+
storageUpdates.forEach((value, key) => {
|
|
1760
|
+
state.batch.updates.storageUpdates.set(key, mergeStorageUpdates(state.batch.updates.storageUpdates.get(key), value));
|
|
1761
|
+
});
|
|
1762
|
+
state.batch.reverseOps.push(...reverse);
|
|
1763
|
+
} else {
|
|
1764
|
+
addToUndoStack(reverse);
|
|
1765
|
+
state.redoStack = [];
|
|
1766
|
+
dispatch(ops);
|
|
1767
|
+
notify({ storageUpdates });
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
function notify({
|
|
1771
|
+
storageUpdates = /* @__PURE__ */ new Map(),
|
|
1772
|
+
presence = false,
|
|
1773
|
+
others = []
|
|
1774
|
+
}) {
|
|
1775
|
+
if (others.length > 0) {
|
|
1776
|
+
state.others = makeOthers(state.users);
|
|
1777
|
+
for (const event of others) {
|
|
1778
|
+
for (const listener of state.listeners["others"]) {
|
|
1779
|
+
listener(state.others, event);
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
if (presence) {
|
|
1784
|
+
for (const listener of state.listeners["my-presence"]) {
|
|
1785
|
+
listener(state.me);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
if (storageUpdates.size > 0) {
|
|
1789
|
+
for (const subscriber of state.listeners.storage) {
|
|
1790
|
+
subscriber(Array.from(storageUpdates.values()));
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
function getConnectionId() {
|
|
1795
|
+
if (state.connection.state === "open" || state.connection.state === "connecting") {
|
|
1796
|
+
return state.connection.id;
|
|
1797
|
+
} else if (state.lastConnectionId !== null) {
|
|
1798
|
+
return state.lastConnectionId;
|
|
1799
|
+
}
|
|
1800
|
+
throw new Error("Internal. Tried to get connection id but connection was never open");
|
|
1801
|
+
}
|
|
1802
|
+
function generateId() {
|
|
1803
|
+
return `${getConnectionId()}:${state.clock++}`;
|
|
1804
|
+
}
|
|
1805
|
+
function generateOpId() {
|
|
1806
|
+
return `${getConnectionId()}:${state.opClock++}`;
|
|
1807
|
+
}
|
|
1808
|
+
function apply(item, isLocal) {
|
|
1809
|
+
const result = {
|
|
1810
|
+
reverse: [],
|
|
1811
|
+
updates: {
|
|
1812
|
+
storageUpdates: /* @__PURE__ */ new Map(),
|
|
1813
|
+
presence: false
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
for (const op of item) {
|
|
1817
|
+
if (op.type === "presence") {
|
|
1818
|
+
const reverse = {
|
|
1819
|
+
type: "presence",
|
|
1820
|
+
data: {}
|
|
1821
|
+
};
|
|
1822
|
+
for (const key in op.data) {
|
|
1823
|
+
reverse.data[key] = state.me[key];
|
|
1824
|
+
}
|
|
1825
|
+
state.me = __spreadValues$1(__spreadValues$1({}, state.me), op.data);
|
|
1826
|
+
if (state.buffer.presence == null) {
|
|
1827
|
+
state.buffer.presence = op.data;
|
|
1828
|
+
} else {
|
|
1829
|
+
for (const key in op.data) {
|
|
1830
|
+
state.buffer.presence[key] = op.data;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
result.reverse.unshift(reverse);
|
|
1834
|
+
result.updates.presence = true;
|
|
1835
|
+
} else {
|
|
1836
|
+
if (isLocal && !op.opId) {
|
|
1837
|
+
op.opId = generateOpId();
|
|
1838
|
+
}
|
|
1839
|
+
const applyOpResult = applyOp(op, isLocal);
|
|
1840
|
+
if (applyOpResult.modified) {
|
|
1841
|
+
result.updates.storageUpdates.set(applyOpResult.modified.node._id, mergeStorageUpdates(result.updates.storageUpdates.get(applyOpResult.modified.node._id), applyOpResult.modified));
|
|
1842
|
+
result.reverse.unshift(...applyOpResult.reverse);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
return result;
|
|
1847
|
+
}
|
|
1848
|
+
function applyOp(op, isLocal) {
|
|
1849
|
+
if (op.opId) {
|
|
1850
|
+
state.offlineOperations.delete(op.opId);
|
|
1851
|
+
}
|
|
1852
|
+
switch (op.type) {
|
|
1853
|
+
case OpType.DeleteObjectKey:
|
|
1854
|
+
case OpType.UpdateObject:
|
|
1855
|
+
case OpType.DeleteCrdt: {
|
|
1856
|
+
const item = state.items.get(op.id);
|
|
1857
|
+
if (item == null) {
|
|
1858
|
+
return { modified: false };
|
|
1859
|
+
}
|
|
1860
|
+
return item._apply(op, isLocal);
|
|
1861
|
+
}
|
|
1862
|
+
case OpType.SetParentKey: {
|
|
1863
|
+
const item = state.items.get(op.id);
|
|
1864
|
+
if (item == null) {
|
|
1865
|
+
return { modified: false };
|
|
1866
|
+
}
|
|
1867
|
+
if (item._parent instanceof LiveList) {
|
|
1868
|
+
const previousKey = item._parentKey;
|
|
1869
|
+
if (previousKey === op.parentKey) {
|
|
1870
|
+
return { modified: false };
|
|
1871
|
+
} else {
|
|
1872
|
+
return item._parent._setChildKey(op.parentKey, item, previousKey);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return { modified: false };
|
|
1876
|
+
}
|
|
1877
|
+
case OpType.CreateObject: {
|
|
1878
|
+
const parent = state.items.get(op.parentId);
|
|
1879
|
+
if (parent == null) {
|
|
1880
|
+
return { modified: false };
|
|
1881
|
+
}
|
|
1882
|
+
return parent._attachChild(op.id, op.parentKey, new LiveObject(op.data), op.opId, isLocal);
|
|
1883
|
+
}
|
|
1884
|
+
case OpType.CreateList: {
|
|
1885
|
+
const parent = state.items.get(op.parentId);
|
|
1886
|
+
if (parent == null) {
|
|
1887
|
+
return { modified: false };
|
|
1888
|
+
}
|
|
1889
|
+
return parent._attachChild(op.id, op.parentKey, new LiveList(), op.opId, isLocal);
|
|
1890
|
+
}
|
|
1891
|
+
case OpType.CreateRegister: {
|
|
1892
|
+
const parent = state.items.get(op.parentId);
|
|
1893
|
+
if (parent == null) {
|
|
1894
|
+
return { modified: false };
|
|
1895
|
+
}
|
|
1896
|
+
return parent._attachChild(op.id, op.parentKey, new LiveRegister(op.data), op.opId, isLocal);
|
|
1897
|
+
}
|
|
1898
|
+
case OpType.CreateMap: {
|
|
1899
|
+
const parent = state.items.get(op.parentId);
|
|
1900
|
+
if (parent == null) {
|
|
1901
|
+
return { modified: false };
|
|
1902
|
+
}
|
|
1903
|
+
return parent._attachChild(op.id, op.parentKey, new LiveMap(), op.opId, isLocal);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
return { modified: false };
|
|
1907
|
+
}
|
|
1908
|
+
function subscribe(firstParam, listener, options) {
|
|
1909
|
+
if (firstParam instanceof AbstractCrdt) {
|
|
1910
|
+
return crdtSubscribe(firstParam, listener, options);
|
|
1911
|
+
} else if (typeof firstParam === "function") {
|
|
1912
|
+
return genericSubscribe(firstParam);
|
|
1913
|
+
} else if (!isValidRoomEventType(firstParam)) {
|
|
1914
|
+
throw new Error(`"${firstParam}" is not a valid event name`);
|
|
1915
|
+
}
|
|
1916
|
+
state.listeners[firstParam].push(listener);
|
|
1917
|
+
return () => {
|
|
1918
|
+
const callbacks = state.listeners[firstParam];
|
|
1919
|
+
remove(callbacks, listener);
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
function unsubscribe(event, callback) {
|
|
1923
|
+
console.warn(`unsubscribe is depreacted and will be removed in a future version.
|
|
1924
|
+
use the callback returned by subscribe instead.
|
|
1925
|
+
See v0.13 release notes for more information.
|
|
1926
|
+
`);
|
|
1927
|
+
if (!isValidRoomEventType(event)) {
|
|
1928
|
+
throw new Error(`"${event}" is not a valid event name`);
|
|
1929
|
+
}
|
|
1930
|
+
const callbacks = state.listeners[event];
|
|
1931
|
+
remove(callbacks, callback);
|
|
1932
|
+
}
|
|
1933
|
+
function getConnectionState() {
|
|
1934
|
+
return state.connection.state;
|
|
1935
|
+
}
|
|
1936
|
+
function getSelf() {
|
|
1937
|
+
return state.connection.state === "open" || state.connection.state === "connecting" ? {
|
|
1938
|
+
connectionId: state.connection.id,
|
|
1939
|
+
id: state.connection.userId,
|
|
1940
|
+
info: state.connection.userInfo,
|
|
1941
|
+
presence: getPresence()
|
|
1942
|
+
} : null;
|
|
1943
|
+
}
|
|
1944
|
+
function connect() {
|
|
1945
|
+
if (state.connection.state !== "closed" && state.connection.state !== "unavailable") {
|
|
1946
|
+
return null;
|
|
1947
|
+
}
|
|
1948
|
+
const auth = prepareAuthEndpoint(context.authentication, context.fetchPolyfill);
|
|
1949
|
+
const createWebSocket = prepareCreateWebSocket(context.liveblocksServer, context.WebSocketPolyfill);
|
|
1950
|
+
updateConnection({ state: "authenticating" });
|
|
1951
|
+
effects.authenticate(auth, createWebSocket);
|
|
1952
|
+
}
|
|
1953
|
+
function updatePresence(overrides, options) {
|
|
1954
|
+
const oldValues = {};
|
|
1955
|
+
if (state.buffer.presence == null) {
|
|
1956
|
+
state.buffer.presence = {};
|
|
1957
|
+
}
|
|
1958
|
+
for (const key in overrides) {
|
|
1959
|
+
state.buffer.presence[key] = overrides[key];
|
|
1960
|
+
oldValues[key] = state.me[key];
|
|
1961
|
+
}
|
|
1962
|
+
state.me = __spreadValues$1(__spreadValues$1({}, state.me), overrides);
|
|
1963
|
+
if (state.isBatching) {
|
|
1964
|
+
if (options == null ? void 0 : options.addToHistory) {
|
|
1965
|
+
state.batch.reverseOps.push({ type: "presence", data: oldValues });
|
|
1966
|
+
}
|
|
1967
|
+
state.batch.updates.presence = true;
|
|
1968
|
+
} else {
|
|
1969
|
+
tryFlushing();
|
|
1970
|
+
if (options == null ? void 0 : options.addToHistory) {
|
|
1971
|
+
addToUndoStack([{ type: "presence", data: oldValues }]);
|
|
1972
|
+
}
|
|
1973
|
+
notify({ presence: true });
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
function authenticationSuccess(token, socket) {
|
|
1977
|
+
socket.addEventListener("message", onMessage);
|
|
1978
|
+
socket.addEventListener("open", onOpen);
|
|
1979
|
+
socket.addEventListener("close", onClose);
|
|
1980
|
+
socket.addEventListener("error", onError);
|
|
1981
|
+
updateConnection({
|
|
1982
|
+
state: "connecting",
|
|
1983
|
+
id: token.actor,
|
|
1984
|
+
userInfo: token.info,
|
|
1985
|
+
userId: token.id
|
|
1986
|
+
});
|
|
1987
|
+
state.idFactory = makeIdFactory(token.actor);
|
|
1988
|
+
state.socket = socket;
|
|
1989
|
+
}
|
|
1990
|
+
function authenticationFailure(error) {
|
|
1991
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1992
|
+
console.error("Call to authentication endpoint failed", error);
|
|
1993
|
+
}
|
|
1994
|
+
updateConnection({ state: "unavailable" });
|
|
1995
|
+
state.numberOfRetry++;
|
|
1996
|
+
state.timeoutHandles.reconnect = effects.scheduleReconnect(getRetryDelay());
|
|
1997
|
+
}
|
|
1998
|
+
function onVisibilityChange(visibilityState) {
|
|
1999
|
+
if (visibilityState === "visible" && state.connection.state === "open") {
|
|
2000
|
+
heartbeat();
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
function onUpdatePresenceMessage(message) {
|
|
2004
|
+
const user = state.users[message.actor];
|
|
2005
|
+
if (user == null) {
|
|
2006
|
+
state.users[message.actor] = {
|
|
2007
|
+
connectionId: message.actor,
|
|
2008
|
+
presence: message.data
|
|
2009
|
+
};
|
|
2010
|
+
} else {
|
|
2011
|
+
state.users[message.actor] = {
|
|
2012
|
+
id: user.id,
|
|
2013
|
+
info: user.info,
|
|
2014
|
+
connectionId: message.actor,
|
|
2015
|
+
presence: __spreadValues$1(__spreadValues$1({}, user.presence), message.data)
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
return {
|
|
2019
|
+
type: "update",
|
|
2020
|
+
updates: message.data,
|
|
2021
|
+
user: state.users[message.actor]
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
function onUserLeftMessage(message) {
|
|
2025
|
+
const userLeftMessage = message;
|
|
2026
|
+
const user = state.users[userLeftMessage.actor];
|
|
2027
|
+
if (user) {
|
|
2028
|
+
delete state.users[userLeftMessage.actor];
|
|
2029
|
+
return { type: "leave", user };
|
|
2030
|
+
}
|
|
2031
|
+
return null;
|
|
2032
|
+
}
|
|
2033
|
+
function onRoomStateMessage(message) {
|
|
2034
|
+
const newUsers = {};
|
|
2035
|
+
for (const key in message.users) {
|
|
2036
|
+
const connectionId = Number.parseInt(key);
|
|
2037
|
+
const user = message.users[key];
|
|
2038
|
+
newUsers[connectionId] = {
|
|
2039
|
+
connectionId,
|
|
2040
|
+
info: user.info,
|
|
2041
|
+
id: user.id
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
state.users = newUsers;
|
|
2045
|
+
return { type: "reset" };
|
|
2046
|
+
}
|
|
2047
|
+
function onNavigatorOnline() {
|
|
2048
|
+
if (state.connection.state === "unavailable") {
|
|
2049
|
+
reconnect();
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
function onEvent(message) {
|
|
2053
|
+
for (const listener of state.listeners.event) {
|
|
2054
|
+
listener({ connectionId: message.actor, event: message.event });
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
function onUserJoinedMessage(message) {
|
|
2058
|
+
state.users[message.actor] = {
|
|
2059
|
+
connectionId: message.actor,
|
|
2060
|
+
info: message.info,
|
|
2061
|
+
id: message.id
|
|
2062
|
+
};
|
|
2063
|
+
if (state.me) {
|
|
2064
|
+
state.buffer.messages.push({
|
|
2065
|
+
type: ClientMessageType.UpdatePresence,
|
|
2066
|
+
data: state.me,
|
|
2067
|
+
targetActor: message.actor
|
|
2068
|
+
});
|
|
2069
|
+
tryFlushing();
|
|
2070
|
+
}
|
|
2071
|
+
return { type: "enter", user: state.users[message.actor] };
|
|
2072
|
+
}
|
|
2073
|
+
function onMessage(event) {
|
|
2074
|
+
if (event.data === "pong") {
|
|
2075
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2076
|
+
return;
|
|
2077
|
+
}
|
|
2078
|
+
const message = JSON.parse(event.data);
|
|
2079
|
+
let subMessages = [];
|
|
2080
|
+
if (Array.isArray(message)) {
|
|
2081
|
+
subMessages = message;
|
|
2082
|
+
} else {
|
|
2083
|
+
subMessages.push(message);
|
|
2084
|
+
}
|
|
2085
|
+
const updates = {
|
|
2086
|
+
storageUpdates: /* @__PURE__ */ new Map(),
|
|
2087
|
+
others: []
|
|
2088
|
+
};
|
|
2089
|
+
for (const subMessage of subMessages) {
|
|
2090
|
+
switch (subMessage.type) {
|
|
2091
|
+
case ServerMessageType.UserJoined: {
|
|
2092
|
+
updates.others.push(onUserJoinedMessage(message));
|
|
2093
|
+
break;
|
|
2094
|
+
}
|
|
2095
|
+
case ServerMessageType.UpdatePresence: {
|
|
2096
|
+
updates.others.push(onUpdatePresenceMessage(subMessage));
|
|
2097
|
+
break;
|
|
2098
|
+
}
|
|
2099
|
+
case ServerMessageType.Event: {
|
|
2100
|
+
onEvent(subMessage);
|
|
2101
|
+
break;
|
|
2102
|
+
}
|
|
2103
|
+
case ServerMessageType.UserLeft: {
|
|
2104
|
+
const event2 = onUserLeftMessage(subMessage);
|
|
2105
|
+
if (event2) {
|
|
2106
|
+
updates.others.push(event2);
|
|
2107
|
+
}
|
|
2108
|
+
break;
|
|
2109
|
+
}
|
|
2110
|
+
case ServerMessageType.RoomState: {
|
|
2111
|
+
updates.others.push(onRoomStateMessage(subMessage));
|
|
2112
|
+
break;
|
|
2113
|
+
}
|
|
2114
|
+
case ServerMessageType.InitialStorageState: {
|
|
2115
|
+
createOrUpdateRootFromMessage(subMessage);
|
|
2116
|
+
applyAndSendOfflineOps();
|
|
2117
|
+
_getInitialStateResolver == null ? void 0 : _getInitialStateResolver();
|
|
2118
|
+
break;
|
|
2119
|
+
}
|
|
2120
|
+
case ServerMessageType.UpdateStorage: {
|
|
2121
|
+
const applyResult = apply(subMessage.ops, false);
|
|
2122
|
+
applyResult.updates.storageUpdates.forEach((value, key) => {
|
|
2123
|
+
updates.storageUpdates.set(key, mergeStorageUpdates(updates.storageUpdates.get(key), value));
|
|
2124
|
+
});
|
|
2125
|
+
break;
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
notify(updates);
|
|
2130
|
+
}
|
|
2131
|
+
function onClose(event) {
|
|
2132
|
+
state.socket = null;
|
|
2133
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2134
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
2135
|
+
if (state.timeoutHandles.flush) {
|
|
2136
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
2137
|
+
}
|
|
2138
|
+
clearTimeout(state.timeoutHandles.reconnect);
|
|
2139
|
+
state.users = {};
|
|
2140
|
+
notify({ others: [{ type: "reset" }] });
|
|
2141
|
+
if (event.code >= 4e3 && event.code <= 4100) {
|
|
2142
|
+
updateConnection({ state: "failed" });
|
|
2143
|
+
const error = new LiveblocksError(event.reason, event.code);
|
|
2144
|
+
for (const listener of state.listeners.error) {
|
|
2145
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2146
|
+
console.error(`Connection to Liveblocks websocket server closed. Reason: ${error.message} (code: ${error.code})`);
|
|
2147
|
+
}
|
|
2148
|
+
listener(error);
|
|
2149
|
+
}
|
|
2150
|
+
} else if (event.wasClean === false) {
|
|
2151
|
+
state.numberOfRetry++;
|
|
2152
|
+
const delay = getRetryDelay();
|
|
2153
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2154
|
+
console.warn(`Connection to Liveblocks websocket server closed (code: ${event.code}). Retrying in ${delay}ms.`);
|
|
2155
|
+
}
|
|
2156
|
+
updateConnection({ state: "unavailable" });
|
|
2157
|
+
state.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
|
|
2158
|
+
} else {
|
|
2159
|
+
updateConnection({ state: "closed" });
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
function updateConnection(connection) {
|
|
2163
|
+
state.connection = connection;
|
|
2164
|
+
for (const listener of state.listeners.connection) {
|
|
2165
|
+
listener(connection.state);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
function getRetryDelay() {
|
|
2169
|
+
return BACKOFF_RETRY_DELAYS[state.numberOfRetry < BACKOFF_RETRY_DELAYS.length ? state.numberOfRetry : BACKOFF_RETRY_DELAYS.length - 1];
|
|
2170
|
+
}
|
|
2171
|
+
function onError() {
|
|
2172
|
+
}
|
|
2173
|
+
function onOpen() {
|
|
2174
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
2175
|
+
state.intervalHandles.heartbeat = effects.startHeartbeatInterval();
|
|
2176
|
+
if (state.connection.state === "connecting") {
|
|
2177
|
+
updateConnection(__spreadProps$1(__spreadValues$1({}, state.connection), { state: "open" }));
|
|
2178
|
+
state.numberOfRetry = 0;
|
|
2179
|
+
if (state.lastConnectionId !== void 0) {
|
|
2180
|
+
state.buffer.presence = state.me;
|
|
2181
|
+
tryFlushing();
|
|
2182
|
+
}
|
|
2183
|
+
state.lastConnectionId = state.connection.id;
|
|
2184
|
+
if (state.root) {
|
|
2185
|
+
state.buffer.messages.push({ type: ClientMessageType.FetchStorage });
|
|
2186
|
+
}
|
|
2187
|
+
tryFlushing();
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
function heartbeat() {
|
|
2191
|
+
if (state.socket == null) {
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2195
|
+
state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
|
|
2196
|
+
if (state.socket.readyState === state.socket.OPEN) {
|
|
2197
|
+
state.socket.send("ping");
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
function pongTimeout() {
|
|
2201
|
+
reconnect();
|
|
2202
|
+
}
|
|
2203
|
+
function reconnect() {
|
|
2204
|
+
if (state.socket) {
|
|
2205
|
+
state.socket.removeEventListener("open", onOpen);
|
|
2206
|
+
state.socket.removeEventListener("message", onMessage);
|
|
2207
|
+
state.socket.removeEventListener("close", onClose);
|
|
2208
|
+
state.socket.removeEventListener("error", onError);
|
|
2209
|
+
state.socket.close();
|
|
2210
|
+
state.socket = null;
|
|
2211
|
+
}
|
|
2212
|
+
updateConnection({ state: "unavailable" });
|
|
2213
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2214
|
+
if (state.timeoutHandles.flush) {
|
|
2215
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
2216
|
+
}
|
|
2217
|
+
clearTimeout(state.timeoutHandles.reconnect);
|
|
2218
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
2219
|
+
connect();
|
|
2220
|
+
}
|
|
2221
|
+
function applyAndSendOfflineOps() {
|
|
2222
|
+
if (state.offlineOperations.size === 0) {
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
const messages = [];
|
|
2226
|
+
const ops = Array.from(state.offlineOperations.values());
|
|
2227
|
+
const result = apply(ops, true);
|
|
2228
|
+
messages.push({
|
|
2229
|
+
type: ClientMessageType.UpdateStorage,
|
|
2230
|
+
ops
|
|
2231
|
+
});
|
|
2232
|
+
notify(result.updates);
|
|
2233
|
+
effects.send(messages);
|
|
2234
|
+
}
|
|
2235
|
+
function tryFlushing() {
|
|
2236
|
+
const storageOps = state.buffer.storageOperations;
|
|
2237
|
+
if (storageOps.length > 0) {
|
|
2238
|
+
storageOps.forEach((op) => {
|
|
2239
|
+
state.offlineOperations.set(op.opId, op);
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
if (state.socket == null || state.socket.readyState !== state.socket.OPEN) {
|
|
2243
|
+
state.buffer.storageOperations = [];
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
const now = Date.now();
|
|
2247
|
+
const elapsedTime = now - state.lastFlushTime;
|
|
2248
|
+
if (elapsedTime > context.throttleDelay) {
|
|
2249
|
+
const messages = flushDataToMessages(state);
|
|
2250
|
+
if (messages.length === 0) {
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
2253
|
+
effects.send(messages);
|
|
2254
|
+
state.buffer = {
|
|
2255
|
+
messages: [],
|
|
2256
|
+
storageOperations: [],
|
|
2257
|
+
presence: null
|
|
2258
|
+
};
|
|
2259
|
+
state.lastFlushTime = now;
|
|
2260
|
+
} else {
|
|
2261
|
+
if (state.timeoutHandles.flush != null) {
|
|
2262
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
2263
|
+
}
|
|
2264
|
+
state.timeoutHandles.flush = effects.delayFlush(context.throttleDelay - (now - state.lastFlushTime));
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
function flushDataToMessages(state2) {
|
|
2268
|
+
const messages = [];
|
|
2269
|
+
if (state2.buffer.presence) {
|
|
2270
|
+
messages.push({
|
|
2271
|
+
type: ClientMessageType.UpdatePresence,
|
|
2272
|
+
data: state2.buffer.presence
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
for (const event of state2.buffer.messages) {
|
|
2276
|
+
messages.push(event);
|
|
2277
|
+
}
|
|
2278
|
+
if (state2.buffer.storageOperations.length > 0) {
|
|
2279
|
+
messages.push({
|
|
2280
|
+
type: ClientMessageType.UpdateStorage,
|
|
2281
|
+
ops: state2.buffer.storageOperations
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
return messages;
|
|
2285
|
+
}
|
|
2286
|
+
function disconnect() {
|
|
2287
|
+
if (state.socket) {
|
|
2288
|
+
state.socket.removeEventListener("open", onOpen);
|
|
2289
|
+
state.socket.removeEventListener("message", onMessage);
|
|
2290
|
+
state.socket.removeEventListener("close", onClose);
|
|
2291
|
+
state.socket.removeEventListener("error", onError);
|
|
2292
|
+
state.socket.close();
|
|
2293
|
+
state.socket = null;
|
|
2294
|
+
}
|
|
2295
|
+
updateConnection({ state: "closed" });
|
|
2296
|
+
if (state.timeoutHandles.flush) {
|
|
2297
|
+
clearTimeout(state.timeoutHandles.flush);
|
|
2298
|
+
}
|
|
2299
|
+
clearTimeout(state.timeoutHandles.reconnect);
|
|
2300
|
+
clearTimeout(state.timeoutHandles.pongTimeout);
|
|
2301
|
+
clearInterval(state.intervalHandles.heartbeat);
|
|
2302
|
+
state.users = {};
|
|
2303
|
+
notify({ others: [{ type: "reset" }] });
|
|
2304
|
+
clearListeners();
|
|
2305
|
+
}
|
|
2306
|
+
function clearListeners() {
|
|
2307
|
+
for (const key in state.listeners) {
|
|
2308
|
+
state.listeners[key] = [];
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
function getPresence() {
|
|
2312
|
+
return state.me;
|
|
2313
|
+
}
|
|
2314
|
+
function getOthers() {
|
|
2315
|
+
return state.others;
|
|
2316
|
+
}
|
|
2317
|
+
function broadcastEvent(event, options = {
|
|
2318
|
+
shouldQueueEventIfNotReady: false
|
|
2319
|
+
}) {
|
|
2320
|
+
if (state.socket == null && options.shouldQueueEventIfNotReady == false) {
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
state.buffer.messages.push({
|
|
2324
|
+
type: ClientMessageType.ClientEvent,
|
|
2325
|
+
event
|
|
2326
|
+
});
|
|
2327
|
+
tryFlushing();
|
|
2328
|
+
}
|
|
2329
|
+
function dispatch(ops) {
|
|
2330
|
+
state.buffer.storageOperations.push(...ops);
|
|
2331
|
+
tryFlushing();
|
|
2332
|
+
}
|
|
2333
|
+
let _getInitialStatePromise = null;
|
|
2334
|
+
let _getInitialStateResolver = null;
|
|
2335
|
+
async function getStorage() {
|
|
2336
|
+
if (state.root) {
|
|
2337
|
+
return {
|
|
2338
|
+
root: state.root
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
if (_getInitialStatePromise == null) {
|
|
2342
|
+
state.buffer.messages.push({ type: ClientMessageType.FetchStorage });
|
|
2343
|
+
tryFlushing();
|
|
2344
|
+
_getInitialStatePromise = new Promise((resolve) => _getInitialStateResolver = resolve);
|
|
2345
|
+
}
|
|
2346
|
+
await _getInitialStatePromise;
|
|
2347
|
+
return {
|
|
2348
|
+
root: state.root
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
function undo() {
|
|
2352
|
+
if (state.isBatching) {
|
|
2353
|
+
throw new Error("undo is not allowed during a batch");
|
|
2354
|
+
}
|
|
2355
|
+
const historyItem = state.undoStack.pop();
|
|
2356
|
+
if (historyItem == null) {
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
state.isHistoryPaused = false;
|
|
2360
|
+
const result = apply(historyItem, true);
|
|
2361
|
+
notify(result.updates);
|
|
2362
|
+
state.redoStack.push(result.reverse);
|
|
2363
|
+
for (const op of historyItem) {
|
|
2364
|
+
if (op.type !== "presence") {
|
|
2365
|
+
state.buffer.storageOperations.push(op);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
tryFlushing();
|
|
2369
|
+
}
|
|
2370
|
+
function redo() {
|
|
2371
|
+
if (state.isBatching) {
|
|
2372
|
+
throw new Error("redo is not allowed during a batch");
|
|
2373
|
+
}
|
|
2374
|
+
const historyItem = state.redoStack.pop();
|
|
2375
|
+
if (historyItem == null) {
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
state.isHistoryPaused = false;
|
|
2379
|
+
const result = apply(historyItem, true);
|
|
2380
|
+
notify(result.updates);
|
|
2381
|
+
state.undoStack.push(result.reverse);
|
|
2382
|
+
for (const op of historyItem) {
|
|
2383
|
+
if (op.type !== "presence") {
|
|
2384
|
+
state.buffer.storageOperations.push(op);
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
tryFlushing();
|
|
2388
|
+
}
|
|
2389
|
+
function batch(callback) {
|
|
2390
|
+
if (state.isBatching) {
|
|
2391
|
+
throw new Error("batch should not be called during a batch");
|
|
2392
|
+
}
|
|
2393
|
+
state.isBatching = true;
|
|
2394
|
+
try {
|
|
2395
|
+
callback();
|
|
2396
|
+
} finally {
|
|
2397
|
+
state.isBatching = false;
|
|
2398
|
+
if (state.batch.reverseOps.length > 0) {
|
|
2399
|
+
addToUndoStack(state.batch.reverseOps);
|
|
2400
|
+
}
|
|
2401
|
+
if (state.batch.ops.length > 0) {
|
|
2402
|
+
state.redoStack = [];
|
|
2403
|
+
}
|
|
2404
|
+
if (state.batch.ops.length > 0) {
|
|
2405
|
+
dispatch(state.batch.ops);
|
|
2406
|
+
}
|
|
2407
|
+
notify(state.batch.updates);
|
|
2408
|
+
state.batch = {
|
|
2409
|
+
ops: [],
|
|
2410
|
+
reverseOps: [],
|
|
2411
|
+
updates: {
|
|
2412
|
+
others: [],
|
|
2413
|
+
storageUpdates: /* @__PURE__ */ new Map(),
|
|
2414
|
+
presence: false
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
tryFlushing();
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
function pauseHistory() {
|
|
2421
|
+
state.pausedHistory = [];
|
|
2422
|
+
state.isHistoryPaused = true;
|
|
2423
|
+
}
|
|
2424
|
+
function resumeHistory() {
|
|
2425
|
+
state.isHistoryPaused = false;
|
|
2426
|
+
if (state.pausedHistory.length > 0) {
|
|
2427
|
+
addToUndoStack(state.pausedHistory);
|
|
2428
|
+
}
|
|
2429
|
+
state.pausedHistory = [];
|
|
2430
|
+
}
|
|
2431
|
+
function simulateSocketClose() {
|
|
2432
|
+
if (state.socket) {
|
|
2433
|
+
state.socket.close();
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
function simulateSendCloseEvent(event) {
|
|
2437
|
+
if (state.socket) {
|
|
2438
|
+
onClose(event);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
return {
|
|
2442
|
+
onClose,
|
|
2443
|
+
onMessage,
|
|
2444
|
+
authenticationSuccess,
|
|
2445
|
+
heartbeat,
|
|
2446
|
+
onNavigatorOnline,
|
|
2447
|
+
simulateSocketClose,
|
|
2448
|
+
simulateSendCloseEvent,
|
|
2449
|
+
onVisibilityChange,
|
|
2450
|
+
getUndoStack: () => state.undoStack,
|
|
2451
|
+
getItemsCount: () => state.items.size,
|
|
2452
|
+
connect,
|
|
2453
|
+
disconnect,
|
|
2454
|
+
subscribe,
|
|
2455
|
+
unsubscribe,
|
|
2456
|
+
updatePresence,
|
|
2457
|
+
broadcastEvent,
|
|
2458
|
+
batch,
|
|
2459
|
+
undo,
|
|
2460
|
+
redo,
|
|
2461
|
+
pauseHistory,
|
|
2462
|
+
resumeHistory,
|
|
2463
|
+
getStorage,
|
|
2464
|
+
selectors: {
|
|
2465
|
+
getConnectionState,
|
|
2466
|
+
getSelf,
|
|
2467
|
+
getPresence,
|
|
2468
|
+
getOthers
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
function defaultState(me, defaultStorageRoot) {
|
|
2473
|
+
return {
|
|
2474
|
+
connection: { state: "closed" },
|
|
2475
|
+
lastConnectionId: null,
|
|
2476
|
+
socket: null,
|
|
2477
|
+
listeners: {
|
|
2478
|
+
event: [],
|
|
2479
|
+
others: [],
|
|
2480
|
+
"my-presence": [],
|
|
2481
|
+
error: [],
|
|
2482
|
+
connection: [],
|
|
2483
|
+
storage: []
|
|
2484
|
+
},
|
|
2485
|
+
numberOfRetry: 0,
|
|
2486
|
+
lastFlushTime: 0,
|
|
2487
|
+
timeoutHandles: {
|
|
2488
|
+
flush: null,
|
|
2489
|
+
reconnect: 0,
|
|
2490
|
+
pongTimeout: 0
|
|
2491
|
+
},
|
|
2492
|
+
buffer: {
|
|
2493
|
+
presence: me == null ? {} : me,
|
|
2494
|
+
messages: [],
|
|
2495
|
+
storageOperations: []
|
|
2496
|
+
},
|
|
2497
|
+
intervalHandles: {
|
|
2498
|
+
heartbeat: 0
|
|
2499
|
+
},
|
|
2500
|
+
me: me == null ? {} : me,
|
|
2501
|
+
users: {},
|
|
2502
|
+
others: makeOthers({}),
|
|
2503
|
+
defaultStorageRoot,
|
|
2504
|
+
idFactory: null,
|
|
2505
|
+
clock: 0,
|
|
2506
|
+
opClock: 0,
|
|
2507
|
+
items: /* @__PURE__ */ new Map(),
|
|
2508
|
+
root: void 0,
|
|
2509
|
+
undoStack: [],
|
|
2510
|
+
redoStack: [],
|
|
2511
|
+
isHistoryPaused: false,
|
|
2512
|
+
pausedHistory: [],
|
|
2513
|
+
isBatching: false,
|
|
2514
|
+
batch: {
|
|
2515
|
+
ops: [],
|
|
2516
|
+
updates: {
|
|
2517
|
+
storageUpdates: /* @__PURE__ */ new Map(),
|
|
2518
|
+
presence: false,
|
|
2519
|
+
others: []
|
|
2520
|
+
},
|
|
2521
|
+
reverseOps: []
|
|
2522
|
+
},
|
|
2523
|
+
offlineOperations: /* @__PURE__ */ new Map()
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2526
|
+
function createRoom(options, context) {
|
|
2527
|
+
const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
|
|
2528
|
+
const machine = makeStateMachine(state, context);
|
|
2529
|
+
const room = {
|
|
2530
|
+
id: context.room,
|
|
2531
|
+
getConnectionState: machine.selectors.getConnectionState,
|
|
2532
|
+
getSelf: machine.selectors.getSelf,
|
|
2533
|
+
subscribe: machine.subscribe,
|
|
2534
|
+
unsubscribe: machine.unsubscribe,
|
|
2535
|
+
getPresence: machine.selectors.getPresence,
|
|
2536
|
+
updatePresence: machine.updatePresence,
|
|
2537
|
+
getOthers: machine.selectors.getOthers,
|
|
2538
|
+
broadcastEvent: machine.broadcastEvent,
|
|
2539
|
+
getStorage: machine.getStorage,
|
|
2540
|
+
batch: machine.batch,
|
|
2541
|
+
history: {
|
|
2542
|
+
undo: machine.undo,
|
|
2543
|
+
redo: machine.redo,
|
|
2544
|
+
pause: machine.pauseHistory,
|
|
2545
|
+
resume: machine.resumeHistory
|
|
2546
|
+
},
|
|
2547
|
+
internalDevTools: {
|
|
2548
|
+
closeWebsocket: machine.simulateSocketClose,
|
|
2549
|
+
sendCloseEvent: machine.simulateSendCloseEvent
|
|
2550
|
+
}
|
|
2551
|
+
};
|
|
2552
|
+
return {
|
|
2553
|
+
connect: machine.connect,
|
|
2554
|
+
disconnect: machine.disconnect,
|
|
2555
|
+
onNavigatorOnline: machine.onNavigatorOnline,
|
|
2556
|
+
onVisibilityChange: machine.onVisibilityChange,
|
|
2557
|
+
room
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
class LiveblocksError extends Error {
|
|
2561
|
+
constructor(message, code) {
|
|
2562
|
+
super(message);
|
|
2563
|
+
this.code = code;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
function parseToken(token) {
|
|
2567
|
+
const tokenParts = token.split(".");
|
|
2568
|
+
if (tokenParts.length !== 3) {
|
|
2569
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
2570
|
+
}
|
|
2571
|
+
const data = JSON.parse(atob(tokenParts[1]));
|
|
2572
|
+
if (typeof data.actor !== "number") {
|
|
2573
|
+
throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
|
|
2574
|
+
}
|
|
2575
|
+
return data;
|
|
2576
|
+
}
|
|
2577
|
+
function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
2578
|
+
if (typeof window === "undefined" && WebSocketPolyfill == null) {
|
|
2579
|
+
throw new Error("To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill.");
|
|
2580
|
+
}
|
|
2581
|
+
const ws = WebSocketPolyfill || WebSocket;
|
|
2582
|
+
return (token) => {
|
|
2583
|
+
return new ws(`${liveblocksServer}/?token=${token}`);
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
2587
|
+
if (authentication.type === "public") {
|
|
2588
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
2589
|
+
throw new Error("To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill.");
|
|
2590
|
+
}
|
|
2591
|
+
return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
2592
|
+
room,
|
|
2593
|
+
publicApiKey: authentication.publicApiKey
|
|
2594
|
+
});
|
|
2595
|
+
}
|
|
2596
|
+
if (authentication.type === "private") {
|
|
2597
|
+
if (typeof window === "undefined" && fetchPolyfill == null) {
|
|
2598
|
+
throw new Error("To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill.");
|
|
2599
|
+
}
|
|
2600
|
+
return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
|
|
2601
|
+
room
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2604
|
+
if (authentication.type === "custom") {
|
|
2605
|
+
return authentication.callback;
|
|
2606
|
+
}
|
|
2607
|
+
throw new Error("Internal error. Unexpected authentication type");
|
|
2608
|
+
}
|
|
2609
|
+
async function fetchAuthEndpoint(fetch2, endpoint, body) {
|
|
2610
|
+
const res = await fetch2(endpoint, {
|
|
2611
|
+
method: "POST",
|
|
2612
|
+
headers: {
|
|
2613
|
+
"Content-Type": "application/json"
|
|
2614
|
+
},
|
|
2615
|
+
body: JSON.stringify(body)
|
|
2616
|
+
});
|
|
2617
|
+
if (!res.ok) {
|
|
2618
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
2619
|
+
}
|
|
2620
|
+
let authResponse = null;
|
|
2621
|
+
try {
|
|
2622
|
+
authResponse = await res.json();
|
|
2623
|
+
} catch (er) {
|
|
2624
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
2625
|
+
}
|
|
2626
|
+
if (typeof authResponse.token !== "string") {
|
|
2627
|
+
throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
|
|
2628
|
+
}
|
|
2629
|
+
return authResponse;
|
|
2630
|
+
}
|
|
2631
|
+
class AuthenticationError extends Error {
|
|
2632
|
+
constructor(message) {
|
|
2633
|
+
super(message);
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
function createClient(options) {
|
|
2638
|
+
const clientOptions = options;
|
|
2639
|
+
const throttleDelay = getThrottleDelayFromOptions(options);
|
|
2640
|
+
const rooms = /* @__PURE__ */ new Map();
|
|
2641
|
+
function getRoom(roomId) {
|
|
2642
|
+
const internalRoom = rooms.get(roomId);
|
|
2643
|
+
return internalRoom ? internalRoom.room : null;
|
|
2644
|
+
}
|
|
2645
|
+
function enter(roomId, options2 = {}) {
|
|
2646
|
+
let internalRoom = rooms.get(roomId);
|
|
2647
|
+
if (internalRoom) {
|
|
2648
|
+
return internalRoom.room;
|
|
2649
|
+
}
|
|
2650
|
+
internalRoom = createRoom({
|
|
2651
|
+
defaultPresence: options2.defaultPresence,
|
|
2652
|
+
defaultStorageRoot: options2.defaultStorageRoot
|
|
2653
|
+
}, {
|
|
2654
|
+
room: roomId,
|
|
2655
|
+
throttleDelay,
|
|
2656
|
+
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
2657
|
+
fetchPolyfill: clientOptions.fetchPolyfill,
|
|
2658
|
+
liveblocksServer: clientOptions.liveblocksServer || "wss://liveblocks.net/v5",
|
|
2659
|
+
authentication: prepareAuthentication(clientOptions)
|
|
2660
|
+
});
|
|
2661
|
+
rooms.set(roomId, internalRoom);
|
|
2662
|
+
if (!options2.DO_NOT_USE_withoutConnecting) {
|
|
2663
|
+
internalRoom.connect();
|
|
2664
|
+
}
|
|
2665
|
+
return internalRoom.room;
|
|
2666
|
+
}
|
|
2667
|
+
function leave(roomId) {
|
|
2668
|
+
let room = rooms.get(roomId);
|
|
2669
|
+
if (room) {
|
|
2670
|
+
room.disconnect();
|
|
2671
|
+
rooms.delete(roomId);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
if (typeof window !== "undefined") {
|
|
2675
|
+
window.addEventListener("online", () => {
|
|
2676
|
+
for (const [, room] of rooms) {
|
|
2677
|
+
room.onNavigatorOnline();
|
|
2678
|
+
}
|
|
2679
|
+
});
|
|
2680
|
+
}
|
|
2681
|
+
if (typeof document !== "undefined") {
|
|
2682
|
+
document.addEventListener("visibilitychange", () => {
|
|
2683
|
+
for (const [, room] of rooms) {
|
|
2684
|
+
room.onVisibilityChange(document.visibilityState);
|
|
2685
|
+
}
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
return {
|
|
2689
|
+
getRoom,
|
|
2690
|
+
enter,
|
|
2691
|
+
leave
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
function getThrottleDelayFromOptions(options) {
|
|
2695
|
+
if (options.throttle === void 0) {
|
|
2696
|
+
return 100;
|
|
2697
|
+
}
|
|
2698
|
+
if (typeof options.throttle !== "number" || options.throttle < 80 || options.throttle > 1e3) {
|
|
2699
|
+
throw new Error("throttle should be a number between 80 and 1000.");
|
|
2700
|
+
}
|
|
2701
|
+
return options.throttle;
|
|
2702
|
+
}
|
|
2703
|
+
function prepareAuthentication(clientOptions) {
|
|
2704
|
+
if (typeof clientOptions.publicApiKey === "string") {
|
|
2705
|
+
return {
|
|
2706
|
+
type: "public",
|
|
2707
|
+
publicApiKey: clientOptions.publicApiKey,
|
|
2708
|
+
url: clientOptions.publicAuthorizeEndpoint || "https://liveblocks.io/api/public/authorize"
|
|
2709
|
+
};
|
|
2710
|
+
} else if (typeof clientOptions.authEndpoint === "string") {
|
|
2711
|
+
return {
|
|
2712
|
+
type: "private",
|
|
2713
|
+
url: clientOptions.authEndpoint
|
|
2714
|
+
};
|
|
2715
|
+
} else if (typeof clientOptions.authEndpoint === "function") {
|
|
2716
|
+
return {
|
|
2717
|
+
type: "custom",
|
|
2718
|
+
callback: clientOptions.authEndpoint
|
|
2719
|
+
};
|
|
2720
|
+
}
|
|
2721
|
+
throw new Error("Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient");
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
var __defProp = Object.defineProperty;
|
|
2725
|
+
var __defProps = Object.defineProperties;
|
|
2726
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
2727
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
2728
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
2729
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
2730
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
2731
|
+
var __spreadValues = (a, b) => {
|
|
2732
|
+
for (var prop in b || (b = {}))
|
|
2733
|
+
if (__hasOwnProp.call(b, prop))
|
|
2734
|
+
__defNormalProp(a, prop, b[prop]);
|
|
2735
|
+
if (__getOwnPropSymbols)
|
|
2736
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
2737
|
+
if (__propIsEnum.call(b, prop))
|
|
2738
|
+
__defNormalProp(a, prop, b[prop]);
|
|
2739
|
+
}
|
|
2740
|
+
return a;
|
|
2741
|
+
};
|
|
2742
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
2743
|
+
function liveObjectToJson(liveObject) {
|
|
2744
|
+
const result = {};
|
|
2745
|
+
const obj = liveObject.toObject();
|
|
2746
|
+
for (const key in obj) {
|
|
2747
|
+
result[key] = liveNodeToJson(obj[key]);
|
|
2748
|
+
}
|
|
2749
|
+
return result;
|
|
2750
|
+
}
|
|
2751
|
+
function liveMapToJson(map) {
|
|
2752
|
+
const result = {};
|
|
2753
|
+
const obj = Object.fromEntries(map);
|
|
2754
|
+
for (const key in obj) {
|
|
2755
|
+
result[key] = liveNodeToJson(obj[key]);
|
|
2756
|
+
}
|
|
2757
|
+
return result;
|
|
2758
|
+
}
|
|
2759
|
+
function liveListToJson(value) {
|
|
2760
|
+
return value.toArray().map(liveNodeToJson);
|
|
2761
|
+
}
|
|
2762
|
+
function liveNodeToJson(value) {
|
|
2763
|
+
if (value instanceof LiveObject) {
|
|
2764
|
+
return liveObjectToJson(value);
|
|
2765
|
+
} else if (value instanceof LiveList) {
|
|
2766
|
+
return liveListToJson(value);
|
|
2767
|
+
} else if (value instanceof LiveMap) {
|
|
2768
|
+
return liveMapToJson(value);
|
|
2769
|
+
} else if (value instanceof LiveRegister) {
|
|
2770
|
+
return value.data;
|
|
2771
|
+
}
|
|
2772
|
+
return value;
|
|
2773
|
+
}
|
|
2774
|
+
function isPlainObject(obj) {
|
|
2775
|
+
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
2776
|
+
}
|
|
2777
|
+
function anyToCrdt(obj) {
|
|
2778
|
+
if (obj == null) {
|
|
2779
|
+
return obj;
|
|
2780
|
+
}
|
|
2781
|
+
if (Array.isArray(obj)) {
|
|
2782
|
+
return new LiveList(obj.map(anyToCrdt));
|
|
2783
|
+
}
|
|
2784
|
+
if (isPlainObject(obj)) {
|
|
2785
|
+
const init = {};
|
|
2786
|
+
for (const key in obj) {
|
|
2787
|
+
init[key] = anyToCrdt(obj[key]);
|
|
2788
|
+
}
|
|
2789
|
+
return new LiveObject(init);
|
|
2790
|
+
}
|
|
2791
|
+
return obj;
|
|
2792
|
+
}
|
|
2793
|
+
function patchLiveList(liveList, prev, next) {
|
|
2794
|
+
let i = 0;
|
|
2795
|
+
let prevEnd = prev.length - 1;
|
|
2796
|
+
let nextEnd = next.length - 1;
|
|
2797
|
+
let prevNode = prev[0];
|
|
2798
|
+
let nextNode = next[0];
|
|
2799
|
+
outer: {
|
|
2800
|
+
while (prevNode === nextNode) {
|
|
2801
|
+
++i;
|
|
2802
|
+
if (i > prevEnd || i > nextEnd) {
|
|
2803
|
+
break outer;
|
|
2804
|
+
}
|
|
2805
|
+
prevNode = prev[i];
|
|
2806
|
+
nextNode = next[i];
|
|
2807
|
+
}
|
|
2808
|
+
prevNode = prev[prevEnd];
|
|
2809
|
+
nextNode = next[nextEnd];
|
|
2810
|
+
while (prevNode === nextNode) {
|
|
2811
|
+
prevEnd--;
|
|
2812
|
+
nextEnd--;
|
|
2813
|
+
if (i > prevEnd || i > nextEnd) {
|
|
2814
|
+
break outer;
|
|
2815
|
+
}
|
|
2816
|
+
prevNode = prev[prevEnd];
|
|
2817
|
+
nextNode = next[nextEnd];
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
if (i > prevEnd) {
|
|
2821
|
+
if (i <= nextEnd) {
|
|
2822
|
+
while (i <= nextEnd) {
|
|
2823
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
2824
|
+
i++;
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
} else if (i > nextEnd) {
|
|
2828
|
+
let localI = i;
|
|
2829
|
+
while (localI <= prevEnd) {
|
|
2830
|
+
liveList.delete(i);
|
|
2831
|
+
localI++;
|
|
2832
|
+
}
|
|
2833
|
+
} else {
|
|
2834
|
+
while (i <= prevEnd && i <= nextEnd) {
|
|
2835
|
+
prevNode = prev[i];
|
|
2836
|
+
nextNode = next[i];
|
|
2837
|
+
const liveListNode = liveList.get(i);
|
|
2838
|
+
if (liveListNode instanceof LiveObject && isPlainObject(prevNode) && isPlainObject(nextNode)) {
|
|
2839
|
+
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
2840
|
+
} else {
|
|
2841
|
+
liveList.delete(i);
|
|
2842
|
+
liveList.insert(anyToCrdt(nextNode), i);
|
|
2843
|
+
}
|
|
2844
|
+
i++;
|
|
2845
|
+
}
|
|
2846
|
+
while (i <= nextEnd) {
|
|
2847
|
+
liveList.insert(anyToCrdt(next[i]), i);
|
|
2848
|
+
i++;
|
|
2849
|
+
}
|
|
2850
|
+
while (i <= prevEnd) {
|
|
2851
|
+
liveList.delete(i);
|
|
2852
|
+
i++;
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
2857
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2858
|
+
const nonSerializableValue = findNonSerializableValue(next);
|
|
2859
|
+
if (nonSerializableValue) {
|
|
2860
|
+
console.error(`New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.
|
|
2861
|
+
Only serializable value can be synced with Liveblocks.`);
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
const value = liveObject.get(key);
|
|
2866
|
+
if (next === void 0) {
|
|
2867
|
+
liveObject.delete(key);
|
|
2868
|
+
} else if (value === void 0) {
|
|
2869
|
+
liveObject.set(key, anyToCrdt(next));
|
|
2870
|
+
} else if (prev === next) {
|
|
2871
|
+
return;
|
|
2872
|
+
} else if (value instanceof LiveList && Array.isArray(prev) && Array.isArray(next)) {
|
|
2873
|
+
patchLiveList(value, prev, next);
|
|
2874
|
+
} else if (value instanceof LiveObject && isPlainObject(prev) && isPlainObject(next)) {
|
|
2875
|
+
patchLiveObject(value, prev, next);
|
|
2876
|
+
} else {
|
|
2877
|
+
liveObject.set(key, anyToCrdt(next));
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
function patchLiveObject(root, prev, next) {
|
|
2881
|
+
const updates = {};
|
|
2882
|
+
for (const key in next) {
|
|
2883
|
+
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
2884
|
+
}
|
|
2885
|
+
for (const key in prev) {
|
|
2886
|
+
if (next[key] === void 0) {
|
|
2887
|
+
root.delete(key);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
if (Object.keys(updates).length > 0) {
|
|
2891
|
+
root.update(updates);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
function getParentsPath(node) {
|
|
2895
|
+
const path = [];
|
|
2896
|
+
while (node._parentKey != null && node._parent != null) {
|
|
2897
|
+
if (node._parent instanceof LiveList) {
|
|
2898
|
+
path.push(node._parent._indexOfPosition(node._parentKey));
|
|
2899
|
+
} else {
|
|
2900
|
+
path.push(node._parentKey);
|
|
2901
|
+
}
|
|
2902
|
+
node = node._parent;
|
|
2903
|
+
}
|
|
2904
|
+
return path;
|
|
2905
|
+
}
|
|
2906
|
+
function patchImmutableObject(state, updates) {
|
|
2907
|
+
return updates.reduce((state2, update) => patchImmutableObjectWithUpdate(state2, update), state);
|
|
2908
|
+
}
|
|
2909
|
+
function patchImmutableObjectWithUpdate(state, update) {
|
|
2910
|
+
const path = getParentsPath(update.node);
|
|
2911
|
+
return patchImmutableNode(state, path, update);
|
|
2912
|
+
}
|
|
2913
|
+
function patchImmutableNode(state, path, update) {
|
|
2914
|
+
var _a, _b, _c, _d;
|
|
2915
|
+
const pathItem = path.pop();
|
|
2916
|
+
if (pathItem === void 0) {
|
|
2917
|
+
switch (update.type) {
|
|
2918
|
+
case "LiveObject": {
|
|
2919
|
+
if (typeof state !== "object") {
|
|
2920
|
+
throw new Error("Internal: received update on LiveObject but state was not an object");
|
|
2921
|
+
}
|
|
2922
|
+
let newState = Object.assign({}, state);
|
|
2923
|
+
for (const key in update.updates) {
|
|
2924
|
+
if (((_a = update.updates[key]) == null ? void 0 : _a.type) === "update") {
|
|
2925
|
+
newState[key] = liveNodeToJson(update.node.get(key));
|
|
2926
|
+
} else if (((_b = update.updates[key]) == null ? void 0 : _b.type) === "delete") {
|
|
2927
|
+
delete newState[key];
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
return newState;
|
|
2931
|
+
}
|
|
2932
|
+
case "LiveList": {
|
|
2933
|
+
if (Array.isArray(state) === false) {
|
|
2934
|
+
throw new Error("Internal: received update on LiveList but state was not an array");
|
|
2935
|
+
}
|
|
2936
|
+
let newState = state.map((x) => x);
|
|
2937
|
+
for (const listUpdate of update.updates) {
|
|
2938
|
+
if (listUpdate.type === "insert") {
|
|
2939
|
+
if (listUpdate.index === newState.length) {
|
|
2940
|
+
newState.push(liveNodeToJson(listUpdate.item));
|
|
2941
|
+
} else {
|
|
2942
|
+
newState = [
|
|
2943
|
+
...newState.slice(0, listUpdate.index),
|
|
2944
|
+
liveNodeToJson(listUpdate.item),
|
|
2945
|
+
...newState.slice(listUpdate.index)
|
|
2946
|
+
];
|
|
2947
|
+
}
|
|
2948
|
+
} else if (listUpdate.type === "delete") {
|
|
2949
|
+
newState.splice(listUpdate.index, 1);
|
|
2950
|
+
} else if (listUpdate.type === "move") {
|
|
2951
|
+
if (listUpdate.previousIndex > listUpdate.index) {
|
|
2952
|
+
newState = [
|
|
2953
|
+
...newState.slice(0, listUpdate.index),
|
|
2954
|
+
liveNodeToJson(listUpdate.item),
|
|
2955
|
+
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
2956
|
+
...newState.slice(listUpdate.previousIndex + 1)
|
|
2957
|
+
];
|
|
2958
|
+
} else {
|
|
2959
|
+
newState = [
|
|
2960
|
+
...newState.slice(0, listUpdate.previousIndex),
|
|
2961
|
+
...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1),
|
|
2962
|
+
liveNodeToJson(listUpdate.item),
|
|
2963
|
+
...newState.slice(listUpdate.index + 1)
|
|
2964
|
+
];
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
return newState;
|
|
2969
|
+
}
|
|
2970
|
+
case "LiveMap": {
|
|
2971
|
+
if (typeof state !== "object") {
|
|
2972
|
+
throw new Error("Internal: received update on LiveMap but state was not an object");
|
|
2973
|
+
}
|
|
2974
|
+
let newState = Object.assign({}, state);
|
|
2975
|
+
for (const key in update.updates) {
|
|
2976
|
+
if (((_c = update.updates[key]) == null ? void 0 : _c.type) === "update") {
|
|
2977
|
+
newState[key] = liveNodeToJson(update.node.get(key));
|
|
2978
|
+
} else if (((_d = update.updates[key]) == null ? void 0 : _d.type) === "delete") {
|
|
2979
|
+
delete newState[key];
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
return newState;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
if (Array.isArray(state)) {
|
|
2987
|
+
const newArray = [...state];
|
|
2988
|
+
newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
|
|
2989
|
+
return newArray;
|
|
2990
|
+
} else {
|
|
2991
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
2992
|
+
[pathItem]: patchImmutableNode(state[pathItem], path, update)
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
const internals = {
|
|
2998
|
+
liveObjectToJson,
|
|
2999
|
+
liveNodeToJson,
|
|
3000
|
+
patchLiveList,
|
|
3001
|
+
patchImmutableObject,
|
|
3002
|
+
patchLiveObject,
|
|
3003
|
+
patchLiveObjectKey
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3006
|
+
export { LiveList, LiveMap, LiveObject, createClient, internals };
|