@liveblocks/core 1.0.2 → 1.0.6-test2
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/dist/index.d.ts +13 -13
- package/dist/index.js +747 -421
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -72,10 +72,12 @@ function makeEventSource() {
|
|
|
72
72
|
_observers.clear();
|
|
73
73
|
}
|
|
74
74
|
return {
|
|
75
|
+
// Private/internal control over event emission
|
|
75
76
|
notify,
|
|
76
77
|
subscribe,
|
|
77
78
|
subscribeOnce,
|
|
78
79
|
clear,
|
|
80
|
+
// Publicly exposable subscription API
|
|
79
81
|
observable: {
|
|
80
82
|
subscribe,
|
|
81
83
|
subscribeOnce
|
|
@@ -113,7 +115,10 @@ if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
|
|
|
113
115
|
var onMessageFromPanel = eventSource.observable;
|
|
114
116
|
|
|
115
117
|
// src/devtools/index.ts
|
|
116
|
-
var VERSION = true ?
|
|
118
|
+
var VERSION = true ? (
|
|
119
|
+
/* istanbul ignore next */
|
|
120
|
+
"1.0.6-test2"
|
|
121
|
+
) : "dev";
|
|
117
122
|
var _devtoolsSetupHasRun = false;
|
|
118
123
|
function setupDevTools(getAllRooms) {
|
|
119
124
|
if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
|
|
@@ -153,9 +158,13 @@ function startSyncStream(room) {
|
|
|
153
158
|
stopSyncStream(room.id);
|
|
154
159
|
fullSync(room);
|
|
155
160
|
unsubsByRoomId.set(room.id, [
|
|
161
|
+
// When the connection status changes
|
|
156
162
|
room.events.connection.subscribe(() => partialSyncConnection(room)),
|
|
163
|
+
// When storage initializes, send the update
|
|
157
164
|
room.events.storageDidLoad.subscribeOnce(() => partialSyncStorage(room)),
|
|
165
|
+
// Any time storage updates, send the new storage root
|
|
158
166
|
room.events.storage.subscribe(() => partialSyncStorage(room)),
|
|
167
|
+
// Any time "me" or "others" updates, send the new values accordingly
|
|
159
168
|
room.events.me.subscribe(() => partialSyncMe(room)),
|
|
160
169
|
room.events.others.subscribe(() => partialSyncOthers(room))
|
|
161
170
|
]);
|
|
@@ -178,7 +187,7 @@ function partialSyncStorage(room) {
|
|
|
178
187
|
}
|
|
179
188
|
}
|
|
180
189
|
function partialSyncMe(room) {
|
|
181
|
-
const me = room.getSelf_forDevTools();
|
|
190
|
+
const me = room.__internal.getSelf_forDevTools();
|
|
182
191
|
if (me) {
|
|
183
192
|
sendToPanel({
|
|
184
193
|
msg: "room::sync::partial",
|
|
@@ -188,7 +197,7 @@ function partialSyncMe(room) {
|
|
|
188
197
|
}
|
|
189
198
|
}
|
|
190
199
|
function partialSyncOthers(room) {
|
|
191
|
-
const others = room.getOthers_forDevTools();
|
|
200
|
+
const others = room.__internal.getOthers_forDevTools();
|
|
192
201
|
if (others) {
|
|
193
202
|
sendToPanel({
|
|
194
203
|
msg: "room::sync::partial",
|
|
@@ -200,8 +209,8 @@ function partialSyncOthers(room) {
|
|
|
200
209
|
function fullSync(room) {
|
|
201
210
|
var _a;
|
|
202
211
|
const root = room.getStorageSnapshot();
|
|
203
|
-
const me = room.getSelf_forDevTools();
|
|
204
|
-
const others = room.getOthers_forDevTools();
|
|
212
|
+
const me = room.__internal.getSelf_forDevTools();
|
|
213
|
+
const others = room.__internal.getOthers_forDevTools();
|
|
205
214
|
sendToPanel({
|
|
206
215
|
msg: "room::sync::full",
|
|
207
216
|
roomId: room.id,
|
|
@@ -227,6 +236,8 @@ function linkDevTools(roomId, room) {
|
|
|
227
236
|
stopRoomChannelListener(roomId);
|
|
228
237
|
roomChannelListeners.set(
|
|
229
238
|
roomId,
|
|
239
|
+
// Returns the unsubscribe callback, that we store in the
|
|
240
|
+
// roomChannelListeners registry
|
|
230
241
|
onMessageFromPanel.subscribe((msg) => {
|
|
231
242
|
switch (msg.msg) {
|
|
232
243
|
case "room::subscribe": {
|
|
@@ -261,17 +272,23 @@ function unlinkDevTools(roomId) {
|
|
|
261
272
|
var badge = "background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;";
|
|
262
273
|
var bold = "font-weight:600";
|
|
263
274
|
function wrap(method) {
|
|
264
|
-
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
275
|
+
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
276
|
+
/* istanbul ignore next */
|
|
277
|
+
(message, ...args) => console[method]("%cLiveblocks", badge, message, ...args)
|
|
278
|
+
);
|
|
265
279
|
}
|
|
266
280
|
var warn = wrap("warn");
|
|
267
281
|
var error = wrap("error");
|
|
268
282
|
function wrapWithTitle(method) {
|
|
269
|
-
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
283
|
+
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
284
|
+
/* istanbul ignore next */
|
|
285
|
+
(title, message, ...args) => console[method](
|
|
286
|
+
`%cLiveblocks%c ${title}`,
|
|
287
|
+
badge,
|
|
288
|
+
bold,
|
|
289
|
+
message,
|
|
290
|
+
...args
|
|
291
|
+
)
|
|
275
292
|
);
|
|
276
293
|
}
|
|
277
294
|
var warnWithTitle = wrapWithTitle("warn");
|
|
@@ -358,8 +375,10 @@ function Orphaned(oldKey) {
|
|
|
358
375
|
}
|
|
359
376
|
var AbstractCrdt = class {
|
|
360
377
|
constructor() {
|
|
378
|
+
/** @internal */
|
|
361
379
|
this._parent = NoParent;
|
|
362
380
|
}
|
|
381
|
+
/** @internal */
|
|
363
382
|
_getParentKeyOrThrow() {
|
|
364
383
|
switch (this.parent.type) {
|
|
365
384
|
case "HasParent":
|
|
@@ -372,18 +391,22 @@ var AbstractCrdt = class {
|
|
|
372
391
|
return assertNever(this.parent, "Unknown state");
|
|
373
392
|
}
|
|
374
393
|
}
|
|
394
|
+
/** @internal */
|
|
375
395
|
get _pool() {
|
|
376
396
|
return this.__pool;
|
|
377
397
|
}
|
|
378
398
|
get roomId() {
|
|
379
399
|
return this.__pool ? this.__pool.roomId : null;
|
|
380
400
|
}
|
|
401
|
+
/** @internal */
|
|
381
402
|
get _id() {
|
|
382
403
|
return this.__id;
|
|
383
404
|
}
|
|
405
|
+
/** @internal */
|
|
384
406
|
get parent() {
|
|
385
407
|
return this._parent;
|
|
386
408
|
}
|
|
409
|
+
/** @internal */
|
|
387
410
|
get _parentNode() {
|
|
388
411
|
switch (this.parent.type) {
|
|
389
412
|
case "HasParent":
|
|
@@ -396,6 +419,7 @@ var AbstractCrdt = class {
|
|
|
396
419
|
return assertNever(this.parent, "Unknown state");
|
|
397
420
|
}
|
|
398
421
|
}
|
|
422
|
+
/** @internal */
|
|
399
423
|
get _parentKey() {
|
|
400
424
|
switch (this.parent.type) {
|
|
401
425
|
case "HasParent":
|
|
@@ -408,6 +432,7 @@ var AbstractCrdt = class {
|
|
|
408
432
|
return assertNever(this.parent, "Unknown state");
|
|
409
433
|
}
|
|
410
434
|
}
|
|
435
|
+
/** @internal */
|
|
411
436
|
_apply(op, _isLocal) {
|
|
412
437
|
switch (op.type) {
|
|
413
438
|
case 5 /* DELETE_CRDT */: {
|
|
@@ -419,6 +444,7 @@ var AbstractCrdt = class {
|
|
|
419
444
|
}
|
|
420
445
|
return { modified: false };
|
|
421
446
|
}
|
|
447
|
+
/** @internal */
|
|
422
448
|
_setParentLink(newParentNode, newParentKey) {
|
|
423
449
|
switch (this.parent.type) {
|
|
424
450
|
case "HasParent":
|
|
@@ -437,6 +463,7 @@ var AbstractCrdt = class {
|
|
|
437
463
|
return assertNever(this.parent, "Unknown state");
|
|
438
464
|
}
|
|
439
465
|
}
|
|
466
|
+
/** @internal */
|
|
440
467
|
_attach(id, pool) {
|
|
441
468
|
if (this.__id || this.__pool) {
|
|
442
469
|
throw new Error("Cannot attach node: already attached");
|
|
@@ -445,6 +472,7 @@ var AbstractCrdt = class {
|
|
|
445
472
|
this.__id = id;
|
|
446
473
|
this.__pool = pool;
|
|
447
474
|
}
|
|
475
|
+
/** @internal */
|
|
448
476
|
_detach() {
|
|
449
477
|
if (this.__pool && this.__id) {
|
|
450
478
|
this.__pool.deleteNode(this.__id);
|
|
@@ -467,6 +495,13 @@ var AbstractCrdt = class {
|
|
|
467
495
|
}
|
|
468
496
|
this.__pool = void 0;
|
|
469
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* @internal
|
|
500
|
+
*
|
|
501
|
+
* Clear the Immutable cache, so that the next call to `.toImmutable()` will
|
|
502
|
+
* recompute the equivalent Immutable value again. Call this after every
|
|
503
|
+
* mutation to the Live node.
|
|
504
|
+
*/
|
|
470
505
|
invalidate() {
|
|
471
506
|
if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
|
|
472
507
|
this._cachedImmutable = void 0;
|
|
@@ -476,6 +511,11 @@ var AbstractCrdt = class {
|
|
|
476
511
|
}
|
|
477
512
|
}
|
|
478
513
|
}
|
|
514
|
+
/**
|
|
515
|
+
* @internal
|
|
516
|
+
*
|
|
517
|
+
* Return an snapshot of this Live tree for use in DevTools.
|
|
518
|
+
*/
|
|
479
519
|
toTreeNode(key) {
|
|
480
520
|
if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
|
|
481
521
|
this._cachedTreeNodeKey = key;
|
|
@@ -483,6 +523,9 @@ var AbstractCrdt = class {
|
|
|
483
523
|
}
|
|
484
524
|
return this._cachedTreeNode;
|
|
485
525
|
}
|
|
526
|
+
/**
|
|
527
|
+
* Return an immutable snapshot of this Live node and its children.
|
|
528
|
+
*/
|
|
486
529
|
toImmutable() {
|
|
487
530
|
if (this._cachedImmutable === void 0) {
|
|
488
531
|
this._cachedImmutable = this._toImmutable();
|
|
@@ -679,11 +722,13 @@ var LiveRegister = class extends AbstractCrdt {
|
|
|
679
722
|
get data() {
|
|
680
723
|
return this._data;
|
|
681
724
|
}
|
|
725
|
+
/** @internal */
|
|
682
726
|
static _deserialize([id, item], _parentToChildren, pool) {
|
|
683
727
|
const register = new LiveRegister(item.data);
|
|
684
728
|
register._attach(id, pool);
|
|
685
729
|
return register;
|
|
686
730
|
}
|
|
731
|
+
/** @internal */
|
|
687
732
|
_toOps(parentId, parentKey, pool) {
|
|
688
733
|
if (this._id === void 0) {
|
|
689
734
|
throw new Error(
|
|
@@ -701,6 +746,7 @@ var LiveRegister = class extends AbstractCrdt {
|
|
|
701
746
|
}
|
|
702
747
|
];
|
|
703
748
|
}
|
|
749
|
+
/** @internal */
|
|
704
750
|
_serialize() {
|
|
705
751
|
if (this.parent.type !== "HasParent") {
|
|
706
752
|
throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
@@ -712,15 +758,19 @@ var LiveRegister = class extends AbstractCrdt {
|
|
|
712
758
|
data: this.data
|
|
713
759
|
};
|
|
714
760
|
}
|
|
761
|
+
/** @internal */
|
|
715
762
|
_attachChild(_op) {
|
|
716
763
|
throw new Error("Method not implemented.");
|
|
717
764
|
}
|
|
765
|
+
/** @internal */
|
|
718
766
|
_detachChild(_crdt) {
|
|
719
767
|
throw new Error("Method not implemented.");
|
|
720
768
|
}
|
|
769
|
+
/** @internal */
|
|
721
770
|
_apply(op, isLocal) {
|
|
722
771
|
return super._apply(op, isLocal);
|
|
723
772
|
}
|
|
773
|
+
/** @internal */
|
|
724
774
|
_toTreeNode(key) {
|
|
725
775
|
var _a;
|
|
726
776
|
return {
|
|
@@ -730,6 +780,7 @@ var LiveRegister = class extends AbstractCrdt {
|
|
|
730
780
|
payload: this._data
|
|
731
781
|
};
|
|
732
782
|
}
|
|
783
|
+
/** @internal */
|
|
733
784
|
_toImmutable() {
|
|
734
785
|
return this._data;
|
|
735
786
|
}
|
|
@@ -757,6 +808,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
757
808
|
position = newPosition;
|
|
758
809
|
}
|
|
759
810
|
}
|
|
811
|
+
/** @internal */
|
|
760
812
|
static _deserialize([id], parentToChildren, pool) {
|
|
761
813
|
const list = new LiveList();
|
|
762
814
|
list._attach(id, pool);
|
|
@@ -771,6 +823,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
771
823
|
}
|
|
772
824
|
return list;
|
|
773
825
|
}
|
|
826
|
+
/** @internal */
|
|
774
827
|
_toOps(parentId, parentKey, pool) {
|
|
775
828
|
if (this._id === void 0) {
|
|
776
829
|
throw new Error("Cannot serialize item is not attached");
|
|
@@ -789,31 +842,41 @@ var LiveList = class extends AbstractCrdt {
|
|
|
789
842
|
}
|
|
790
843
|
return ops;
|
|
791
844
|
}
|
|
845
|
+
/**
|
|
846
|
+
* @internal
|
|
847
|
+
*
|
|
848
|
+
* Adds a new item into the sorted list, in the correct position.
|
|
849
|
+
*/
|
|
792
850
|
_insertAndSort(item) {
|
|
793
851
|
this._items.push(item);
|
|
794
852
|
this._sortItems();
|
|
795
853
|
}
|
|
854
|
+
/** @internal */
|
|
796
855
|
_sortItems() {
|
|
797
856
|
this._items.sort(compareNodePosition);
|
|
798
857
|
this.invalidate();
|
|
799
858
|
}
|
|
859
|
+
/** @internal */
|
|
800
860
|
_indexOfPosition(position) {
|
|
801
861
|
return this._items.findIndex(
|
|
802
862
|
(item) => item._getParentKeyOrThrow() === position
|
|
803
863
|
);
|
|
804
864
|
}
|
|
865
|
+
/** @internal */
|
|
805
866
|
_attach(id, pool) {
|
|
806
867
|
super._attach(id, pool);
|
|
807
868
|
for (const item of this._items) {
|
|
808
869
|
item._attach(pool.generateId(), pool);
|
|
809
870
|
}
|
|
810
871
|
}
|
|
872
|
+
/** @internal */
|
|
811
873
|
_detach() {
|
|
812
874
|
super._detach();
|
|
813
875
|
for (const item of this._items) {
|
|
814
876
|
item._detach();
|
|
815
877
|
}
|
|
816
878
|
}
|
|
879
|
+
/** @internal */
|
|
817
880
|
_applySetRemote(op) {
|
|
818
881
|
if (this._pool === void 0) {
|
|
819
882
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -868,6 +931,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
868
931
|
};
|
|
869
932
|
}
|
|
870
933
|
}
|
|
934
|
+
/** @internal */
|
|
871
935
|
_applySetAck(op) {
|
|
872
936
|
if (this._pool === void 0) {
|
|
873
937
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -921,6 +985,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
921
985
|
const recreatedItemIndex = this._items.indexOf(orphan);
|
|
922
986
|
return {
|
|
923
987
|
modified: makeUpdate(this, [
|
|
988
|
+
// If there is an item at this position, update is a set, else it's an insert
|
|
924
989
|
indexOfItemWithSamePosition === -1 ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan),
|
|
925
990
|
...delta
|
|
926
991
|
]),
|
|
@@ -936,6 +1001,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
936
1001
|
);
|
|
937
1002
|
return {
|
|
938
1003
|
modified: makeUpdate(this, [
|
|
1004
|
+
// If there is an item at this position, update is a set, else it's an insert
|
|
939
1005
|
indexOfItemWithSamePosition === -1 ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem),
|
|
940
1006
|
...delta
|
|
941
1007
|
]),
|
|
@@ -944,6 +1010,10 @@ var LiveList = class extends AbstractCrdt {
|
|
|
944
1010
|
}
|
|
945
1011
|
}
|
|
946
1012
|
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Returns the update delta of the deletion or null
|
|
1015
|
+
* @internal
|
|
1016
|
+
*/
|
|
947
1017
|
_detachItemAssociatedToSetOperation(deletedId) {
|
|
948
1018
|
if (deletedId === void 0 || this._pool === void 0) {
|
|
949
1019
|
return null;
|
|
@@ -958,6 +1028,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
958
1028
|
}
|
|
959
1029
|
return result.modified.updates[0];
|
|
960
1030
|
}
|
|
1031
|
+
/** @internal */
|
|
961
1032
|
_applyRemoteInsert(op) {
|
|
962
1033
|
if (this._pool === void 0) {
|
|
963
1034
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -973,6 +1044,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
973
1044
|
reverse: []
|
|
974
1045
|
};
|
|
975
1046
|
}
|
|
1047
|
+
/** @internal */
|
|
976
1048
|
_applyInsertAck(op) {
|
|
977
1049
|
const existingItem = this._items.find((item) => item._id === op.id);
|
|
978
1050
|
const key = op.parentKey;
|
|
@@ -1023,6 +1095,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1023
1095
|
}
|
|
1024
1096
|
}
|
|
1025
1097
|
}
|
|
1098
|
+
/** @internal */
|
|
1026
1099
|
_applyInsertUndoRedo(op) {
|
|
1027
1100
|
var _a, _b, _c;
|
|
1028
1101
|
const { id, parentKey: key } = op;
|
|
@@ -1047,6 +1120,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1047
1120
|
reverse: [{ type: 5 /* DELETE_CRDT */, id }]
|
|
1048
1121
|
};
|
|
1049
1122
|
}
|
|
1123
|
+
/** @internal */
|
|
1050
1124
|
_applySetUndoRedo(op) {
|
|
1051
1125
|
var _a;
|
|
1052
1126
|
const { id, parentKey: key } = op;
|
|
@@ -1088,6 +1162,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1088
1162
|
};
|
|
1089
1163
|
}
|
|
1090
1164
|
}
|
|
1165
|
+
/** @internal */
|
|
1091
1166
|
_attachChild(op, source) {
|
|
1092
1167
|
if (this._pool === void 0) {
|
|
1093
1168
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -1115,6 +1190,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1115
1190
|
}
|
|
1116
1191
|
return result;
|
|
1117
1192
|
}
|
|
1193
|
+
/** @internal */
|
|
1118
1194
|
_detachChild(child) {
|
|
1119
1195
|
if (child) {
|
|
1120
1196
|
const parentKey = nn(child._parentKey);
|
|
@@ -1135,6 +1211,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1135
1211
|
}
|
|
1136
1212
|
return { modified: false };
|
|
1137
1213
|
}
|
|
1214
|
+
/** @internal */
|
|
1138
1215
|
_applySetChildKeyRemote(newKey, child) {
|
|
1139
1216
|
var _a;
|
|
1140
1217
|
if (this._implicitlyDeletedItems.has(child)) {
|
|
@@ -1191,6 +1268,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1191
1268
|
};
|
|
1192
1269
|
}
|
|
1193
1270
|
}
|
|
1271
|
+
/** @internal */
|
|
1194
1272
|
_applySetChildKeyAck(newKey, child) {
|
|
1195
1273
|
var _a, _b;
|
|
1196
1274
|
const previousKey = nn(child._parentKey);
|
|
@@ -1245,6 +1323,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1245
1323
|
}
|
|
1246
1324
|
}
|
|
1247
1325
|
}
|
|
1326
|
+
/** @internal */
|
|
1248
1327
|
_applySetChildKeyUndoRedo(newKey, child) {
|
|
1249
1328
|
var _a;
|
|
1250
1329
|
const previousKey = nn(child._parentKey);
|
|
@@ -1278,6 +1357,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1278
1357
|
]
|
|
1279
1358
|
};
|
|
1280
1359
|
}
|
|
1360
|
+
/** @internal */
|
|
1281
1361
|
_setChildKey(newKey, child, source) {
|
|
1282
1362
|
if (source === 1 /* REMOTE */) {
|
|
1283
1363
|
return this._applySetChildKeyRemote(newKey, child);
|
|
@@ -1287,9 +1367,11 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1287
1367
|
return this._applySetChildKeyUndoRedo(newKey, child);
|
|
1288
1368
|
}
|
|
1289
1369
|
}
|
|
1370
|
+
/** @internal */
|
|
1290
1371
|
_apply(op, isLocal) {
|
|
1291
1372
|
return super._apply(op, isLocal);
|
|
1292
1373
|
}
|
|
1374
|
+
/** @internal */
|
|
1293
1375
|
_serialize() {
|
|
1294
1376
|
if (this.parent.type !== "HasParent") {
|
|
1295
1377
|
throw new Error("Cannot serialize LiveList if parent is missing");
|
|
@@ -1300,14 +1382,26 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1300
1382
|
parentKey: this.parent.key
|
|
1301
1383
|
};
|
|
1302
1384
|
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Returns the number of elements.
|
|
1387
|
+
*/
|
|
1303
1388
|
get length() {
|
|
1304
1389
|
return this._items.length;
|
|
1305
1390
|
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Adds one element to the end of the LiveList.
|
|
1393
|
+
* @param element The element to add to the end of the LiveList.
|
|
1394
|
+
*/
|
|
1306
1395
|
push(element) {
|
|
1307
1396
|
var _a;
|
|
1308
1397
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
1309
1398
|
return this.insert(element, this.length);
|
|
1310
1399
|
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Inserts one element at a specified index.
|
|
1402
|
+
* @param element The element to insert.
|
|
1403
|
+
* @param index The index at which you want to insert the element.
|
|
1404
|
+
*/
|
|
1311
1405
|
insert(element, index) {
|
|
1312
1406
|
var _a;
|
|
1313
1407
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -1334,6 +1428,11 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1334
1428
|
);
|
|
1335
1429
|
}
|
|
1336
1430
|
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Move one element from one index to another.
|
|
1433
|
+
* @param index The index of the element to move
|
|
1434
|
+
* @param targetIndex The index where the element should be after moving.
|
|
1435
|
+
*/
|
|
1337
1436
|
move(index, targetIndex) {
|
|
1338
1437
|
var _a;
|
|
1339
1438
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -1389,6 +1488,10 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1389
1488
|
);
|
|
1390
1489
|
}
|
|
1391
1490
|
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Deletes an element at the specified index
|
|
1493
|
+
* @param index The index of the element to delete
|
|
1494
|
+
*/
|
|
1392
1495
|
delete(index) {
|
|
1393
1496
|
var _a;
|
|
1394
1497
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -1491,52 +1594,111 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1491
1594
|
this._pool.dispatch(ops, reverseOps, storageUpdates);
|
|
1492
1595
|
}
|
|
1493
1596
|
}
|
|
1597
|
+
/**
|
|
1598
|
+
* Returns an Array of all the elements in the LiveList.
|
|
1599
|
+
*/
|
|
1494
1600
|
toArray() {
|
|
1495
1601
|
return this._items.map(
|
|
1496
1602
|
(entry) => liveNodeToLson(entry)
|
|
1603
|
+
// ^^^^^^^^
|
|
1604
|
+
// FIXME! This isn't safe.
|
|
1497
1605
|
);
|
|
1498
1606
|
}
|
|
1607
|
+
/**
|
|
1608
|
+
* Tests whether all elements pass the test implemented by the provided function.
|
|
1609
|
+
* @param predicate Function to test for each element, taking two arguments (the element and its index).
|
|
1610
|
+
* @returns true if the predicate function returns a truthy value for every element. Otherwise, false.
|
|
1611
|
+
*/
|
|
1499
1612
|
every(predicate) {
|
|
1500
1613
|
return this.toArray().every(predicate);
|
|
1501
1614
|
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Creates an array with all elements that pass the test implemented by the provided function.
|
|
1617
|
+
* @param predicate Function to test each element of the LiveList. Return a value that coerces to true to keep the element, or to false otherwise.
|
|
1618
|
+
* @returns An array with the elements that pass the test.
|
|
1619
|
+
*/
|
|
1502
1620
|
filter(predicate) {
|
|
1503
1621
|
return this.toArray().filter(predicate);
|
|
1504
1622
|
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Returns the first element that satisfies the provided testing function.
|
|
1625
|
+
* @param predicate Function to execute on each value.
|
|
1626
|
+
* @returns The value of the first element in the LiveList that satisfies the provided testing function. Otherwise, undefined is returned.
|
|
1627
|
+
*/
|
|
1505
1628
|
find(predicate) {
|
|
1506
1629
|
return this.toArray().find(predicate);
|
|
1507
1630
|
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Returns the index of the first element in the LiveList that satisfies the provided testing function.
|
|
1633
|
+
* @param predicate Function to execute on each value until the function returns true, indicating that the satisfying element was found.
|
|
1634
|
+
* @returns The index of the first element in the LiveList that passes the test. Otherwise, -1.
|
|
1635
|
+
*/
|
|
1508
1636
|
findIndex(predicate) {
|
|
1509
1637
|
return this.toArray().findIndex(predicate);
|
|
1510
1638
|
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Executes a provided function once for each element.
|
|
1641
|
+
* @param callbackfn Function to execute on each element.
|
|
1642
|
+
*/
|
|
1511
1643
|
forEach(callbackfn) {
|
|
1512
1644
|
return this.toArray().forEach(callbackfn);
|
|
1513
1645
|
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Get the element at the specified index.
|
|
1648
|
+
* @param index The index on the element to get.
|
|
1649
|
+
* @returns The element at the specified index or undefined.
|
|
1650
|
+
*/
|
|
1514
1651
|
get(index) {
|
|
1515
1652
|
if (index < 0 || index >= this._items.length) {
|
|
1516
1653
|
return void 0;
|
|
1517
1654
|
}
|
|
1518
1655
|
return liveNodeToLson(this._items[index]);
|
|
1519
1656
|
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Returns the first index at which a given element can be found in the LiveList, or -1 if it is not present.
|
|
1659
|
+
* @param searchElement Element to locate.
|
|
1660
|
+
* @param fromIndex The index to start the search at.
|
|
1661
|
+
* @returns The first index of the element in the LiveList; -1 if not found.
|
|
1662
|
+
*/
|
|
1520
1663
|
indexOf(searchElement, fromIndex) {
|
|
1521
1664
|
return this.toArray().indexOf(searchElement, fromIndex);
|
|
1522
1665
|
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Returns the last index at which a given element can be found in the LiveList, or -1 if it is not present. The LiveLsit is searched backwards, starting at fromIndex.
|
|
1668
|
+
* @param searchElement Element to locate.
|
|
1669
|
+
* @param fromIndex The index at which to start searching backwards.
|
|
1670
|
+
* @returns
|
|
1671
|
+
*/
|
|
1523
1672
|
lastIndexOf(searchElement, fromIndex) {
|
|
1524
1673
|
return this.toArray().lastIndexOf(searchElement, fromIndex);
|
|
1525
1674
|
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Creates an array populated with the results of calling a provided function on every element.
|
|
1677
|
+
* @param callback Function that is called for every element.
|
|
1678
|
+
* @returns An array with each element being the result of the callback function.
|
|
1679
|
+
*/
|
|
1526
1680
|
map(callback) {
|
|
1527
1681
|
return this._items.map(
|
|
1528
1682
|
(entry, i) => callback(
|
|
1529
1683
|
liveNodeToLson(entry),
|
|
1684
|
+
// ^^^^^^^^
|
|
1685
|
+
// FIXME! This isn't safe.
|
|
1530
1686
|
i
|
|
1531
1687
|
)
|
|
1532
1688
|
);
|
|
1533
1689
|
}
|
|
1690
|
+
/**
|
|
1691
|
+
* Tests whether at least one element in the LiveList passes the test implemented by the provided function.
|
|
1692
|
+
* @param predicate Function to test for each element.
|
|
1693
|
+
* @returns true if the callback function returns a truthy value for at least one element. Otherwise, false.
|
|
1694
|
+
*/
|
|
1534
1695
|
some(predicate) {
|
|
1535
1696
|
return this.toArray().some(predicate);
|
|
1536
1697
|
}
|
|
1537
1698
|
[Symbol.iterator]() {
|
|
1538
1699
|
return new LiveListIterator(this._items);
|
|
1539
1700
|
}
|
|
1701
|
+
/** @internal */
|
|
1540
1702
|
_createAttachItemAndSort(op, key) {
|
|
1541
1703
|
const newItem = creationOpToLiveNode(op);
|
|
1542
1704
|
newItem._attach(op.id, nn(this._pool));
|
|
@@ -1545,6 +1707,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1545
1707
|
const newIndex = this._indexOfPosition(key);
|
|
1546
1708
|
return { newItem, newIndex };
|
|
1547
1709
|
}
|
|
1710
|
+
/** @internal */
|
|
1548
1711
|
_shiftItemPosition(index, key) {
|
|
1549
1712
|
var _a;
|
|
1550
1713
|
const shiftedPosition = makePosition(
|
|
@@ -1553,6 +1716,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1553
1716
|
);
|
|
1554
1717
|
this._items[index]._setParentLink(this, shiftedPosition);
|
|
1555
1718
|
}
|
|
1719
|
+
/** @internal */
|
|
1556
1720
|
_toTreeNode(key) {
|
|
1557
1721
|
var _a;
|
|
1558
1722
|
return {
|
|
@@ -1567,6 +1731,7 @@ var LiveList = class extends AbstractCrdt {
|
|
|
1567
1731
|
toImmutable() {
|
|
1568
1732
|
return super.toImmutable();
|
|
1569
1733
|
}
|
|
1734
|
+
/** @internal */
|
|
1570
1735
|
_toImmutable() {
|
|
1571
1736
|
const result = this._items.map((node) => node.toImmutable());
|
|
1572
1737
|
return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
|
|
@@ -1641,7 +1806,10 @@ function HACK_addIntentAndDeletedIdToOperation(ops, deletedId) {
|
|
|
1641
1806
|
}
|
|
1642
1807
|
|
|
1643
1808
|
// src/lib/freeze.ts
|
|
1644
|
-
var freeze = process.env.NODE_ENV === "production" ? (
|
|
1809
|
+
var freeze = process.env.NODE_ENV === "production" ? (
|
|
1810
|
+
/* istanbul ignore next */
|
|
1811
|
+
(x) => x
|
|
1812
|
+
) : Object.freeze;
|
|
1645
1813
|
|
|
1646
1814
|
// src/crdts/LiveMap.ts
|
|
1647
1815
|
var LiveMap = class extends AbstractCrdt {
|
|
@@ -1660,6 +1828,9 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1660
1828
|
this._map = /* @__PURE__ */ new Map();
|
|
1661
1829
|
}
|
|
1662
1830
|
}
|
|
1831
|
+
/**
|
|
1832
|
+
* @internal
|
|
1833
|
+
*/
|
|
1663
1834
|
_toOps(parentId, parentKey, pool) {
|
|
1664
1835
|
if (this._id === void 0) {
|
|
1665
1836
|
throw new Error("Cannot serialize item is not attached");
|
|
@@ -1678,6 +1849,9 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1678
1849
|
}
|
|
1679
1850
|
return ops;
|
|
1680
1851
|
}
|
|
1852
|
+
/**
|
|
1853
|
+
* @internal
|
|
1854
|
+
*/
|
|
1681
1855
|
static _deserialize([id, _item], parentToChildren, pool) {
|
|
1682
1856
|
const map = new LiveMap();
|
|
1683
1857
|
map._attach(id, pool);
|
|
@@ -1693,6 +1867,9 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1693
1867
|
}
|
|
1694
1868
|
return map;
|
|
1695
1869
|
}
|
|
1870
|
+
/**
|
|
1871
|
+
* @internal
|
|
1872
|
+
*/
|
|
1696
1873
|
_attach(id, pool) {
|
|
1697
1874
|
super._attach(id, pool);
|
|
1698
1875
|
for (const [_key, value] of this._map) {
|
|
@@ -1701,6 +1878,9 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1701
1878
|
}
|
|
1702
1879
|
}
|
|
1703
1880
|
}
|
|
1881
|
+
/**
|
|
1882
|
+
* @internal
|
|
1883
|
+
*/
|
|
1704
1884
|
_attachChild(op, source) {
|
|
1705
1885
|
if (this._pool === void 0) {
|
|
1706
1886
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -1744,12 +1924,18 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1744
1924
|
reverse
|
|
1745
1925
|
};
|
|
1746
1926
|
}
|
|
1927
|
+
/**
|
|
1928
|
+
* @internal
|
|
1929
|
+
*/
|
|
1747
1930
|
_detach() {
|
|
1748
1931
|
super._detach();
|
|
1749
1932
|
for (const item of this._map.values()) {
|
|
1750
1933
|
item._detach();
|
|
1751
1934
|
}
|
|
1752
1935
|
}
|
|
1936
|
+
/**
|
|
1937
|
+
* @internal
|
|
1938
|
+
*/
|
|
1753
1939
|
_detachChild(child) {
|
|
1754
1940
|
const id = nn(this._id);
|
|
1755
1941
|
const parentKey = nn(child._parentKey);
|
|
@@ -1768,6 +1954,9 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1768
1954
|
};
|
|
1769
1955
|
return { modified: storageUpdate, reverse };
|
|
1770
1956
|
}
|
|
1957
|
+
/**
|
|
1958
|
+
* @internal
|
|
1959
|
+
*/
|
|
1771
1960
|
_serialize() {
|
|
1772
1961
|
if (this.parent.type !== "HasParent") {
|
|
1773
1962
|
throw new Error("Cannot serialize LiveMap if parent is missing");
|
|
@@ -1778,6 +1967,11 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1778
1967
|
parentKey: this.parent.key
|
|
1779
1968
|
};
|
|
1780
1969
|
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Returns a specified element from the LiveMap.
|
|
1972
|
+
* @param key The key of the element to return.
|
|
1973
|
+
* @returns The element associated with the specified key, or undefined if the key can't be found in the LiveMap.
|
|
1974
|
+
*/
|
|
1781
1975
|
get(key) {
|
|
1782
1976
|
const value = this._map.get(key);
|
|
1783
1977
|
if (value === void 0) {
|
|
@@ -1785,6 +1979,11 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1785
1979
|
}
|
|
1786
1980
|
return liveNodeToLson(value);
|
|
1787
1981
|
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Adds or updates an element with a specified key and a value.
|
|
1984
|
+
* @param key The key of the element to add. Should be a string.
|
|
1985
|
+
* @param value The value of the element to add. Should be serializable to JSON.
|
|
1986
|
+
*/
|
|
1788
1987
|
set(key, value) {
|
|
1789
1988
|
var _a;
|
|
1790
1989
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -1814,12 +2013,24 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1814
2013
|
);
|
|
1815
2014
|
}
|
|
1816
2015
|
}
|
|
2016
|
+
/**
|
|
2017
|
+
* Returns the number of elements in the LiveMap.
|
|
2018
|
+
*/
|
|
1817
2019
|
get size() {
|
|
1818
2020
|
return this._map.size;
|
|
1819
2021
|
}
|
|
2022
|
+
/**
|
|
2023
|
+
* Returns a boolean indicating whether an element with the specified key exists or not.
|
|
2024
|
+
* @param key The key of the element to test for presence.
|
|
2025
|
+
*/
|
|
1820
2026
|
has(key) {
|
|
1821
2027
|
return this._map.has(key);
|
|
1822
2028
|
}
|
|
2029
|
+
/**
|
|
2030
|
+
* Removes the specified element by key.
|
|
2031
|
+
* @param key The key of the element to remove.
|
|
2032
|
+
* @returns true if an element existed and has been removed, or false if the element does not exist.
|
|
2033
|
+
*/
|
|
1823
2034
|
delete(key) {
|
|
1824
2035
|
var _a;
|
|
1825
2036
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -1852,6 +2063,9 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1852
2063
|
}
|
|
1853
2064
|
return true;
|
|
1854
2065
|
}
|
|
2066
|
+
/**
|
|
2067
|
+
* Returns a new Iterator object that contains the [key, value] pairs for each element.
|
|
2068
|
+
*/
|
|
1855
2069
|
entries() {
|
|
1856
2070
|
const innerIterator = this._map.entries();
|
|
1857
2071
|
return {
|
|
@@ -1875,12 +2089,21 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1875
2089
|
}
|
|
1876
2090
|
};
|
|
1877
2091
|
}
|
|
2092
|
+
/**
|
|
2093
|
+
* Same function object as the initial value of the entries method.
|
|
2094
|
+
*/
|
|
1878
2095
|
[Symbol.iterator]() {
|
|
1879
2096
|
return this.entries();
|
|
1880
2097
|
}
|
|
2098
|
+
/**
|
|
2099
|
+
* Returns a new Iterator object that contains the keys for each element.
|
|
2100
|
+
*/
|
|
1881
2101
|
keys() {
|
|
1882
2102
|
return this._map.keys();
|
|
1883
2103
|
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Returns a new Iterator object that contains the values for each element.
|
|
2106
|
+
*/
|
|
1884
2107
|
values() {
|
|
1885
2108
|
const innerIterator = this._map.values();
|
|
1886
2109
|
return {
|
|
@@ -1900,11 +2123,16 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1900
2123
|
}
|
|
1901
2124
|
};
|
|
1902
2125
|
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Executes a provided function once per each key/value pair in the Map object, in insertion order.
|
|
2128
|
+
* @param callback Function to execute for each entry in the map.
|
|
2129
|
+
*/
|
|
1903
2130
|
forEach(callback) {
|
|
1904
2131
|
for (const entry of this) {
|
|
1905
2132
|
callback(entry[1], entry[0], this);
|
|
1906
2133
|
}
|
|
1907
2134
|
}
|
|
2135
|
+
/** @internal */
|
|
1908
2136
|
_toTreeNode(key) {
|
|
1909
2137
|
var _a;
|
|
1910
2138
|
return {
|
|
@@ -1919,6 +2147,7 @@ var LiveMap = class extends AbstractCrdt {
|
|
|
1919
2147
|
toImmutable() {
|
|
1920
2148
|
return super.toImmutable();
|
|
1921
2149
|
}
|
|
2150
|
+
/** @internal */
|
|
1922
2151
|
_toImmutable() {
|
|
1923
2152
|
const result = /* @__PURE__ */ new Map();
|
|
1924
2153
|
for (const [key, value] of this._map) {
|
|
@@ -1943,6 +2172,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
1943
2172
|
}
|
|
1944
2173
|
this._map = new Map(Object.entries(obj));
|
|
1945
2174
|
}
|
|
2175
|
+
/** @internal */
|
|
1946
2176
|
_toOps(parentId, parentKey, pool) {
|
|
1947
2177
|
if (this._id === void 0) {
|
|
1948
2178
|
throw new Error("Cannot serialize item is not attached");
|
|
@@ -1956,7 +2186,10 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
1956
2186
|
parentId,
|
|
1957
2187
|
parentKey,
|
|
1958
2188
|
data: {}
|
|
1959
|
-
} :
|
|
2189
|
+
} : (
|
|
2190
|
+
// Root object
|
|
2191
|
+
{ type: 4 /* CREATE_OBJECT */, id: this._id, opId, data: {} }
|
|
2192
|
+
);
|
|
1960
2193
|
ops.push(op);
|
|
1961
2194
|
for (const [key, value] of this._map) {
|
|
1962
2195
|
if (isLiveNode(value)) {
|
|
@@ -1967,11 +2200,13 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
1967
2200
|
}
|
|
1968
2201
|
return ops;
|
|
1969
2202
|
}
|
|
2203
|
+
/** @internal */
|
|
1970
2204
|
static _deserialize([id, item], parentToChildren, pool) {
|
|
1971
2205
|
const liveObj = new LiveObject(item.data);
|
|
1972
2206
|
liveObj._attach(id, pool);
|
|
1973
2207
|
return this._deserializeChildren(liveObj, parentToChildren, pool);
|
|
1974
2208
|
}
|
|
2209
|
+
/** @internal */
|
|
1975
2210
|
static _deserializeChildren(liveObj, parentToChildren, pool) {
|
|
1976
2211
|
const children = parentToChildren.get(nn(liveObj._id));
|
|
1977
2212
|
if (children === void 0) {
|
|
@@ -1987,6 +2222,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
1987
2222
|
}
|
|
1988
2223
|
return liveObj;
|
|
1989
2224
|
}
|
|
2225
|
+
/** @internal */
|
|
1990
2226
|
_attach(id, pool) {
|
|
1991
2227
|
super._attach(id, pool);
|
|
1992
2228
|
for (const [_key, value] of this._map) {
|
|
@@ -1995,6 +2231,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
1995
2231
|
}
|
|
1996
2232
|
}
|
|
1997
2233
|
}
|
|
2234
|
+
/** @internal */
|
|
1998
2235
|
_attachChild(op, source) {
|
|
1999
2236
|
if (this._pool === void 0) {
|
|
2000
2237
|
throw new Error("Can't attach child if managed pool is not present");
|
|
@@ -2048,6 +2285,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2048
2285
|
}
|
|
2049
2286
|
};
|
|
2050
2287
|
}
|
|
2288
|
+
/** @internal */
|
|
2051
2289
|
_detachChild(child) {
|
|
2052
2290
|
if (child) {
|
|
2053
2291
|
const id = nn(this._id);
|
|
@@ -2071,6 +2309,9 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2071
2309
|
}
|
|
2072
2310
|
return { modified: false };
|
|
2073
2311
|
}
|
|
2312
|
+
/**
|
|
2313
|
+
* @internal
|
|
2314
|
+
*/
|
|
2074
2315
|
_detach() {
|
|
2075
2316
|
super._detach();
|
|
2076
2317
|
for (const value of this._map.values()) {
|
|
@@ -2079,6 +2320,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2079
2320
|
}
|
|
2080
2321
|
}
|
|
2081
2322
|
}
|
|
2323
|
+
/** @internal */
|
|
2082
2324
|
_apply(op, isLocal) {
|
|
2083
2325
|
if (op.type === 3 /* UPDATE_OBJECT */) {
|
|
2084
2326
|
return this._applyUpdate(op, isLocal);
|
|
@@ -2087,6 +2329,9 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2087
2329
|
}
|
|
2088
2330
|
return super._apply(op, isLocal);
|
|
2089
2331
|
}
|
|
2332
|
+
/**
|
|
2333
|
+
* @internal
|
|
2334
|
+
*/
|
|
2090
2335
|
_serialize() {
|
|
2091
2336
|
const data = {};
|
|
2092
2337
|
for (const [key, value] of this._map) {
|
|
@@ -2108,6 +2353,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2108
2353
|
};
|
|
2109
2354
|
}
|
|
2110
2355
|
}
|
|
2356
|
+
/** @internal */
|
|
2111
2357
|
_applyUpdate(op, isLocal) {
|
|
2112
2358
|
let isModified = false;
|
|
2113
2359
|
const id = nn(this._id);
|
|
@@ -2166,6 +2412,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2166
2412
|
reverse
|
|
2167
2413
|
} : { modified: false };
|
|
2168
2414
|
}
|
|
2415
|
+
/** @internal */
|
|
2169
2416
|
_applyDeleteObjectKey(op, isLocal) {
|
|
2170
2417
|
const key = op.key;
|
|
2171
2418
|
if (this._map.has(key) === false) {
|
|
@@ -2200,17 +2447,33 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2200
2447
|
reverse
|
|
2201
2448
|
};
|
|
2202
2449
|
}
|
|
2450
|
+
/**
|
|
2451
|
+
* Transform the LiveObject into a javascript object
|
|
2452
|
+
*/
|
|
2203
2453
|
toObject() {
|
|
2204
2454
|
return fromEntries(this._map);
|
|
2205
2455
|
}
|
|
2456
|
+
/**
|
|
2457
|
+
* Adds or updates a property with a specified key and a value.
|
|
2458
|
+
* @param key The key of the property to add
|
|
2459
|
+
* @param value The value of the property to add
|
|
2460
|
+
*/
|
|
2206
2461
|
set(key, value) {
|
|
2207
2462
|
var _a;
|
|
2208
2463
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
2209
2464
|
this.update({ [key]: value });
|
|
2210
2465
|
}
|
|
2466
|
+
/**
|
|
2467
|
+
* Returns a specified property from the LiveObject.
|
|
2468
|
+
* @param key The key of the property to get
|
|
2469
|
+
*/
|
|
2211
2470
|
get(key) {
|
|
2212
2471
|
return this._map.get(key);
|
|
2213
2472
|
}
|
|
2473
|
+
/**
|
|
2474
|
+
* Deletes a key from the LiveObject
|
|
2475
|
+
* @param key The key of the property to delete
|
|
2476
|
+
*/
|
|
2214
2477
|
delete(key) {
|
|
2215
2478
|
var _a;
|
|
2216
2479
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -2261,6 +2524,10 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2261
2524
|
storageUpdates
|
|
2262
2525
|
);
|
|
2263
2526
|
}
|
|
2527
|
+
/**
|
|
2528
|
+
* Adds or updates multiple properties at once with an object.
|
|
2529
|
+
* @param patch The object used to overrides properties
|
|
2530
|
+
*/
|
|
2264
2531
|
update(patch) {
|
|
2265
2532
|
var _a;
|
|
2266
2533
|
(_a = this._pool) == null ? void 0 : _a.assertStorageIsWritable();
|
|
@@ -2347,9 +2614,11 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2347
2614
|
toImmutable() {
|
|
2348
2615
|
return super.toImmutable();
|
|
2349
2616
|
}
|
|
2617
|
+
/** @internal */
|
|
2350
2618
|
toTreeNode(key) {
|
|
2351
2619
|
return super.toTreeNode(key);
|
|
2352
2620
|
}
|
|
2621
|
+
/** @internal */
|
|
2353
2622
|
_toTreeNode(key) {
|
|
2354
2623
|
var _a;
|
|
2355
2624
|
const nodeId = (_a = this._id) != null ? _a : nanoid();
|
|
@@ -2362,6 +2631,7 @@ var LiveObject = class extends AbstractCrdt {
|
|
|
2362
2631
|
)
|
|
2363
2632
|
};
|
|
2364
2633
|
}
|
|
2634
|
+
/** @internal */
|
|
2365
2635
|
_toImmutable() {
|
|
2366
2636
|
const result = {};
|
|
2367
2637
|
for (const [key, val] of this._map) {
|
|
@@ -2526,7 +2796,10 @@ function getTreesDiffOperations(currentItems, newItems) {
|
|
|
2526
2796
|
parentId: crdt.parentId,
|
|
2527
2797
|
parentKey: crdt.parentKey,
|
|
2528
2798
|
data: crdt.data
|
|
2529
|
-
} :
|
|
2799
|
+
} : (
|
|
2800
|
+
// Root object
|
|
2801
|
+
{ type: 4 /* CREATE_OBJECT */, id, data: crdt.data }
|
|
2802
|
+
)
|
|
2530
2803
|
);
|
|
2531
2804
|
break;
|
|
2532
2805
|
case 2 /* MAP */:
|
|
@@ -2567,7 +2840,7 @@ function mergeListStorageUpdates(first, second) {
|
|
|
2567
2840
|
});
|
|
2568
2841
|
}
|
|
2569
2842
|
function mergeStorageUpdates(first, second) {
|
|
2570
|
-
if (
|
|
2843
|
+
if (first === void 0) {
|
|
2571
2844
|
return second;
|
|
2572
2845
|
}
|
|
2573
2846
|
if (first.type === "LiveObject" && second.type === "LiveObject") {
|
|
@@ -2678,6 +2951,8 @@ function parseRoomAuthToken(tokenString) {
|
|
|
2678
2951
|
const _a = data, {
|
|
2679
2952
|
maxConnections: _legacyField
|
|
2680
2953
|
} = _a, token = __objRest(_a, [
|
|
2954
|
+
// If this legacy field is found on the token, pretend it wasn't there,
|
|
2955
|
+
// to make all internally used token payloads uniform
|
|
2681
2956
|
"maxConnections"
|
|
2682
2957
|
]);
|
|
2683
2958
|
return token;
|
|
@@ -2753,9 +3028,13 @@ var MeRef = class extends ImmutableRef {
|
|
|
2753
3028
|
super();
|
|
2754
3029
|
this._me = freeze(compactObject(initialPresence));
|
|
2755
3030
|
}
|
|
3031
|
+
/** @internal */
|
|
2756
3032
|
_toImmutable() {
|
|
2757
3033
|
return this._me;
|
|
2758
3034
|
}
|
|
3035
|
+
/**
|
|
3036
|
+
* Patches the current "me" instance.
|
|
3037
|
+
*/
|
|
2759
3038
|
patch(patch) {
|
|
2760
3039
|
const oldMe = this._me;
|
|
2761
3040
|
const newMe = merge(oldMe, patch);
|
|
@@ -2784,12 +3063,16 @@ function makeUser(conn, presence) {
|
|
|
2784
3063
|
return freeze(compactObject(__spreadProps(__spreadValues({}, conn), { presence })));
|
|
2785
3064
|
}
|
|
2786
3065
|
var OthersRef = class extends ImmutableRef {
|
|
3066
|
+
//
|
|
3067
|
+
// --------------------------------------------------------------
|
|
3068
|
+
//
|
|
2787
3069
|
constructor() {
|
|
2788
3070
|
super();
|
|
2789
3071
|
this._connections = {};
|
|
2790
3072
|
this._presences = {};
|
|
2791
3073
|
this._users = {};
|
|
2792
3074
|
}
|
|
3075
|
+
/** @internal */
|
|
2793
3076
|
_toImmutable() {
|
|
2794
3077
|
const users = compact(
|
|
2795
3078
|
Object.keys(this._presences).map(
|
|
@@ -2804,6 +3087,7 @@ var OthersRef = class extends ImmutableRef {
|
|
|
2804
3087
|
this._users = {};
|
|
2805
3088
|
this.invalidate();
|
|
2806
3089
|
}
|
|
3090
|
+
/** @internal */
|
|
2807
3091
|
_getUser(connectionId) {
|
|
2808
3092
|
const conn = this._connections[connectionId];
|
|
2809
3093
|
const presence = this._presences[connectionId];
|
|
@@ -2824,12 +3108,17 @@ var OthersRef = class extends ImmutableRef {
|
|
|
2824
3108
|
}
|
|
2825
3109
|
return void 0;
|
|
2826
3110
|
}
|
|
3111
|
+
/** @internal */
|
|
2827
3112
|
_invalidateUser(connectionId) {
|
|
2828
3113
|
if (this._users[connectionId] !== void 0) {
|
|
2829
3114
|
delete this._users[connectionId];
|
|
2830
3115
|
}
|
|
2831
3116
|
this.invalidate();
|
|
2832
3117
|
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Records a known connection. This records the connection ID and the
|
|
3120
|
+
* associated metadata.
|
|
3121
|
+
*/
|
|
2833
3122
|
setConnection(connectionId, metaUserId, metaUserInfo, metaIsReadonly) {
|
|
2834
3123
|
this._connections[connectionId] = freeze({
|
|
2835
3124
|
connectionId,
|
|
@@ -2841,17 +3130,30 @@ var OthersRef = class extends ImmutableRef {
|
|
|
2841
3130
|
this._invalidateUser(connectionId);
|
|
2842
3131
|
}
|
|
2843
3132
|
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Removes a known connectionId. Removes both the connection's metadata and
|
|
3135
|
+
* the presence information.
|
|
3136
|
+
*/
|
|
2844
3137
|
removeConnection(connectionId) {
|
|
2845
3138
|
delete this._connections[connectionId];
|
|
2846
3139
|
delete this._presences[connectionId];
|
|
2847
3140
|
this._invalidateUser(connectionId);
|
|
2848
3141
|
}
|
|
3142
|
+
/**
|
|
3143
|
+
* Stores a new user from a full presence update. If the user already exists,
|
|
3144
|
+
* its known presence data is overwritten.
|
|
3145
|
+
*/
|
|
2849
3146
|
setOther(connectionId, presence) {
|
|
2850
3147
|
this._presences[connectionId] = freeze(compactObject(presence));
|
|
2851
3148
|
if (this._connections[connectionId] !== void 0) {
|
|
2852
3149
|
this._invalidateUser(connectionId);
|
|
2853
3150
|
}
|
|
2854
3151
|
}
|
|
3152
|
+
/**
|
|
3153
|
+
* Patches the presence data for an existing "other". If we don't know the
|
|
3154
|
+
* initial presence data for this user yet, discard this patch and await the
|
|
3155
|
+
* full .setOther() call first.
|
|
3156
|
+
*/
|
|
2855
3157
|
patchOther(connectionId, patch) {
|
|
2856
3158
|
const oldPresence = this._presences[connectionId];
|
|
2857
3159
|
if (oldPresence === void 0) {
|
|
@@ -2871,6 +3173,7 @@ var ValueRef = class extends ImmutableRef {
|
|
|
2871
3173
|
super();
|
|
2872
3174
|
this._value = freeze(initialValue);
|
|
2873
3175
|
}
|
|
3176
|
+
/** @internal */
|
|
2874
3177
|
_toImmutable() {
|
|
2875
3178
|
return this._value;
|
|
2876
3179
|
}
|
|
@@ -2890,6 +3193,7 @@ var DerivedRef = class extends ImmutableRef {
|
|
|
2890
3193
|
});
|
|
2891
3194
|
this._transform = transformFn;
|
|
2892
3195
|
}
|
|
3196
|
+
/** @internal */
|
|
2893
3197
|
_toImmutable() {
|
|
2894
3198
|
return this._transform(
|
|
2895
3199
|
...this._refs.map((ref) => ref.current)
|
|
@@ -2911,9 +3215,6 @@ var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
|
|
|
2911
3215
|
})(WebsocketCloseCodes || {});
|
|
2912
3216
|
|
|
2913
3217
|
// src/room.ts
|
|
2914
|
-
function isRoomEventName(value) {
|
|
2915
|
-
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "connection" || value === "history" || value === "storage-status";
|
|
2916
|
-
}
|
|
2917
3218
|
var BACKOFF_RETRY_DELAYS = [250, 500, 1e3, 2e3, 4e3, 8e3, 1e4];
|
|
2918
3219
|
var BACKOFF_RETRY_DELAYS_SLOW = [2e3, 3e4, 6e4, 3e5];
|
|
2919
3220
|
var HEARTBEAT_INTERVAL = 3e4;
|
|
@@ -2926,7 +3227,7 @@ function log(..._params) {
|
|
|
2926
3227
|
return;
|
|
2927
3228
|
}
|
|
2928
3229
|
function isConnectionSelfAware(connection) {
|
|
2929
|
-
return connection.
|
|
3230
|
+
return connection.status === "open" || connection.status === "connecting";
|
|
2930
3231
|
}
|
|
2931
3232
|
function userToTreeNode(key, user) {
|
|
2932
3233
|
return {
|
|
@@ -2936,25 +3237,68 @@ function userToTreeNode(key, user) {
|
|
|
2936
3237
|
payload: user
|
|
2937
3238
|
};
|
|
2938
3239
|
}
|
|
2939
|
-
function makeStateMachine(
|
|
3240
|
+
function makeStateMachine(config, initialPresence, initialStorage) {
|
|
2940
3241
|
var _a;
|
|
3242
|
+
const context = {
|
|
3243
|
+
token: null,
|
|
3244
|
+
lastConnectionId: null,
|
|
3245
|
+
socket: null,
|
|
3246
|
+
numberOfRetry: 0,
|
|
3247
|
+
lastFlushTime: 0,
|
|
3248
|
+
timeoutHandles: {
|
|
3249
|
+
flush: void 0,
|
|
3250
|
+
reconnect: void 0,
|
|
3251
|
+
pongTimeout: void 0
|
|
3252
|
+
},
|
|
3253
|
+
buffer: {
|
|
3254
|
+
me: (
|
|
3255
|
+
// Queue up the initial presence message as a Full Presence™ update
|
|
3256
|
+
{
|
|
3257
|
+
type: "full",
|
|
3258
|
+
data: initialPresence
|
|
3259
|
+
}
|
|
3260
|
+
),
|
|
3261
|
+
messages: [],
|
|
3262
|
+
storageOperations: []
|
|
3263
|
+
},
|
|
3264
|
+
intervalHandles: {
|
|
3265
|
+
heartbeat: void 0
|
|
3266
|
+
},
|
|
3267
|
+
connection: new ValueRef({ status: "closed" }),
|
|
3268
|
+
me: new MeRef(initialPresence),
|
|
3269
|
+
others: new OthersRef(),
|
|
3270
|
+
initialStorage,
|
|
3271
|
+
idFactory: null,
|
|
3272
|
+
// Storage
|
|
3273
|
+
clock: 0,
|
|
3274
|
+
opClock: 0,
|
|
3275
|
+
nodes: /* @__PURE__ */ new Map(),
|
|
3276
|
+
root: void 0,
|
|
3277
|
+
undoStack: [],
|
|
3278
|
+
redoStack: [],
|
|
3279
|
+
pausedHistory: null,
|
|
3280
|
+
activeBatch: null,
|
|
3281
|
+
unacknowledgedOps: /* @__PURE__ */ new Map(),
|
|
3282
|
+
// Debug
|
|
3283
|
+
opStackTraces: process.env.NODE_ENV !== "production" ? /* @__PURE__ */ new Map() : void 0
|
|
3284
|
+
};
|
|
2941
3285
|
const doNotBatchUpdates = (cb) => cb();
|
|
2942
3286
|
const batchUpdates = (_a = config.unstable_batchedUpdates) != null ? _a : doNotBatchUpdates;
|
|
2943
3287
|
const pool = {
|
|
2944
3288
|
roomId: config.roomId,
|
|
2945
|
-
getNode: (id) =>
|
|
2946
|
-
addNode: (id, node) => void
|
|
2947
|
-
deleteNode: (id) => void
|
|
2948
|
-
generateId: () => `${getConnectionId()}:${
|
|
2949
|
-
generateOpId: () => `${getConnectionId()}:${
|
|
3289
|
+
getNode: (id) => context.nodes.get(id),
|
|
3290
|
+
addNode: (id, node) => void context.nodes.set(id, node),
|
|
3291
|
+
deleteNode: (id) => void context.nodes.delete(id),
|
|
3292
|
+
generateId: () => `${getConnectionId()}:${context.clock++}`,
|
|
3293
|
+
generateOpId: () => `${getConnectionId()}:${context.opClock++}`,
|
|
2950
3294
|
dispatch(ops, reverse, storageUpdates) {
|
|
2951
|
-
const activeBatch =
|
|
3295
|
+
const activeBatch = context.activeBatch;
|
|
2952
3296
|
if (process.env.NODE_ENV !== "production") {
|
|
2953
3297
|
const stackTrace = captureStackTrace("Storage mutation", this.dispatch);
|
|
2954
3298
|
if (stackTrace) {
|
|
2955
3299
|
ops.forEach((op) => {
|
|
2956
3300
|
if (op.opId) {
|
|
2957
|
-
nn(
|
|
3301
|
+
nn(context.opStackTraces).set(op.opId, stackTrace);
|
|
2958
3302
|
}
|
|
2959
3303
|
});
|
|
2960
3304
|
}
|
|
@@ -2974,14 +3318,14 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
2974
3318
|
} else {
|
|
2975
3319
|
batchUpdates(() => {
|
|
2976
3320
|
addToUndoStack(reverse, doNotBatchUpdates);
|
|
2977
|
-
|
|
3321
|
+
context.redoStack = [];
|
|
2978
3322
|
dispatchOps(ops);
|
|
2979
3323
|
notify({ storageUpdates }, doNotBatchUpdates);
|
|
2980
3324
|
});
|
|
2981
3325
|
}
|
|
2982
3326
|
},
|
|
2983
3327
|
assertStorageIsWritable: () => {
|
|
2984
|
-
if (isConnectionSelfAware(
|
|
3328
|
+
if (isConnectionSelfAware(context.connection.current) && context.connection.current.isReadOnly) {
|
|
2985
3329
|
throw new Error(
|
|
2986
3330
|
"Cannot write to storage with a read only user, please ensure the user has write permissions"
|
|
2987
3331
|
);
|
|
@@ -2999,23 +3343,22 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
2999
3343
|
storageDidLoad: makeEventSource(),
|
|
3000
3344
|
storageStatus: makeEventSource()
|
|
3001
3345
|
};
|
|
3002
|
-
const effects = mockedEffects || {
|
|
3346
|
+
const effects = config.mockedEffects || {
|
|
3003
3347
|
authenticate(auth, createWebSocket) {
|
|
3004
|
-
const
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
authenticationSuccess(parsedToken, socket);
|
|
3348
|
+
const prevToken = context.token;
|
|
3349
|
+
if (prevToken !== null && !isTokenExpired(prevToken.parsed)) {
|
|
3350
|
+
const socket = createWebSocket(prevToken.raw);
|
|
3351
|
+
authenticationSuccess(prevToken.parsed, socket);
|
|
3009
3352
|
return void 0;
|
|
3010
3353
|
} else {
|
|
3011
3354
|
return auth(config.roomId).then(({ token }) => {
|
|
3012
|
-
if (
|
|
3355
|
+
if (context.connection.current.status !== "authenticating") {
|
|
3013
3356
|
return;
|
|
3014
3357
|
}
|
|
3015
|
-
const
|
|
3358
|
+
const parsedToken = parseRoomAuthToken(token);
|
|
3016
3359
|
const socket = createWebSocket(token);
|
|
3017
|
-
authenticationSuccess(
|
|
3018
|
-
|
|
3360
|
+
authenticationSuccess(parsedToken, socket);
|
|
3361
|
+
context.token = { raw: token, parsed: parsedToken };
|
|
3019
3362
|
}).catch(
|
|
3020
3363
|
(er) => authenticationFailure(
|
|
3021
3364
|
er instanceof Error ? er : new Error(String(er))
|
|
@@ -3024,10 +3367,10 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3024
3367
|
}
|
|
3025
3368
|
},
|
|
3026
3369
|
send(messageOrMessages) {
|
|
3027
|
-
if (
|
|
3370
|
+
if (context.socket === null) {
|
|
3028
3371
|
throw new Error("Can't send message if socket is null");
|
|
3029
3372
|
}
|
|
3030
|
-
|
|
3373
|
+
context.socket.send(JSON.stringify(messageOrMessages));
|
|
3031
3374
|
},
|
|
3032
3375
|
delayFlush(delay) {
|
|
3033
3376
|
return setTimeout(tryFlushing, delay);
|
|
@@ -3043,8 +3386,8 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3043
3386
|
}
|
|
3044
3387
|
};
|
|
3045
3388
|
const self = new DerivedRef(
|
|
3046
|
-
|
|
3047
|
-
|
|
3389
|
+
context.connection,
|
|
3390
|
+
context.me,
|
|
3048
3391
|
(conn, me) => isConnectionSelfAware(conn) ? {
|
|
3049
3392
|
connectionId: conn.id,
|
|
3050
3393
|
id: conn.userId,
|
|
@@ -3061,14 +3404,14 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3061
3404
|
if (message.items.length === 0) {
|
|
3062
3405
|
throw new Error("Internal error: cannot load storage without items");
|
|
3063
3406
|
}
|
|
3064
|
-
if (
|
|
3407
|
+
if (context.root) {
|
|
3065
3408
|
updateRoot(message.items, batchedUpdatesWrapper);
|
|
3066
3409
|
} else {
|
|
3067
|
-
|
|
3410
|
+
context.root = load(message.items);
|
|
3068
3411
|
}
|
|
3069
|
-
for (const key in
|
|
3070
|
-
if (
|
|
3071
|
-
|
|
3412
|
+
for (const key in context.initialStorage) {
|
|
3413
|
+
if (context.root.get(key) === void 0) {
|
|
3414
|
+
context.root.set(key, context.initialStorage[key]);
|
|
3072
3415
|
}
|
|
3073
3416
|
}
|
|
3074
3417
|
}
|
|
@@ -3094,11 +3437,11 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3094
3437
|
return [root, parentToChildren];
|
|
3095
3438
|
}
|
|
3096
3439
|
function updateRoot(items, batchedUpdatesWrapper) {
|
|
3097
|
-
if (!
|
|
3440
|
+
if (!context.root) {
|
|
3098
3441
|
return;
|
|
3099
3442
|
}
|
|
3100
3443
|
const currentItems = /* @__PURE__ */ new Map();
|
|
3101
|
-
|
|
3444
|
+
context.nodes.forEach((node, id) => {
|
|
3102
3445
|
currentItems.set(id, node._serialize());
|
|
3103
3446
|
});
|
|
3104
3447
|
const ops = getTreesDiffOperations(currentItems, new Map(items));
|
|
@@ -3110,15 +3453,15 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3110
3453
|
return LiveObject._deserialize(root, parentToChildren, pool);
|
|
3111
3454
|
}
|
|
3112
3455
|
function _addToRealUndoStack(historyOps, batchedUpdatesWrapper) {
|
|
3113
|
-
if (
|
|
3114
|
-
|
|
3456
|
+
if (context.undoStack.length >= 50) {
|
|
3457
|
+
context.undoStack.shift();
|
|
3115
3458
|
}
|
|
3116
|
-
|
|
3459
|
+
context.undoStack.push(historyOps);
|
|
3117
3460
|
onHistoryChange(batchedUpdatesWrapper);
|
|
3118
3461
|
}
|
|
3119
3462
|
function addToUndoStack(historyOps, batchedUpdatesWrapper) {
|
|
3120
|
-
if (
|
|
3121
|
-
|
|
3463
|
+
if (context.pausedHistory !== null) {
|
|
3464
|
+
context.pausedHistory.unshift(...historyOps);
|
|
3122
3465
|
} else {
|
|
3123
3466
|
_addToRealUndoStack(historyOps, batchedUpdatesWrapper);
|
|
3124
3467
|
}
|
|
@@ -3130,13 +3473,13 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3130
3473
|
}, batchedUpdatesWrapper) {
|
|
3131
3474
|
batchedUpdatesWrapper(() => {
|
|
3132
3475
|
if (otherEvents.length > 0) {
|
|
3133
|
-
const others =
|
|
3476
|
+
const others = context.others.current;
|
|
3134
3477
|
for (const event of otherEvents) {
|
|
3135
3478
|
eventHub.others.notify({ others, event });
|
|
3136
3479
|
}
|
|
3137
3480
|
}
|
|
3138
3481
|
if (presence) {
|
|
3139
|
-
eventHub.me.notify(
|
|
3482
|
+
eventHub.me.notify(context.me.current);
|
|
3140
3483
|
}
|
|
3141
3484
|
if (storageUpdates.size > 0) {
|
|
3142
3485
|
const updates = Array.from(storageUpdates.values());
|
|
@@ -3145,11 +3488,11 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3145
3488
|
});
|
|
3146
3489
|
}
|
|
3147
3490
|
function getConnectionId() {
|
|
3148
|
-
const conn =
|
|
3491
|
+
const conn = context.connection.current;
|
|
3149
3492
|
if (isConnectionSelfAware(conn)) {
|
|
3150
3493
|
return conn.id;
|
|
3151
|
-
} else if (
|
|
3152
|
-
return
|
|
3494
|
+
} else if (context.lastConnectionId !== null) {
|
|
3495
|
+
return context.lastConnectionId;
|
|
3153
3496
|
}
|
|
3154
3497
|
throw new Error(
|
|
3155
3498
|
"Internal. Tried to get connection id but connection was never open"
|
|
@@ -3176,14 +3519,14 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3176
3519
|
data: {}
|
|
3177
3520
|
};
|
|
3178
3521
|
for (const key in op.data) {
|
|
3179
|
-
reverse.data[key] =
|
|
3522
|
+
reverse.data[key] = context.me.current[key];
|
|
3180
3523
|
}
|
|
3181
|
-
|
|
3182
|
-
if (
|
|
3183
|
-
|
|
3524
|
+
context.me.patch(op.data);
|
|
3525
|
+
if (context.buffer.me === null) {
|
|
3526
|
+
context.buffer.me = { type: "partial", data: op.data };
|
|
3184
3527
|
} else {
|
|
3185
3528
|
for (const key in op.data) {
|
|
3186
|
-
|
|
3529
|
+
context.buffer.me.data[key] = op.data[key];
|
|
3187
3530
|
}
|
|
3188
3531
|
}
|
|
3189
3532
|
output.reverse.unshift(reverse);
|
|
@@ -3195,9 +3538,9 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3195
3538
|
} else {
|
|
3196
3539
|
const opId = nn(op.opId);
|
|
3197
3540
|
if (process.env.NODE_ENV !== "production") {
|
|
3198
|
-
nn(
|
|
3541
|
+
nn(context.opStackTraces).delete(opId);
|
|
3199
3542
|
}
|
|
3200
|
-
const deleted =
|
|
3543
|
+
const deleted = context.unacknowledgedOps.delete(opId);
|
|
3201
3544
|
source = deleted ? 2 /* ACK */ : 1 /* REMOTE */;
|
|
3202
3545
|
}
|
|
3203
3546
|
const applyOpResult = applyOp(op, source);
|
|
@@ -3207,9 +3550,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3207
3550
|
output.storageUpdates.set(
|
|
3208
3551
|
nn(applyOpResult.modified.node._id),
|
|
3209
3552
|
mergeStorageUpdates(
|
|
3210
|
-
output.storageUpdates.get(
|
|
3211
|
-
nn(applyOpResult.modified.node._id)
|
|
3212
|
-
),
|
|
3553
|
+
output.storageUpdates.get(nn(applyOpResult.modified.node._id)),
|
|
3213
3554
|
applyOpResult.modified
|
|
3214
3555
|
)
|
|
3215
3556
|
);
|
|
@@ -3239,14 +3580,14 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3239
3580
|
case 6 /* DELETE_OBJECT_KEY */:
|
|
3240
3581
|
case 3 /* UPDATE_OBJECT */:
|
|
3241
3582
|
case 5 /* DELETE_CRDT */: {
|
|
3242
|
-
const node =
|
|
3583
|
+
const node = context.nodes.get(op.id);
|
|
3243
3584
|
if (node === void 0) {
|
|
3244
3585
|
return { modified: false };
|
|
3245
3586
|
}
|
|
3246
3587
|
return node._apply(op, source === 0 /* UNDOREDO_RECONNECT */);
|
|
3247
3588
|
}
|
|
3248
3589
|
case 1 /* SET_PARENT_KEY */: {
|
|
3249
|
-
const node =
|
|
3590
|
+
const node = context.nodes.get(op.id);
|
|
3250
3591
|
if (node === void 0) {
|
|
3251
3592
|
return { modified: false };
|
|
3252
3593
|
}
|
|
@@ -3262,7 +3603,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3262
3603
|
if (op.parentId === void 0) {
|
|
3263
3604
|
return { modified: false };
|
|
3264
3605
|
}
|
|
3265
|
-
const parentNode =
|
|
3606
|
+
const parentNode = context.nodes.get(op.parentId);
|
|
3266
3607
|
if (parentNode === void 0) {
|
|
3267
3608
|
return { modified: false };
|
|
3268
3609
|
}
|
|
@@ -3270,107 +3611,26 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3270
3611
|
}
|
|
3271
3612
|
}
|
|
3272
3613
|
}
|
|
3273
|
-
function subscribeToLiveStructureDeeply(node, callback) {
|
|
3274
|
-
return eventHub.storage.subscribe((updates) => {
|
|
3275
|
-
const relatedUpdates = updates.filter(
|
|
3276
|
-
(update) => isSameNodeOrChildOf(update.node, node)
|
|
3277
|
-
);
|
|
3278
|
-
if (relatedUpdates.length > 0) {
|
|
3279
|
-
callback(relatedUpdates);
|
|
3280
|
-
}
|
|
3281
|
-
});
|
|
3282
|
-
}
|
|
3283
|
-
function subscribeToLiveStructureShallowly(node, callback) {
|
|
3284
|
-
return eventHub.storage.subscribe((updates) => {
|
|
3285
|
-
for (const update of updates) {
|
|
3286
|
-
if (update.node._id === node._id) {
|
|
3287
|
-
callback(update.node);
|
|
3288
|
-
}
|
|
3289
|
-
}
|
|
3290
|
-
});
|
|
3291
|
-
}
|
|
3292
|
-
function subscribe(first, second, options) {
|
|
3293
|
-
if (typeof first === "string" && isRoomEventName(first)) {
|
|
3294
|
-
if (typeof second !== "function") {
|
|
3295
|
-
throw new Error("Second argument must be a callback function");
|
|
3296
|
-
}
|
|
3297
|
-
const callback = second;
|
|
3298
|
-
switch (first) {
|
|
3299
|
-
case "event":
|
|
3300
|
-
return eventHub.customEvent.subscribe(
|
|
3301
|
-
callback
|
|
3302
|
-
);
|
|
3303
|
-
case "my-presence":
|
|
3304
|
-
return eventHub.me.subscribe(callback);
|
|
3305
|
-
case "others": {
|
|
3306
|
-
const cb = callback;
|
|
3307
|
-
return eventHub.others.subscribe(
|
|
3308
|
-
({ others, event }) => cb(others, event)
|
|
3309
|
-
);
|
|
3310
|
-
}
|
|
3311
|
-
case "error":
|
|
3312
|
-
return eventHub.error.subscribe(callback);
|
|
3313
|
-
case "connection":
|
|
3314
|
-
return eventHub.connection.subscribe(
|
|
3315
|
-
callback
|
|
3316
|
-
);
|
|
3317
|
-
case "storage":
|
|
3318
|
-
return eventHub.storage.subscribe(
|
|
3319
|
-
callback
|
|
3320
|
-
);
|
|
3321
|
-
case "history":
|
|
3322
|
-
return eventHub.history.subscribe(callback);
|
|
3323
|
-
case "storage-status":
|
|
3324
|
-
return eventHub.storageStatus.subscribe(
|
|
3325
|
-
callback
|
|
3326
|
-
);
|
|
3327
|
-
default:
|
|
3328
|
-
return assertNever(first, "Unknown event");
|
|
3329
|
-
}
|
|
3330
|
-
}
|
|
3331
|
-
if (second === void 0 || typeof first === "function") {
|
|
3332
|
-
if (typeof first === "function") {
|
|
3333
|
-
const storageCallback = first;
|
|
3334
|
-
return eventHub.storage.subscribe(storageCallback);
|
|
3335
|
-
} else {
|
|
3336
|
-
throw new Error("Please specify a listener callback");
|
|
3337
|
-
}
|
|
3338
|
-
}
|
|
3339
|
-
if (isLiveNode(first)) {
|
|
3340
|
-
const node = first;
|
|
3341
|
-
if (options == null ? void 0 : options.isDeep) {
|
|
3342
|
-
const storageCallback = second;
|
|
3343
|
-
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
3344
|
-
} else {
|
|
3345
|
-
const nodeCallback = second;
|
|
3346
|
-
return subscribeToLiveStructureShallowly(node, nodeCallback);
|
|
3347
|
-
}
|
|
3348
|
-
}
|
|
3349
|
-
throw new Error(`"${first}" is not a valid event name`);
|
|
3350
|
-
}
|
|
3351
|
-
function getConnectionState() {
|
|
3352
|
-
return state.connection.current.state;
|
|
3353
|
-
}
|
|
3354
3614
|
function connect() {
|
|
3355
|
-
var _a2, _b
|
|
3356
|
-
if (
|
|
3615
|
+
var _a2, _b;
|
|
3616
|
+
if (context.connection.current.status !== "closed" && context.connection.current.status !== "unavailable") {
|
|
3357
3617
|
return;
|
|
3358
3618
|
}
|
|
3359
3619
|
const auth = prepareAuthEndpoint(
|
|
3360
3620
|
config.authentication,
|
|
3361
|
-
(
|
|
3621
|
+
(_a2 = config.polyfills) == null ? void 0 : _a2.fetch
|
|
3362
3622
|
);
|
|
3363
3623
|
const createWebSocket = prepareCreateWebSocket(
|
|
3364
3624
|
config.liveblocksServer,
|
|
3365
|
-
(
|
|
3625
|
+
(_b = config.polyfills) == null ? void 0 : _b.WebSocket
|
|
3366
3626
|
);
|
|
3367
|
-
updateConnection({
|
|
3627
|
+
updateConnection({ status: "authenticating" }, batchUpdates);
|
|
3368
3628
|
effects.authenticate(auth, createWebSocket);
|
|
3369
3629
|
}
|
|
3370
3630
|
function updatePresence(patch, options) {
|
|
3371
3631
|
const oldValues = {};
|
|
3372
|
-
if (
|
|
3373
|
-
|
|
3632
|
+
if (context.buffer.me === null) {
|
|
3633
|
+
context.buffer.me = {
|
|
3374
3634
|
type: "partial",
|
|
3375
3635
|
data: {}
|
|
3376
3636
|
};
|
|
@@ -3380,18 +3640,18 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3380
3640
|
if (overrideValue === void 0) {
|
|
3381
3641
|
continue;
|
|
3382
3642
|
}
|
|
3383
|
-
|
|
3384
|
-
oldValues[key] =
|
|
3643
|
+
context.buffer.me.data[key] = overrideValue;
|
|
3644
|
+
oldValues[key] = context.me.current[key];
|
|
3385
3645
|
}
|
|
3386
|
-
|
|
3387
|
-
if (
|
|
3646
|
+
context.me.patch(patch);
|
|
3647
|
+
if (context.activeBatch) {
|
|
3388
3648
|
if (options == null ? void 0 : options.addToHistory) {
|
|
3389
|
-
|
|
3649
|
+
context.activeBatch.reverseOps.unshift({
|
|
3390
3650
|
type: "presence",
|
|
3391
3651
|
data: oldValues
|
|
3392
3652
|
});
|
|
3393
3653
|
}
|
|
3394
|
-
|
|
3654
|
+
context.activeBatch.updates.presence = true;
|
|
3395
3655
|
} else {
|
|
3396
3656
|
tryFlushing();
|
|
3397
3657
|
batchUpdates(() => {
|
|
@@ -3415,7 +3675,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3415
3675
|
socket.addEventListener("error", onError);
|
|
3416
3676
|
updateConnection(
|
|
3417
3677
|
{
|
|
3418
|
-
|
|
3678
|
+
status: "connecting",
|
|
3419
3679
|
id: token.actor,
|
|
3420
3680
|
userInfo: token.info,
|
|
3421
3681
|
userId: token.id,
|
|
@@ -3423,36 +3683,38 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3423
3683
|
},
|
|
3424
3684
|
batchUpdates
|
|
3425
3685
|
);
|
|
3426
|
-
|
|
3427
|
-
|
|
3686
|
+
context.idFactory = makeIdFactory(token.actor);
|
|
3687
|
+
context.socket = socket;
|
|
3428
3688
|
}
|
|
3429
3689
|
function authenticationFailure(error2) {
|
|
3430
3690
|
if (process.env.NODE_ENV !== "production") {
|
|
3431
3691
|
error("Call to authentication endpoint failed", error2);
|
|
3432
3692
|
}
|
|
3433
|
-
|
|
3434
|
-
updateConnection({
|
|
3435
|
-
|
|
3436
|
-
|
|
3693
|
+
context.token = null;
|
|
3694
|
+
updateConnection({ status: "unavailable" }, batchUpdates);
|
|
3695
|
+
context.numberOfRetry++;
|
|
3696
|
+
context.timeoutHandles.reconnect = effects.scheduleReconnect(
|
|
3697
|
+
getRetryDelay()
|
|
3698
|
+
);
|
|
3437
3699
|
}
|
|
3438
3700
|
function onVisibilityChange(visibilityState) {
|
|
3439
|
-
if (visibilityState === "visible" &&
|
|
3701
|
+
if (visibilityState === "visible" && context.connection.current.status === "open") {
|
|
3440
3702
|
log("Heartbeat after visibility change");
|
|
3441
3703
|
heartbeat();
|
|
3442
3704
|
}
|
|
3443
3705
|
}
|
|
3444
3706
|
function onUpdatePresenceMessage(message) {
|
|
3445
3707
|
if (message.targetActor !== void 0) {
|
|
3446
|
-
const oldUser =
|
|
3447
|
-
|
|
3448
|
-
const newUser =
|
|
3708
|
+
const oldUser = context.others.getUser(message.actor);
|
|
3709
|
+
context.others.setOther(message.actor, message.data);
|
|
3710
|
+
const newUser = context.others.getUser(message.actor);
|
|
3449
3711
|
if (oldUser === void 0 && newUser !== void 0) {
|
|
3450
3712
|
return { type: "enter", user: newUser };
|
|
3451
3713
|
}
|
|
3452
3714
|
} else {
|
|
3453
|
-
|
|
3715
|
+
context.others.patchOther(message.actor, message.data), message;
|
|
3454
3716
|
}
|
|
3455
|
-
const user =
|
|
3717
|
+
const user = context.others.getUser(message.actor);
|
|
3456
3718
|
if (user) {
|
|
3457
3719
|
return {
|
|
3458
3720
|
type: "update",
|
|
@@ -3464,24 +3726,24 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3464
3726
|
}
|
|
3465
3727
|
}
|
|
3466
3728
|
function onUserLeftMessage(message) {
|
|
3467
|
-
const user =
|
|
3729
|
+
const user = context.others.getUser(message.actor);
|
|
3468
3730
|
if (user) {
|
|
3469
|
-
|
|
3731
|
+
context.others.removeConnection(message.actor);
|
|
3470
3732
|
return { type: "leave", user };
|
|
3471
3733
|
}
|
|
3472
3734
|
return null;
|
|
3473
3735
|
}
|
|
3474
3736
|
function onRoomStateMessage(message) {
|
|
3475
|
-
for (const connectionId in
|
|
3737
|
+
for (const connectionId in context.others._connections) {
|
|
3476
3738
|
const user = message.users[connectionId];
|
|
3477
3739
|
if (user === void 0) {
|
|
3478
|
-
|
|
3740
|
+
context.others.removeConnection(Number(connectionId));
|
|
3479
3741
|
}
|
|
3480
3742
|
}
|
|
3481
3743
|
for (const key in message.users) {
|
|
3482
3744
|
const user = message.users[key];
|
|
3483
3745
|
const connectionId = Number(key);
|
|
3484
|
-
|
|
3746
|
+
context.others.setConnection(
|
|
3485
3747
|
connectionId,
|
|
3486
3748
|
user.id,
|
|
3487
3749
|
user.info,
|
|
@@ -3491,7 +3753,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3491
3753
|
return { type: "reset" };
|
|
3492
3754
|
}
|
|
3493
3755
|
function onNavigatorOnline() {
|
|
3494
|
-
if (
|
|
3756
|
+
if (context.connection.current.status === "unavailable") {
|
|
3495
3757
|
log("Try to reconnect after connectivity change");
|
|
3496
3758
|
reconnect();
|
|
3497
3759
|
}
|
|
@@ -3502,19 +3764,19 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3502
3764
|
});
|
|
3503
3765
|
}
|
|
3504
3766
|
function onUserJoinedMessage(message) {
|
|
3505
|
-
|
|
3767
|
+
context.others.setConnection(
|
|
3506
3768
|
message.actor,
|
|
3507
3769
|
message.id,
|
|
3508
3770
|
message.info,
|
|
3509
3771
|
isStorageReadOnly(message.scopes)
|
|
3510
3772
|
);
|
|
3511
|
-
|
|
3773
|
+
context.buffer.messages.push({
|
|
3512
3774
|
type: 100 /* UPDATE_PRESENCE */,
|
|
3513
|
-
data:
|
|
3775
|
+
data: context.me.current,
|
|
3514
3776
|
targetActor: message.actor
|
|
3515
3777
|
});
|
|
3516
3778
|
tryFlushing();
|
|
3517
|
-
const user =
|
|
3779
|
+
const user = context.others.getUser(message.actor);
|
|
3518
3780
|
return user ? { type: "enter", user } : void 0;
|
|
3519
3781
|
}
|
|
3520
3782
|
function parseServerMessage(data) {
|
|
@@ -3535,7 +3797,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3535
3797
|
}
|
|
3536
3798
|
function onMessage(event) {
|
|
3537
3799
|
if (event.data === "pong") {
|
|
3538
|
-
clearTimeout(
|
|
3800
|
+
clearTimeout(context.timeoutHandles.pongTimeout);
|
|
3539
3801
|
return;
|
|
3540
3802
|
}
|
|
3541
3803
|
const messages = parseServerMessages(event.data);
|
|
@@ -3583,7 +3845,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3583
3845
|
break;
|
|
3584
3846
|
}
|
|
3585
3847
|
case 200 /* INITIAL_STORAGE_STATE */: {
|
|
3586
|
-
const unacknowledgedOps = new Map(
|
|
3848
|
+
const unacknowledgedOps = new Map(context.unacknowledgedOps);
|
|
3587
3849
|
createOrUpdateRootFromMessage(message, doNotBatchUpdates);
|
|
3588
3850
|
applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
|
|
3589
3851
|
if (_getInitialStateResolver !== null) {
|
|
@@ -3598,10 +3860,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3598
3860
|
applyResult.updates.storageUpdates.forEach((value, key) => {
|
|
3599
3861
|
updates.storageUpdates.set(
|
|
3600
3862
|
key,
|
|
3601
|
-
mergeStorageUpdates(
|
|
3602
|
-
updates.storageUpdates.get(key),
|
|
3603
|
-
value
|
|
3604
|
-
)
|
|
3863
|
+
mergeStorageUpdates(updates.storageUpdates.get(key), value)
|
|
3605
3864
|
);
|
|
3606
3865
|
});
|
|
3607
3866
|
break;
|
|
@@ -3614,7 +3873,7 @@ function makeStateMachine(state, config, mockedEffects) {
|
|
|
3614
3873
|
if (process.env.NODE_ENV !== "production") {
|
|
3615
3874
|
const traces = /* @__PURE__ */ new Set();
|
|
3616
3875
|
for (const opId of message.opIds) {
|
|
3617
|
-
const trace = (_a2 =
|
|
3876
|
+
const trace = (_a2 = context.opStackTraces) == null ? void 0 : _a2.get(opId);
|
|
3618
3877
|
if (trace) {
|
|
3619
3878
|
traces.add(trace);
|
|
3620
3879
|
}
|
|
@@ -3639,90 +3898,95 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3639
3898
|
});
|
|
3640
3899
|
}
|
|
3641
3900
|
function onClose(event) {
|
|
3642
|
-
|
|
3643
|
-
clearTimeout(
|
|
3644
|
-
clearInterval(
|
|
3645
|
-
if (
|
|
3646
|
-
clearTimeout(
|
|
3647
|
-
}
|
|
3648
|
-
clearTimeout(
|
|
3649
|
-
|
|
3901
|
+
context.socket = null;
|
|
3902
|
+
clearTimeout(context.timeoutHandles.pongTimeout);
|
|
3903
|
+
clearInterval(context.intervalHandles.heartbeat);
|
|
3904
|
+
if (context.timeoutHandles.flush) {
|
|
3905
|
+
clearTimeout(context.timeoutHandles.flush);
|
|
3906
|
+
}
|
|
3907
|
+
clearTimeout(context.timeoutHandles.reconnect);
|
|
3908
|
+
context.others.clearOthers();
|
|
3650
3909
|
batchUpdates(() => {
|
|
3651
3910
|
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
3652
3911
|
if (event.code >= 4e3 && event.code <= 4100) {
|
|
3653
|
-
updateConnection({
|
|
3912
|
+
updateConnection({ status: "failed" }, doNotBatchUpdates);
|
|
3654
3913
|
const error2 = new LiveblocksError(event.reason, event.code);
|
|
3655
3914
|
eventHub.error.notify(error2);
|
|
3656
3915
|
const delay = getRetryDelay(true);
|
|
3657
|
-
|
|
3916
|
+
context.numberOfRetry++;
|
|
3658
3917
|
if (process.env.NODE_ENV !== "production") {
|
|
3659
3918
|
error(
|
|
3660
3919
|
`Connection to websocket server closed. Reason: ${error2.message} (code: ${error2.code}). Retrying in ${delay}ms.`
|
|
3661
3920
|
);
|
|
3662
3921
|
}
|
|
3663
|
-
updateConnection({
|
|
3664
|
-
|
|
3922
|
+
updateConnection({ status: "unavailable" }, doNotBatchUpdates);
|
|
3923
|
+
context.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
|
|
3665
3924
|
} else if (event.code === 4999 /* CLOSE_WITHOUT_RETRY */) {
|
|
3666
|
-
updateConnection({
|
|
3925
|
+
updateConnection({ status: "closed" }, doNotBatchUpdates);
|
|
3667
3926
|
} else {
|
|
3668
3927
|
const delay = getRetryDelay();
|
|
3669
|
-
|
|
3928
|
+
context.numberOfRetry++;
|
|
3670
3929
|
if (process.env.NODE_ENV !== "production") {
|
|
3671
3930
|
warn(
|
|
3672
3931
|
`Connection to Liveblocks websocket server closed (code: ${event.code}). Retrying in ${delay}ms.`
|
|
3673
3932
|
);
|
|
3674
3933
|
}
|
|
3675
|
-
updateConnection({
|
|
3676
|
-
|
|
3934
|
+
updateConnection({ status: "unavailable" }, doNotBatchUpdates);
|
|
3935
|
+
context.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
|
|
3677
3936
|
}
|
|
3678
3937
|
});
|
|
3679
3938
|
}
|
|
3680
3939
|
function updateConnection(connection, batchedUpdatesWrapper) {
|
|
3681
|
-
|
|
3940
|
+
context.connection.set(connection);
|
|
3682
3941
|
batchedUpdatesWrapper(() => {
|
|
3683
|
-
eventHub.connection.notify(connection.
|
|
3942
|
+
eventHub.connection.notify(connection.status);
|
|
3684
3943
|
});
|
|
3685
3944
|
}
|
|
3686
3945
|
function getRetryDelay(slow = false) {
|
|
3687
3946
|
if (slow) {
|
|
3688
|
-
return BACKOFF_RETRY_DELAYS_SLOW[
|
|
3947
|
+
return BACKOFF_RETRY_DELAYS_SLOW[context.numberOfRetry < BACKOFF_RETRY_DELAYS_SLOW.length ? context.numberOfRetry : BACKOFF_RETRY_DELAYS_SLOW.length - 1];
|
|
3689
3948
|
}
|
|
3690
|
-
return BACKOFF_RETRY_DELAYS[
|
|
3949
|
+
return BACKOFF_RETRY_DELAYS[context.numberOfRetry < BACKOFF_RETRY_DELAYS.length ? context.numberOfRetry : BACKOFF_RETRY_DELAYS.length - 1];
|
|
3691
3950
|
}
|
|
3692
3951
|
function onError() {
|
|
3693
3952
|
}
|
|
3694
3953
|
function onOpen() {
|
|
3695
|
-
clearInterval(
|
|
3696
|
-
|
|
3697
|
-
if (
|
|
3954
|
+
clearInterval(context.intervalHandles.heartbeat);
|
|
3955
|
+
context.intervalHandles.heartbeat = effects.startHeartbeatInterval();
|
|
3956
|
+
if (context.connection.current.status === "connecting") {
|
|
3698
3957
|
updateConnection(
|
|
3699
|
-
__spreadProps(__spreadValues({},
|
|
3958
|
+
__spreadProps(__spreadValues({}, context.connection.current), { status: "open" }),
|
|
3700
3959
|
batchUpdates
|
|
3701
3960
|
);
|
|
3702
|
-
|
|
3703
|
-
if (
|
|
3704
|
-
|
|
3961
|
+
context.numberOfRetry = 0;
|
|
3962
|
+
if (context.lastConnectionId !== void 0) {
|
|
3963
|
+
context.buffer.me = {
|
|
3705
3964
|
type: "full",
|
|
3706
|
-
data:
|
|
3965
|
+
data: (
|
|
3966
|
+
// Because state.me.current is a readonly object, we'll have to
|
|
3967
|
+
// make a copy here. Otherwise, type errors happen later when
|
|
3968
|
+
// "patching" my presence.
|
|
3969
|
+
__spreadValues({}, context.me.current)
|
|
3970
|
+
)
|
|
3707
3971
|
};
|
|
3708
3972
|
tryFlushing();
|
|
3709
3973
|
}
|
|
3710
|
-
|
|
3711
|
-
if (
|
|
3712
|
-
|
|
3974
|
+
context.lastConnectionId = context.connection.current.id;
|
|
3975
|
+
if (context.root) {
|
|
3976
|
+
context.buffer.messages.push({ type: 200 /* FETCH_STORAGE */ });
|
|
3713
3977
|
}
|
|
3714
3978
|
tryFlushing();
|
|
3715
3979
|
} else {
|
|
3716
3980
|
}
|
|
3717
3981
|
}
|
|
3718
3982
|
function heartbeat() {
|
|
3719
|
-
if (
|
|
3983
|
+
if (context.socket === null) {
|
|
3720
3984
|
return;
|
|
3721
3985
|
}
|
|
3722
|
-
clearTimeout(
|
|
3723
|
-
|
|
3724
|
-
if (
|
|
3725
|
-
|
|
3986
|
+
clearTimeout(context.timeoutHandles.pongTimeout);
|
|
3987
|
+
context.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
|
|
3988
|
+
if (context.socket.readyState === context.socket.OPEN) {
|
|
3989
|
+
context.socket.send("ping");
|
|
3726
3990
|
}
|
|
3727
3991
|
}
|
|
3728
3992
|
function pongTimeout() {
|
|
@@ -3730,21 +3994,21 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3730
3994
|
reconnect();
|
|
3731
3995
|
}
|
|
3732
3996
|
function reconnect() {
|
|
3733
|
-
if (
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
}
|
|
3741
|
-
updateConnection({
|
|
3742
|
-
clearTimeout(
|
|
3743
|
-
if (
|
|
3744
|
-
clearTimeout(
|
|
3745
|
-
}
|
|
3746
|
-
clearTimeout(
|
|
3747
|
-
clearInterval(
|
|
3997
|
+
if (context.socket) {
|
|
3998
|
+
context.socket.removeEventListener("open", onOpen);
|
|
3999
|
+
context.socket.removeEventListener("message", onMessage);
|
|
4000
|
+
context.socket.removeEventListener("close", onClose);
|
|
4001
|
+
context.socket.removeEventListener("error", onError);
|
|
4002
|
+
context.socket.close();
|
|
4003
|
+
context.socket = null;
|
|
4004
|
+
}
|
|
4005
|
+
updateConnection({ status: "unavailable" }, batchUpdates);
|
|
4006
|
+
clearTimeout(context.timeoutHandles.pongTimeout);
|
|
4007
|
+
if (context.timeoutHandles.flush) {
|
|
4008
|
+
clearTimeout(context.timeoutHandles.flush);
|
|
4009
|
+
}
|
|
4010
|
+
clearTimeout(context.timeoutHandles.reconnect);
|
|
4011
|
+
clearInterval(context.intervalHandles.heartbeat);
|
|
3748
4012
|
connect();
|
|
3749
4013
|
}
|
|
3750
4014
|
function applyAndSendOps(offlineOps, batchedUpdatesWrapper) {
|
|
@@ -3762,114 +4026,111 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3762
4026
|
effects.send(messages);
|
|
3763
4027
|
}
|
|
3764
4028
|
function tryFlushing() {
|
|
3765
|
-
const storageOps =
|
|
4029
|
+
const storageOps = context.buffer.storageOperations;
|
|
3766
4030
|
if (storageOps.length > 0) {
|
|
3767
4031
|
storageOps.forEach((op) => {
|
|
3768
|
-
|
|
4032
|
+
context.unacknowledgedOps.set(nn(op.opId), op);
|
|
3769
4033
|
});
|
|
3770
4034
|
notifyStorageStatus();
|
|
3771
4035
|
}
|
|
3772
|
-
if (
|
|
3773
|
-
|
|
4036
|
+
if (context.socket === null || context.socket.readyState !== context.socket.OPEN) {
|
|
4037
|
+
context.buffer.storageOperations = [];
|
|
3774
4038
|
return;
|
|
3775
4039
|
}
|
|
3776
4040
|
const now = Date.now();
|
|
3777
|
-
const elapsedTime = now -
|
|
4041
|
+
const elapsedTime = now - context.lastFlushTime;
|
|
3778
4042
|
if (elapsedTime > config.throttleDelay) {
|
|
3779
|
-
const messages = flushDataToMessages(
|
|
4043
|
+
const messages = flushDataToMessages(context);
|
|
3780
4044
|
if (messages.length === 0) {
|
|
3781
4045
|
return;
|
|
3782
4046
|
}
|
|
3783
4047
|
effects.send(messages);
|
|
3784
|
-
|
|
4048
|
+
context.buffer = {
|
|
3785
4049
|
messages: [],
|
|
3786
4050
|
storageOperations: [],
|
|
3787
4051
|
me: null
|
|
3788
4052
|
};
|
|
3789
|
-
|
|
4053
|
+
context.lastFlushTime = now;
|
|
3790
4054
|
} else {
|
|
3791
|
-
if (
|
|
3792
|
-
clearTimeout(
|
|
4055
|
+
if (context.timeoutHandles.flush !== null) {
|
|
4056
|
+
clearTimeout(context.timeoutHandles.flush);
|
|
3793
4057
|
}
|
|
3794
|
-
|
|
3795
|
-
config.throttleDelay - (now -
|
|
4058
|
+
context.timeoutHandles.flush = effects.delayFlush(
|
|
4059
|
+
config.throttleDelay - (now - context.lastFlushTime)
|
|
3796
4060
|
);
|
|
3797
4061
|
}
|
|
3798
4062
|
}
|
|
3799
|
-
function flushDataToMessages(
|
|
4063
|
+
function flushDataToMessages(state) {
|
|
3800
4064
|
const messages = [];
|
|
3801
|
-
if (
|
|
4065
|
+
if (state.buffer.me) {
|
|
3802
4066
|
messages.push(
|
|
3803
|
-
|
|
4067
|
+
state.buffer.me.type === "full" ? {
|
|
3804
4068
|
type: 100 /* UPDATE_PRESENCE */,
|
|
4069
|
+
// Populating the `targetActor` field turns this message into
|
|
4070
|
+
// a Full Presence™ update message (not a patch), which will get
|
|
4071
|
+
// interpreted by other clients as such.
|
|
3805
4072
|
targetActor: -1,
|
|
3806
|
-
data:
|
|
4073
|
+
data: state.buffer.me.data
|
|
3807
4074
|
} : {
|
|
3808
4075
|
type: 100 /* UPDATE_PRESENCE */,
|
|
3809
|
-
data:
|
|
4076
|
+
data: state.buffer.me.data
|
|
3810
4077
|
}
|
|
3811
4078
|
);
|
|
3812
4079
|
}
|
|
3813
|
-
for (const event of
|
|
4080
|
+
for (const event of state.buffer.messages) {
|
|
3814
4081
|
messages.push(event);
|
|
3815
4082
|
}
|
|
3816
|
-
if (
|
|
4083
|
+
if (state.buffer.storageOperations.length > 0) {
|
|
3817
4084
|
messages.push({
|
|
3818
4085
|
type: 201 /* UPDATE_STORAGE */,
|
|
3819
|
-
ops:
|
|
4086
|
+
ops: state.buffer.storageOperations
|
|
3820
4087
|
});
|
|
3821
4088
|
}
|
|
3822
4089
|
return messages;
|
|
3823
4090
|
}
|
|
3824
4091
|
function disconnect() {
|
|
3825
|
-
if (
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
4092
|
+
if (context.socket) {
|
|
4093
|
+
context.socket.removeEventListener("open", onOpen);
|
|
4094
|
+
context.socket.removeEventListener("message", onMessage);
|
|
4095
|
+
context.socket.removeEventListener("close", onClose);
|
|
4096
|
+
context.socket.removeEventListener("error", onError);
|
|
4097
|
+
context.socket.close();
|
|
4098
|
+
context.socket = null;
|
|
3832
4099
|
}
|
|
3833
4100
|
batchUpdates(() => {
|
|
3834
|
-
updateConnection({
|
|
3835
|
-
if (
|
|
3836
|
-
clearTimeout(
|
|
4101
|
+
updateConnection({ status: "closed" }, doNotBatchUpdates);
|
|
4102
|
+
if (context.timeoutHandles.flush) {
|
|
4103
|
+
clearTimeout(context.timeoutHandles.flush);
|
|
3837
4104
|
}
|
|
3838
|
-
clearTimeout(
|
|
3839
|
-
clearTimeout(
|
|
3840
|
-
clearInterval(
|
|
3841
|
-
|
|
4105
|
+
clearTimeout(context.timeoutHandles.reconnect);
|
|
4106
|
+
clearTimeout(context.timeoutHandles.pongTimeout);
|
|
4107
|
+
clearInterval(context.intervalHandles.heartbeat);
|
|
4108
|
+
context.others.clearOthers();
|
|
3842
4109
|
notify({ others: [{ type: "reset" }] }, doNotBatchUpdates);
|
|
3843
4110
|
Object.values(eventHub).forEach((eventSource2) => eventSource2.clear());
|
|
3844
4111
|
});
|
|
3845
4112
|
}
|
|
3846
|
-
function getPresence() {
|
|
3847
|
-
return state.me.current;
|
|
3848
|
-
}
|
|
3849
|
-
function getOthers() {
|
|
3850
|
-
return state.others.current;
|
|
3851
|
-
}
|
|
3852
4113
|
function broadcastEvent(event, options = {
|
|
3853
4114
|
shouldQueueEventIfNotReady: false
|
|
3854
4115
|
}) {
|
|
3855
|
-
if (
|
|
4116
|
+
if (context.socket === null && !options.shouldQueueEventIfNotReady) {
|
|
3856
4117
|
return;
|
|
3857
4118
|
}
|
|
3858
|
-
|
|
4119
|
+
context.buffer.messages.push({
|
|
3859
4120
|
type: 103 /* BROADCAST_EVENT */,
|
|
3860
4121
|
event
|
|
3861
4122
|
});
|
|
3862
4123
|
tryFlushing();
|
|
3863
4124
|
}
|
|
3864
4125
|
function dispatchOps(ops) {
|
|
3865
|
-
|
|
4126
|
+
context.buffer.storageOperations.push(...ops);
|
|
3866
4127
|
tryFlushing();
|
|
3867
4128
|
}
|
|
3868
4129
|
let _getInitialStatePromise = null;
|
|
3869
4130
|
let _getInitialStateResolver = null;
|
|
3870
4131
|
function startLoadingStorage() {
|
|
3871
4132
|
if (_getInitialStatePromise === null) {
|
|
3872
|
-
|
|
4133
|
+
context.buffer.messages.push({ type: 200 /* FETCH_STORAGE */ });
|
|
3873
4134
|
tryFlushing();
|
|
3874
4135
|
_getInitialStatePromise = new Promise(
|
|
3875
4136
|
(resolve) => _getInitialStateResolver = resolve
|
|
@@ -3879,7 +4140,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3879
4140
|
return _getInitialStatePromise;
|
|
3880
4141
|
}
|
|
3881
4142
|
function getStorageSnapshot() {
|
|
3882
|
-
const root =
|
|
4143
|
+
const root = context.root;
|
|
3883
4144
|
if (root !== void 0) {
|
|
3884
4145
|
return root;
|
|
3885
4146
|
} else {
|
|
@@ -3889,74 +4150,74 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3889
4150
|
}
|
|
3890
4151
|
function getStorage() {
|
|
3891
4152
|
return __async(this, null, function* () {
|
|
3892
|
-
if (
|
|
4153
|
+
if (context.root) {
|
|
3893
4154
|
return Promise.resolve({
|
|
3894
|
-
root:
|
|
4155
|
+
root: context.root
|
|
3895
4156
|
});
|
|
3896
4157
|
}
|
|
3897
4158
|
yield startLoadingStorage();
|
|
3898
4159
|
return {
|
|
3899
|
-
root: nn(
|
|
4160
|
+
root: nn(context.root)
|
|
3900
4161
|
};
|
|
3901
4162
|
});
|
|
3902
4163
|
}
|
|
3903
4164
|
function undo() {
|
|
3904
|
-
if (
|
|
4165
|
+
if (context.activeBatch) {
|
|
3905
4166
|
throw new Error("undo is not allowed during a batch");
|
|
3906
4167
|
}
|
|
3907
|
-
const historyOps =
|
|
4168
|
+
const historyOps = context.undoStack.pop();
|
|
3908
4169
|
if (historyOps === void 0) {
|
|
3909
4170
|
return;
|
|
3910
4171
|
}
|
|
3911
|
-
|
|
4172
|
+
context.pausedHistory = null;
|
|
3912
4173
|
const result = applyOps(historyOps, true);
|
|
3913
4174
|
batchUpdates(() => {
|
|
3914
4175
|
notify(result.updates, doNotBatchUpdates);
|
|
3915
|
-
|
|
4176
|
+
context.redoStack.push(result.reverse);
|
|
3916
4177
|
onHistoryChange(doNotBatchUpdates);
|
|
3917
4178
|
});
|
|
3918
4179
|
for (const op of result.ops) {
|
|
3919
4180
|
if (op.type !== "presence") {
|
|
3920
|
-
|
|
4181
|
+
context.buffer.storageOperations.push(op);
|
|
3921
4182
|
}
|
|
3922
4183
|
}
|
|
3923
4184
|
tryFlushing();
|
|
3924
4185
|
}
|
|
3925
4186
|
function canUndo() {
|
|
3926
|
-
return
|
|
4187
|
+
return context.undoStack.length > 0;
|
|
3927
4188
|
}
|
|
3928
4189
|
function redo() {
|
|
3929
|
-
if (
|
|
4190
|
+
if (context.activeBatch) {
|
|
3930
4191
|
throw new Error("redo is not allowed during a batch");
|
|
3931
4192
|
}
|
|
3932
|
-
const historyOps =
|
|
4193
|
+
const historyOps = context.redoStack.pop();
|
|
3933
4194
|
if (historyOps === void 0) {
|
|
3934
4195
|
return;
|
|
3935
4196
|
}
|
|
3936
|
-
|
|
4197
|
+
context.pausedHistory = null;
|
|
3937
4198
|
const result = applyOps(historyOps, true);
|
|
3938
4199
|
batchUpdates(() => {
|
|
3939
4200
|
notify(result.updates, doNotBatchUpdates);
|
|
3940
|
-
|
|
4201
|
+
context.undoStack.push(result.reverse);
|
|
3941
4202
|
onHistoryChange(doNotBatchUpdates);
|
|
3942
4203
|
});
|
|
3943
4204
|
for (const op of result.ops) {
|
|
3944
4205
|
if (op.type !== "presence") {
|
|
3945
|
-
|
|
4206
|
+
context.buffer.storageOperations.push(op);
|
|
3946
4207
|
}
|
|
3947
4208
|
}
|
|
3948
4209
|
tryFlushing();
|
|
3949
4210
|
}
|
|
3950
4211
|
function canRedo() {
|
|
3951
|
-
return
|
|
4212
|
+
return context.redoStack.length > 0;
|
|
3952
4213
|
}
|
|
3953
4214
|
function batch(callback) {
|
|
3954
|
-
if (
|
|
4215
|
+
if (context.activeBatch) {
|
|
3955
4216
|
return callback();
|
|
3956
4217
|
}
|
|
3957
4218
|
let returnValue = void 0;
|
|
3958
4219
|
batchUpdates(() => {
|
|
3959
|
-
|
|
4220
|
+
context.activeBatch = {
|
|
3960
4221
|
ops: [],
|
|
3961
4222
|
updates: {
|
|
3962
4223
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
@@ -3968,13 +4229,13 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3968
4229
|
try {
|
|
3969
4230
|
returnValue = callback();
|
|
3970
4231
|
} finally {
|
|
3971
|
-
const currentBatch =
|
|
3972
|
-
|
|
4232
|
+
const currentBatch = context.activeBatch;
|
|
4233
|
+
context.activeBatch = null;
|
|
3973
4234
|
if (currentBatch.reverseOps.length > 0) {
|
|
3974
4235
|
addToUndoStack(currentBatch.reverseOps, doNotBatchUpdates);
|
|
3975
4236
|
}
|
|
3976
4237
|
if (currentBatch.ops.length > 0) {
|
|
3977
|
-
|
|
4238
|
+
context.redoStack = [];
|
|
3978
4239
|
}
|
|
3979
4240
|
if (currentBatch.ops.length > 0) {
|
|
3980
4241
|
dispatchOps(currentBatch.ops);
|
|
@@ -3986,18 +4247,18 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
3986
4247
|
return returnValue;
|
|
3987
4248
|
}
|
|
3988
4249
|
function pauseHistory() {
|
|
3989
|
-
|
|
4250
|
+
context.pausedHistory = [];
|
|
3990
4251
|
}
|
|
3991
4252
|
function resumeHistory() {
|
|
3992
|
-
const historyOps =
|
|
3993
|
-
|
|
4253
|
+
const historyOps = context.pausedHistory;
|
|
4254
|
+
context.pausedHistory = null;
|
|
3994
4255
|
if (historyOps !== null && historyOps.length > 0) {
|
|
3995
4256
|
_addToRealUndoStack(historyOps, batchUpdates);
|
|
3996
4257
|
}
|
|
3997
4258
|
}
|
|
3998
4259
|
function simulateSocketClose() {
|
|
3999
|
-
if (
|
|
4000
|
-
|
|
4260
|
+
if (context.socket) {
|
|
4261
|
+
context.socket = null;
|
|
4001
4262
|
}
|
|
4002
4263
|
}
|
|
4003
4264
|
function simulateSendCloseEvent(event) {
|
|
@@ -4007,10 +4268,10 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4007
4268
|
if (_getInitialStatePromise === null) {
|
|
4008
4269
|
return "not-loaded";
|
|
4009
4270
|
}
|
|
4010
|
-
if (
|
|
4271
|
+
if (context.root === void 0) {
|
|
4011
4272
|
return "loading";
|
|
4012
4273
|
}
|
|
4013
|
-
return
|
|
4274
|
+
return context.unacknowledgedOps.size === 0 ? "synchronized" : "synchronizing";
|
|
4014
4275
|
}
|
|
4015
4276
|
let _lastStorageStatus = getStorageStatus();
|
|
4016
4277
|
function notifyStorageStatus() {
|
|
@@ -4020,23 +4281,34 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4020
4281
|
eventHub.storageStatus.notify(storageStatus);
|
|
4021
4282
|
}
|
|
4022
4283
|
}
|
|
4284
|
+
const others_forDevTools = new DerivedRef(
|
|
4285
|
+
context.others,
|
|
4286
|
+
(others) => others.map((other, index) => userToTreeNode(`Other ${index}`, other))
|
|
4287
|
+
);
|
|
4023
4288
|
return {
|
|
4289
|
+
// Internal
|
|
4290
|
+
get state() {
|
|
4291
|
+
return context;
|
|
4292
|
+
},
|
|
4024
4293
|
onClose,
|
|
4025
4294
|
onMessage,
|
|
4026
4295
|
authenticationSuccess,
|
|
4027
4296
|
heartbeat,
|
|
4028
4297
|
onNavigatorOnline,
|
|
4298
|
+
// Internal DevTools
|
|
4029
4299
|
simulateSocketClose,
|
|
4030
4300
|
simulateSendCloseEvent,
|
|
4031
4301
|
onVisibilityChange,
|
|
4032
|
-
getUndoStack: () =>
|
|
4033
|
-
getItemsCount: () =>
|
|
4302
|
+
getUndoStack: () => context.undoStack,
|
|
4303
|
+
getItemsCount: () => context.nodes.size,
|
|
4304
|
+
// Core
|
|
4034
4305
|
connect,
|
|
4035
4306
|
disconnect,
|
|
4036
4307
|
reconnect,
|
|
4037
|
-
|
|
4308
|
+
// Presence
|
|
4038
4309
|
updatePresence,
|
|
4039
4310
|
broadcastEvent,
|
|
4311
|
+
// Storage
|
|
4040
4312
|
batch,
|
|
4041
4313
|
undo,
|
|
4042
4314
|
redo,
|
|
@@ -4058,83 +4330,45 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
4058
4330
|
storageDidLoad: eventHub.storageDidLoad.observable,
|
|
4059
4331
|
storageStatus: eventHub.storageStatus.observable
|
|
4060
4332
|
},
|
|
4061
|
-
|
|
4062
|
-
|
|
4333
|
+
// Core
|
|
4334
|
+
getConnectionState: () => context.connection.current.status,
|
|
4335
|
+
isSelfAware: () => isConnectionSelfAware(context.connection.current),
|
|
4063
4336
|
getSelf: () => self.current,
|
|
4064
|
-
|
|
4065
|
-
|
|
4337
|
+
// Presence
|
|
4338
|
+
getPresence: () => context.me.current,
|
|
4339
|
+
getOthers: () => context.others.current,
|
|
4340
|
+
// Support for the Liveblocks browser extension
|
|
4066
4341
|
getSelf_forDevTools: () => selfAsTreeNode.current,
|
|
4067
|
-
getOthers_forDevTools: () =>
|
|
4068
|
-
};
|
|
4069
|
-
}
|
|
4070
|
-
function defaultState(initialPresence, initialStorage) {
|
|
4071
|
-
const others = new OthersRef();
|
|
4072
|
-
const others_forDevTools = new DerivedRef(
|
|
4073
|
-
others,
|
|
4074
|
-
(others2) => others2.map((other, index) => userToTreeNode(`Other ${index}`, other))
|
|
4075
|
-
);
|
|
4076
|
-
const connection = new ValueRef({ state: "closed" });
|
|
4077
|
-
return {
|
|
4078
|
-
token: null,
|
|
4079
|
-
lastConnectionId: null,
|
|
4080
|
-
socket: null,
|
|
4081
|
-
numberOfRetry: 0,
|
|
4082
|
-
lastFlushTime: 0,
|
|
4083
|
-
timeoutHandles: {
|
|
4084
|
-
flush: null,
|
|
4085
|
-
reconnect: 0,
|
|
4086
|
-
pongTimeout: 0
|
|
4087
|
-
},
|
|
4088
|
-
buffer: {
|
|
4089
|
-
me: {
|
|
4090
|
-
type: "full",
|
|
4091
|
-
data: initialPresence
|
|
4092
|
-
},
|
|
4093
|
-
messages: [],
|
|
4094
|
-
storageOperations: []
|
|
4095
|
-
},
|
|
4096
|
-
intervalHandles: {
|
|
4097
|
-
heartbeat: 0
|
|
4098
|
-
},
|
|
4099
|
-
connection,
|
|
4100
|
-
me: new MeRef(initialPresence),
|
|
4101
|
-
others,
|
|
4102
|
-
others_forDevTools,
|
|
4103
|
-
initialStorage,
|
|
4104
|
-
idFactory: null,
|
|
4105
|
-
clock: 0,
|
|
4106
|
-
opClock: 0,
|
|
4107
|
-
nodes: /* @__PURE__ */ new Map(),
|
|
4108
|
-
root: void 0,
|
|
4109
|
-
undoStack: [],
|
|
4110
|
-
redoStack: [],
|
|
4111
|
-
pausedHistory: null,
|
|
4112
|
-
activeBatch: null,
|
|
4113
|
-
unacknowledgedOps: /* @__PURE__ */ new Map(),
|
|
4114
|
-
opStackTraces: process.env.NODE_ENV !== "production" ? /* @__PURE__ */ new Map() : void 0
|
|
4342
|
+
getOthers_forDevTools: () => others_forDevTools.current
|
|
4115
4343
|
};
|
|
4116
4344
|
}
|
|
4117
4345
|
function createRoom(options, config) {
|
|
4118
4346
|
const { initialPresence, initialStorage } = options;
|
|
4119
|
-
const
|
|
4347
|
+
const machine = makeStateMachine(
|
|
4348
|
+
config,
|
|
4120
4349
|
typeof initialPresence === "function" ? initialPresence(config.roomId) : initialPresence,
|
|
4121
4350
|
typeof initialStorage === "function" ? initialStorage(config.roomId) : initialStorage
|
|
4122
4351
|
);
|
|
4123
|
-
const machine = makeStateMachine(
|
|
4124
|
-
state,
|
|
4125
|
-
config
|
|
4126
|
-
);
|
|
4127
4352
|
const room = {
|
|
4128
4353
|
id: config.roomId,
|
|
4354
|
+
/////////////
|
|
4355
|
+
// Core //
|
|
4356
|
+
/////////////
|
|
4129
4357
|
getConnectionState: machine.getConnectionState,
|
|
4130
4358
|
isSelfAware: machine.isSelfAware,
|
|
4131
4359
|
getSelf: machine.getSelf,
|
|
4132
4360
|
reconnect: machine.reconnect,
|
|
4133
|
-
subscribe: machine
|
|
4361
|
+
subscribe: makeClassicSubscribeFn(machine),
|
|
4362
|
+
//////////////
|
|
4363
|
+
// Presence //
|
|
4364
|
+
//////////////
|
|
4134
4365
|
getPresence: machine.getPresence,
|
|
4135
4366
|
updatePresence: machine.updatePresence,
|
|
4136
4367
|
getOthers: machine.getOthers,
|
|
4137
4368
|
broadcastEvent: machine.broadcastEvent,
|
|
4369
|
+
//////////////
|
|
4370
|
+
// Storage //
|
|
4371
|
+
//////////////
|
|
4138
4372
|
getStorage: machine.getStorage,
|
|
4139
4373
|
getStorageSnapshot: machine.getStorageSnapshot,
|
|
4140
4374
|
getStorageStatus: machine.getStorageStatus,
|
|
@@ -4148,20 +4382,104 @@ function createRoom(options, config) {
|
|
|
4148
4382
|
pause: machine.pauseHistory,
|
|
4149
4383
|
resume: machine.resumeHistory
|
|
4150
4384
|
},
|
|
4151
|
-
|
|
4385
|
+
__internal: {
|
|
4386
|
+
connect: machine.connect,
|
|
4387
|
+
disconnect: machine.disconnect,
|
|
4388
|
+
onNavigatorOnline: machine.onNavigatorOnline,
|
|
4389
|
+
onVisibilityChange: machine.onVisibilityChange,
|
|
4152
4390
|
simulateCloseWebsocket: machine.simulateSocketClose,
|
|
4153
|
-
simulateSendCloseEvent: machine.simulateSendCloseEvent
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
};
|
|
4158
|
-
return {
|
|
4159
|
-
connect: machine.connect,
|
|
4160
|
-
disconnect: machine.disconnect,
|
|
4161
|
-
onNavigatorOnline: machine.onNavigatorOnline,
|
|
4162
|
-
onVisibilityChange: machine.onVisibilityChange,
|
|
4163
|
-
room
|
|
4391
|
+
simulateSendCloseEvent: machine.simulateSendCloseEvent,
|
|
4392
|
+
getSelf_forDevTools: machine.getSelf_forDevTools,
|
|
4393
|
+
getOthers_forDevTools: machine.getOthers_forDevTools
|
|
4394
|
+
}
|
|
4164
4395
|
};
|
|
4396
|
+
return room;
|
|
4397
|
+
}
|
|
4398
|
+
function makeClassicSubscribeFn(machine) {
|
|
4399
|
+
function subscribeToLiveStructureDeeply(node, callback) {
|
|
4400
|
+
return machine.events.storage.subscribe((updates) => {
|
|
4401
|
+
const relatedUpdates = updates.filter(
|
|
4402
|
+
(update) => isSameNodeOrChildOf(update.node, node)
|
|
4403
|
+
);
|
|
4404
|
+
if (relatedUpdates.length > 0) {
|
|
4405
|
+
callback(relatedUpdates);
|
|
4406
|
+
}
|
|
4407
|
+
});
|
|
4408
|
+
}
|
|
4409
|
+
function subscribeToLiveStructureShallowly(node, callback) {
|
|
4410
|
+
return machine.events.storage.subscribe((updates) => {
|
|
4411
|
+
for (const update of updates) {
|
|
4412
|
+
if (update.node._id === node._id) {
|
|
4413
|
+
callback(update.node);
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
});
|
|
4417
|
+
}
|
|
4418
|
+
function subscribe(first, second, options) {
|
|
4419
|
+
if (typeof first === "string" && isRoomEventName(first)) {
|
|
4420
|
+
if (typeof second !== "function") {
|
|
4421
|
+
throw new Error("Second argument must be a callback function");
|
|
4422
|
+
}
|
|
4423
|
+
const callback = second;
|
|
4424
|
+
switch (first) {
|
|
4425
|
+
case "event":
|
|
4426
|
+
return machine.events.customEvent.subscribe(
|
|
4427
|
+
callback
|
|
4428
|
+
);
|
|
4429
|
+
case "my-presence":
|
|
4430
|
+
return machine.events.me.subscribe(callback);
|
|
4431
|
+
case "others": {
|
|
4432
|
+
const cb = callback;
|
|
4433
|
+
return machine.events.others.subscribe(
|
|
4434
|
+
({ others, event }) => cb(others, event)
|
|
4435
|
+
);
|
|
4436
|
+
}
|
|
4437
|
+
case "error":
|
|
4438
|
+
return machine.events.error.subscribe(callback);
|
|
4439
|
+
case "connection":
|
|
4440
|
+
return machine.events.connection.subscribe(
|
|
4441
|
+
callback
|
|
4442
|
+
);
|
|
4443
|
+
case "storage":
|
|
4444
|
+
return machine.events.storage.subscribe(
|
|
4445
|
+
callback
|
|
4446
|
+
);
|
|
4447
|
+
case "history":
|
|
4448
|
+
return machine.events.history.subscribe(
|
|
4449
|
+
callback
|
|
4450
|
+
);
|
|
4451
|
+
case "storage-status":
|
|
4452
|
+
return machine.events.storageStatus.subscribe(
|
|
4453
|
+
callback
|
|
4454
|
+
);
|
|
4455
|
+
default:
|
|
4456
|
+
return assertNever(first, "Unknown event");
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
if (second === void 0 || typeof first === "function") {
|
|
4460
|
+
if (typeof first === "function") {
|
|
4461
|
+
const storageCallback = first;
|
|
4462
|
+
return machine.events.storage.subscribe(storageCallback);
|
|
4463
|
+
} else {
|
|
4464
|
+
throw new Error("Please specify a listener callback");
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
if (isLiveNode(first)) {
|
|
4468
|
+
const node = first;
|
|
4469
|
+
if (options == null ? void 0 : options.isDeep) {
|
|
4470
|
+
const storageCallback = second;
|
|
4471
|
+
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
4472
|
+
} else {
|
|
4473
|
+
const nodeCallback = second;
|
|
4474
|
+
return subscribeToLiveStructureShallowly(node, nodeCallback);
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
throw new Error(`"${first}" is not a valid event name`);
|
|
4478
|
+
}
|
|
4479
|
+
return subscribe;
|
|
4480
|
+
}
|
|
4481
|
+
function isRoomEventName(value) {
|
|
4482
|
+
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "connection" || value === "history" || value === "storage-status";
|
|
4165
4483
|
}
|
|
4166
4484
|
var LiveblocksError = class extends Error {
|
|
4167
4485
|
constructor(message, code) {
|
|
@@ -4178,7 +4496,13 @@ function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
|
|
|
4178
4496
|
const ws = WebSocketPolyfill || WebSocket;
|
|
4179
4497
|
return (token) => {
|
|
4180
4498
|
return new ws(
|
|
4181
|
-
`${liveblocksServer}/?token=${token}&version=${
|
|
4499
|
+
`${liveblocksServer}/?token=${token}&version=${// prettier-ignore
|
|
4500
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4501
|
+
// @ts-ignore (__PACKAGE_VERSION__ will be injected by the build script)
|
|
4502
|
+
true ? (
|
|
4503
|
+
/* istanbul ignore next */
|
|
4504
|
+
"1.0.6-test2"
|
|
4505
|
+
) : "dev"}`
|
|
4182
4506
|
);
|
|
4183
4507
|
};
|
|
4184
4508
|
}
|
|
@@ -4190,7 +4514,8 @@ function prepareAuthEndpoint(authentication, fetchPolyfill) {
|
|
|
4190
4514
|
);
|
|
4191
4515
|
}
|
|
4192
4516
|
return (room) => fetchAuthEndpoint(
|
|
4193
|
-
fetchPolyfill ||
|
|
4517
|
+
fetchPolyfill || /* istanbul ignore next */
|
|
4518
|
+
fetch,
|
|
4194
4519
|
authentication.url,
|
|
4195
4520
|
{
|
|
4196
4521
|
room,
|
|
@@ -4228,6 +4553,7 @@ function fetchAuthEndpoint(fetch2, endpoint, body) {
|
|
|
4228
4553
|
headers: {
|
|
4229
4554
|
"Content-Type": "application/json"
|
|
4230
4555
|
},
|
|
4556
|
+
// Credentials are needed to support authentication with cookies
|
|
4231
4557
|
credentials: "include",
|
|
4232
4558
|
body: JSON.stringify(body)
|
|
4233
4559
|
});
|
|
@@ -4267,24 +4593,23 @@ var MAX_THROTTLE = 1e3;
|
|
|
4267
4593
|
var DEFAULT_THROTTLE = 100;
|
|
4268
4594
|
function createClient(options) {
|
|
4269
4595
|
const clientOptions = options;
|
|
4270
|
-
const throttleDelay = getThrottleDelayFromOptions(
|
|
4596
|
+
const throttleDelay = getThrottleDelayFromOptions(clientOptions);
|
|
4271
4597
|
const rooms = /* @__PURE__ */ new Map();
|
|
4272
4598
|
function getRoom(roomId) {
|
|
4273
|
-
const
|
|
4274
|
-
return
|
|
4599
|
+
const room = rooms.get(roomId);
|
|
4600
|
+
return room ? room : null;
|
|
4275
4601
|
}
|
|
4276
4602
|
function enter(roomId, options2) {
|
|
4277
|
-
var _a, _b;
|
|
4278
|
-
const
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
return internalRoom.room;
|
|
4603
|
+
var _a, _b, _c;
|
|
4604
|
+
const existingRoom = rooms.get(roomId);
|
|
4605
|
+
if (existingRoom !== void 0) {
|
|
4606
|
+
return existingRoom;
|
|
4282
4607
|
}
|
|
4283
4608
|
deprecateIf(
|
|
4284
4609
|
options2.initialPresence === null || options2.initialPresence === void 0,
|
|
4285
4610
|
"Please provide an initial presence value for the current user when entering the room."
|
|
4286
4611
|
);
|
|
4287
|
-
|
|
4612
|
+
const newRoom = createRoom(
|
|
4288
4613
|
{
|
|
4289
4614
|
initialPresence: (_a = options2.initialPresence) != null ? _a : {},
|
|
4290
4615
|
initialStorage: options2.initialStorage
|
|
@@ -4293,51 +4618,52 @@ function createClient(options) {
|
|
|
4293
4618
|
roomId,
|
|
4294
4619
|
throttleDelay,
|
|
4295
4620
|
polyfills: clientOptions.polyfills,
|
|
4296
|
-
WebSocketPolyfill: clientOptions.WebSocketPolyfill,
|
|
4297
|
-
fetchPolyfill: clientOptions.fetchPolyfill,
|
|
4298
4621
|
unstable_batchedUpdates: options2 == null ? void 0 : options2.unstable_batchedUpdates,
|
|
4299
|
-
liveblocksServer: (
|
|
4622
|
+
liveblocksServer: (
|
|
4623
|
+
// TODO Patch this using public but marked internal fields?
|
|
4624
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4625
|
+
(clientOptions == null ? void 0 : clientOptions.liveblocksServer) || "wss://api.liveblocks.io/v6"
|
|
4626
|
+
),
|
|
4300
4627
|
authentication: prepareAuthentication(clientOptions, roomId)
|
|
4301
4628
|
}
|
|
4302
4629
|
);
|
|
4303
|
-
rooms.set(
|
|
4304
|
-
roomId,
|
|
4305
|
-
internalRoom
|
|
4306
|
-
);
|
|
4630
|
+
rooms.set(roomId, newRoom);
|
|
4307
4631
|
setupDevTools(() => Array.from(rooms.keys()));
|
|
4308
|
-
linkDevTools(roomId,
|
|
4632
|
+
linkDevTools(roomId, newRoom);
|
|
4633
|
+
const shouldConnect = (_b = options2.shouldInitiallyConnect) != null ? _b : true;
|
|
4309
4634
|
if (shouldConnect) {
|
|
4310
4635
|
if (typeof atob === "undefined") {
|
|
4311
|
-
if (((
|
|
4636
|
+
if (((_c = clientOptions.polyfills) == null ? void 0 : _c.atob) === void 0) {
|
|
4312
4637
|
throw new Error(
|
|
4313
4638
|
"You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
|
|
4314
4639
|
);
|
|
4315
4640
|
}
|
|
4316
4641
|
global.atob = clientOptions.polyfills.atob;
|
|
4317
4642
|
}
|
|
4318
|
-
|
|
4643
|
+
newRoom.__internal.connect();
|
|
4319
4644
|
}
|
|
4320
|
-
return
|
|
4645
|
+
return newRoom;
|
|
4321
4646
|
}
|
|
4322
4647
|
function leave(roomId) {
|
|
4323
4648
|
unlinkDevTools(roomId);
|
|
4324
4649
|
const room = rooms.get(roomId);
|
|
4325
|
-
if (room) {
|
|
4326
|
-
room.disconnect();
|
|
4650
|
+
if (room !== void 0) {
|
|
4651
|
+
room.__internal.disconnect();
|
|
4327
4652
|
rooms.delete(roomId);
|
|
4328
4653
|
}
|
|
4329
4654
|
}
|
|
4330
|
-
if (typeof window !== "undefined" &&
|
|
4655
|
+
if (typeof window !== "undefined" && // istanbul ignore next: React Native environment doesn't implement window.addEventListener
|
|
4656
|
+
typeof window.addEventListener !== "undefined") {
|
|
4331
4657
|
window.addEventListener("online", () => {
|
|
4332
4658
|
for (const [, room] of rooms) {
|
|
4333
|
-
room.onNavigatorOnline();
|
|
4659
|
+
room.__internal.onNavigatorOnline();
|
|
4334
4660
|
}
|
|
4335
4661
|
});
|
|
4336
4662
|
}
|
|
4337
4663
|
if (typeof document !== "undefined") {
|
|
4338
4664
|
document.addEventListener("visibilitychange", () => {
|
|
4339
4665
|
for (const [, room] of rooms) {
|
|
4340
|
-
room.onVisibilityChange(document.visibilityState);
|
|
4666
|
+
room.__internal.onVisibilityChange(document.visibilityState);
|
|
4341
4667
|
}
|
|
4342
4668
|
});
|
|
4343
4669
|
}
|