@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.
Files changed (3) hide show
  1. package/dist/index.d.ts +13 -13
  2. package/dist/index.js +747 -421
  3. 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 ? "1.0.2" : "dev";
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] : (message, ...args) => console[method]("%cLiveblocks", badge, message, ...args);
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] : (title, message, ...args) => console[method](
270
- `%cLiveblocks%c ${title}`,
271
- badge,
272
- bold,
273
- message,
274
- ...args
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" ? (x) => x : Object.freeze;
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
- } : { type: 4 /* CREATE_OBJECT */, id: this._id, opId, data: {} };
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
- } : { type: 4 /* CREATE_OBJECT */, id, data: crdt.data }
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 (!first) {
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.state === "open" || connection.state === "connecting";
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(state, config, mockedEffects) {
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) => state.nodes.get(id),
2946
- addNode: (id, node) => void state.nodes.set(id, node),
2947
- deleteNode: (id) => void state.nodes.delete(id),
2948
- generateId: () => `${getConnectionId()}:${state.clock++}`,
2949
- generateOpId: () => `${getConnectionId()}:${state.opClock++}`,
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 = state.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(state.opStackTraces).set(op.opId, stackTrace);
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
- state.redoStack = [];
3321
+ context.redoStack = [];
2978
3322
  dispatchOps(ops);
2979
3323
  notify({ storageUpdates }, doNotBatchUpdates);
2980
3324
  });
2981
3325
  }
2982
3326
  },
2983
3327
  assertStorageIsWritable: () => {
2984
- if (isConnectionSelfAware(state.connection.current) && state.connection.current.isReadOnly) {
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 rawToken = state.token;
3005
- const parsedToken = rawToken !== null && parseRoomAuthToken(rawToken);
3006
- if (parsedToken && !isTokenExpired(parsedToken)) {
3007
- const socket = createWebSocket(rawToken);
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 (state.connection.current.state !== "authenticating") {
3355
+ if (context.connection.current.status !== "authenticating") {
3013
3356
  return;
3014
3357
  }
3015
- const parsedToken2 = parseRoomAuthToken(token);
3358
+ const parsedToken = parseRoomAuthToken(token);
3016
3359
  const socket = createWebSocket(token);
3017
- authenticationSuccess(parsedToken2, socket);
3018
- state.token = token;
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 (state.socket === null) {
3370
+ if (context.socket === null) {
3028
3371
  throw new Error("Can't send message if socket is null");
3029
3372
  }
3030
- state.socket.send(JSON.stringify(messageOrMessages));
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
- state.connection,
3047
- state.me,
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 (state.root) {
3407
+ if (context.root) {
3065
3408
  updateRoot(message.items, batchedUpdatesWrapper);
3066
3409
  } else {
3067
- state.root = load(message.items);
3410
+ context.root = load(message.items);
3068
3411
  }
3069
- for (const key in state.initialStorage) {
3070
- if (state.root.get(key) === void 0) {
3071
- state.root.set(key, state.initialStorage[key]);
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 (!state.root) {
3440
+ if (!context.root) {
3098
3441
  return;
3099
3442
  }
3100
3443
  const currentItems = /* @__PURE__ */ new Map();
3101
- state.nodes.forEach((node, id) => {
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 (state.undoStack.length >= 50) {
3114
- state.undoStack.shift();
3456
+ if (context.undoStack.length >= 50) {
3457
+ context.undoStack.shift();
3115
3458
  }
3116
- state.undoStack.push(historyOps);
3459
+ context.undoStack.push(historyOps);
3117
3460
  onHistoryChange(batchedUpdatesWrapper);
3118
3461
  }
3119
3462
  function addToUndoStack(historyOps, batchedUpdatesWrapper) {
3120
- if (state.pausedHistory !== null) {
3121
- state.pausedHistory.unshift(...historyOps);
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 = state.others.current;
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(state.me.current);
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 = state.connection.current;
3491
+ const conn = context.connection.current;
3149
3492
  if (isConnectionSelfAware(conn)) {
3150
3493
  return conn.id;
3151
- } else if (state.lastConnectionId !== null) {
3152
- return state.lastConnectionId;
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] = state.me.current[key];
3522
+ reverse.data[key] = context.me.current[key];
3180
3523
  }
3181
- state.me.patch(op.data);
3182
- if (state.buffer.me === null) {
3183
- state.buffer.me = { type: "partial", data: op.data };
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
- state.buffer.me.data[key] = op.data[key];
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(state.opStackTraces).delete(opId);
3541
+ nn(context.opStackTraces).delete(opId);
3199
3542
  }
3200
- const deleted = state.unacknowledgedOps.delete(opId);
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 = state.nodes.get(op.id);
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 = state.nodes.get(op.id);
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 = state.nodes.get(op.parentId);
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, _c, _d;
3356
- if (state.connection.current.state !== "closed" && state.connection.current.state !== "unavailable") {
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
- (_b = (_a2 = config.polyfills) == null ? void 0 : _a2.fetch) != null ? _b : config.fetchPolyfill
3621
+ (_a2 = config.polyfills) == null ? void 0 : _a2.fetch
3362
3622
  );
3363
3623
  const createWebSocket = prepareCreateWebSocket(
3364
3624
  config.liveblocksServer,
3365
- (_d = (_c = config.polyfills) == null ? void 0 : _c.WebSocket) != null ? _d : config.WebSocketPolyfill
3625
+ (_b = config.polyfills) == null ? void 0 : _b.WebSocket
3366
3626
  );
3367
- updateConnection({ state: "authenticating" }, batchUpdates);
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 (state.buffer.me === null) {
3373
- state.buffer.me = {
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
- state.buffer.me.data[key] = overrideValue;
3384
- oldValues[key] = state.me.current[key];
3643
+ context.buffer.me.data[key] = overrideValue;
3644
+ oldValues[key] = context.me.current[key];
3385
3645
  }
3386
- state.me.patch(patch);
3387
- if (state.activeBatch) {
3646
+ context.me.patch(patch);
3647
+ if (context.activeBatch) {
3388
3648
  if (options == null ? void 0 : options.addToHistory) {
3389
- state.activeBatch.reverseOps.unshift({
3649
+ context.activeBatch.reverseOps.unshift({
3390
3650
  type: "presence",
3391
3651
  data: oldValues
3392
3652
  });
3393
3653
  }
3394
- state.activeBatch.updates.presence = true;
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
- state: "connecting",
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
- state.idFactory = makeIdFactory(token.actor);
3427
- state.socket = socket;
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
- state.token = null;
3434
- updateConnection({ state: "unavailable" }, batchUpdates);
3435
- state.numberOfRetry++;
3436
- state.timeoutHandles.reconnect = effects.scheduleReconnect(getRetryDelay());
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" && state.connection.current.state === "open") {
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 = state.others.getUser(message.actor);
3447
- state.others.setOther(message.actor, message.data);
3448
- const newUser = state.others.getUser(message.actor);
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
- state.others.patchOther(message.actor, message.data), message;
3715
+ context.others.patchOther(message.actor, message.data), message;
3454
3716
  }
3455
- const user = state.others.getUser(message.actor);
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 = state.others.getUser(message.actor);
3729
+ const user = context.others.getUser(message.actor);
3468
3730
  if (user) {
3469
- state.others.removeConnection(message.actor);
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 state.others._connections) {
3737
+ for (const connectionId in context.others._connections) {
3476
3738
  const user = message.users[connectionId];
3477
3739
  if (user === void 0) {
3478
- state.others.removeConnection(Number(connectionId));
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
- state.others.setConnection(
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 (state.connection.current.state === "unavailable") {
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
- state.others.setConnection(
3767
+ context.others.setConnection(
3506
3768
  message.actor,
3507
3769
  message.id,
3508
3770
  message.info,
3509
3771
  isStorageReadOnly(message.scopes)
3510
3772
  );
3511
- state.buffer.messages.push({
3773
+ context.buffer.messages.push({
3512
3774
  type: 100 /* UPDATE_PRESENCE */,
3513
- data: state.me.current,
3775
+ data: context.me.current,
3514
3776
  targetActor: message.actor
3515
3777
  });
3516
3778
  tryFlushing();
3517
- const user = state.others.getUser(message.actor);
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(state.timeoutHandles.pongTimeout);
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(state.unacknowledgedOps);
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 = state.opStackTraces) == null ? void 0 : _a2.get(opId);
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
- state.socket = null;
3643
- clearTimeout(state.timeoutHandles.pongTimeout);
3644
- clearInterval(state.intervalHandles.heartbeat);
3645
- if (state.timeoutHandles.flush) {
3646
- clearTimeout(state.timeoutHandles.flush);
3647
- }
3648
- clearTimeout(state.timeoutHandles.reconnect);
3649
- state.others.clearOthers();
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({ state: "failed" }, doNotBatchUpdates);
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
- state.numberOfRetry++;
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({ state: "unavailable" }, doNotBatchUpdates);
3664
- state.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
3922
+ updateConnection({ status: "unavailable" }, doNotBatchUpdates);
3923
+ context.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
3665
3924
  } else if (event.code === 4999 /* CLOSE_WITHOUT_RETRY */) {
3666
- updateConnection({ state: "closed" }, doNotBatchUpdates);
3925
+ updateConnection({ status: "closed" }, doNotBatchUpdates);
3667
3926
  } else {
3668
3927
  const delay = getRetryDelay();
3669
- state.numberOfRetry++;
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({ state: "unavailable" }, doNotBatchUpdates);
3676
- state.timeoutHandles.reconnect = effects.scheduleReconnect(delay);
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
- state.connection.set(connection);
3940
+ context.connection.set(connection);
3682
3941
  batchedUpdatesWrapper(() => {
3683
- eventHub.connection.notify(connection.state);
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[state.numberOfRetry < BACKOFF_RETRY_DELAYS_SLOW.length ? state.numberOfRetry : BACKOFF_RETRY_DELAYS_SLOW.length - 1];
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[state.numberOfRetry < BACKOFF_RETRY_DELAYS.length ? state.numberOfRetry : BACKOFF_RETRY_DELAYS.length - 1];
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(state.intervalHandles.heartbeat);
3696
- state.intervalHandles.heartbeat = effects.startHeartbeatInterval();
3697
- if (state.connection.current.state === "connecting") {
3954
+ clearInterval(context.intervalHandles.heartbeat);
3955
+ context.intervalHandles.heartbeat = effects.startHeartbeatInterval();
3956
+ if (context.connection.current.status === "connecting") {
3698
3957
  updateConnection(
3699
- __spreadProps(__spreadValues({}, state.connection.current), { state: "open" }),
3958
+ __spreadProps(__spreadValues({}, context.connection.current), { status: "open" }),
3700
3959
  batchUpdates
3701
3960
  );
3702
- state.numberOfRetry = 0;
3703
- if (state.lastConnectionId !== void 0) {
3704
- state.buffer.me = {
3961
+ context.numberOfRetry = 0;
3962
+ if (context.lastConnectionId !== void 0) {
3963
+ context.buffer.me = {
3705
3964
  type: "full",
3706
- data: __spreadValues({}, state.me.current)
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
- state.lastConnectionId = state.connection.current.id;
3711
- if (state.root) {
3712
- state.buffer.messages.push({ type: 200 /* FETCH_STORAGE */ });
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 (state.socket === null) {
3983
+ if (context.socket === null) {
3720
3984
  return;
3721
3985
  }
3722
- clearTimeout(state.timeoutHandles.pongTimeout);
3723
- state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
3724
- if (state.socket.readyState === state.socket.OPEN) {
3725
- state.socket.send("ping");
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 (state.socket) {
3734
- state.socket.removeEventListener("open", onOpen);
3735
- state.socket.removeEventListener("message", onMessage);
3736
- state.socket.removeEventListener("close", onClose);
3737
- state.socket.removeEventListener("error", onError);
3738
- state.socket.close();
3739
- state.socket = null;
3740
- }
3741
- updateConnection({ state: "unavailable" }, batchUpdates);
3742
- clearTimeout(state.timeoutHandles.pongTimeout);
3743
- if (state.timeoutHandles.flush) {
3744
- clearTimeout(state.timeoutHandles.flush);
3745
- }
3746
- clearTimeout(state.timeoutHandles.reconnect);
3747
- clearInterval(state.intervalHandles.heartbeat);
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 = state.buffer.storageOperations;
4029
+ const storageOps = context.buffer.storageOperations;
3766
4030
  if (storageOps.length > 0) {
3767
4031
  storageOps.forEach((op) => {
3768
- state.unacknowledgedOps.set(nn(op.opId), op);
4032
+ context.unacknowledgedOps.set(nn(op.opId), op);
3769
4033
  });
3770
4034
  notifyStorageStatus();
3771
4035
  }
3772
- if (state.socket === null || state.socket.readyState !== state.socket.OPEN) {
3773
- state.buffer.storageOperations = [];
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 - state.lastFlushTime;
4041
+ const elapsedTime = now - context.lastFlushTime;
3778
4042
  if (elapsedTime > config.throttleDelay) {
3779
- const messages = flushDataToMessages(state);
4043
+ const messages = flushDataToMessages(context);
3780
4044
  if (messages.length === 0) {
3781
4045
  return;
3782
4046
  }
3783
4047
  effects.send(messages);
3784
- state.buffer = {
4048
+ context.buffer = {
3785
4049
  messages: [],
3786
4050
  storageOperations: [],
3787
4051
  me: null
3788
4052
  };
3789
- state.lastFlushTime = now;
4053
+ context.lastFlushTime = now;
3790
4054
  } else {
3791
- if (state.timeoutHandles.flush !== null) {
3792
- clearTimeout(state.timeoutHandles.flush);
4055
+ if (context.timeoutHandles.flush !== null) {
4056
+ clearTimeout(context.timeoutHandles.flush);
3793
4057
  }
3794
- state.timeoutHandles.flush = effects.delayFlush(
3795
- config.throttleDelay - (now - state.lastFlushTime)
4058
+ context.timeoutHandles.flush = effects.delayFlush(
4059
+ config.throttleDelay - (now - context.lastFlushTime)
3796
4060
  );
3797
4061
  }
3798
4062
  }
3799
- function flushDataToMessages(state2) {
4063
+ function flushDataToMessages(state) {
3800
4064
  const messages = [];
3801
- if (state2.buffer.me) {
4065
+ if (state.buffer.me) {
3802
4066
  messages.push(
3803
- state2.buffer.me.type === "full" ? {
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: state2.buffer.me.data
4073
+ data: state.buffer.me.data
3807
4074
  } : {
3808
4075
  type: 100 /* UPDATE_PRESENCE */,
3809
- data: state2.buffer.me.data
4076
+ data: state.buffer.me.data
3810
4077
  }
3811
4078
  );
3812
4079
  }
3813
- for (const event of state2.buffer.messages) {
4080
+ for (const event of state.buffer.messages) {
3814
4081
  messages.push(event);
3815
4082
  }
3816
- if (state2.buffer.storageOperations.length > 0) {
4083
+ if (state.buffer.storageOperations.length > 0) {
3817
4084
  messages.push({
3818
4085
  type: 201 /* UPDATE_STORAGE */,
3819
- ops: state2.buffer.storageOperations
4086
+ ops: state.buffer.storageOperations
3820
4087
  });
3821
4088
  }
3822
4089
  return messages;
3823
4090
  }
3824
4091
  function disconnect() {
3825
- if (state.socket) {
3826
- state.socket.removeEventListener("open", onOpen);
3827
- state.socket.removeEventListener("message", onMessage);
3828
- state.socket.removeEventListener("close", onClose);
3829
- state.socket.removeEventListener("error", onError);
3830
- state.socket.close();
3831
- state.socket = null;
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({ state: "closed" }, doNotBatchUpdates);
3835
- if (state.timeoutHandles.flush) {
3836
- clearTimeout(state.timeoutHandles.flush);
4101
+ updateConnection({ status: "closed" }, doNotBatchUpdates);
4102
+ if (context.timeoutHandles.flush) {
4103
+ clearTimeout(context.timeoutHandles.flush);
3837
4104
  }
3838
- clearTimeout(state.timeoutHandles.reconnect);
3839
- clearTimeout(state.timeoutHandles.pongTimeout);
3840
- clearInterval(state.intervalHandles.heartbeat);
3841
- state.others.clearOthers();
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 (state.socket === null && !options.shouldQueueEventIfNotReady) {
4116
+ if (context.socket === null && !options.shouldQueueEventIfNotReady) {
3856
4117
  return;
3857
4118
  }
3858
- state.buffer.messages.push({
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
- state.buffer.storageOperations.push(...ops);
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
- state.buffer.messages.push({ type: 200 /* FETCH_STORAGE */ });
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 = state.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 (state.root) {
4153
+ if (context.root) {
3893
4154
  return Promise.resolve({
3894
- root: state.root
4155
+ root: context.root
3895
4156
  });
3896
4157
  }
3897
4158
  yield startLoadingStorage();
3898
4159
  return {
3899
- root: nn(state.root)
4160
+ root: nn(context.root)
3900
4161
  };
3901
4162
  });
3902
4163
  }
3903
4164
  function undo() {
3904
- if (state.activeBatch) {
4165
+ if (context.activeBatch) {
3905
4166
  throw new Error("undo is not allowed during a batch");
3906
4167
  }
3907
- const historyOps = state.undoStack.pop();
4168
+ const historyOps = context.undoStack.pop();
3908
4169
  if (historyOps === void 0) {
3909
4170
  return;
3910
4171
  }
3911
- state.pausedHistory = null;
4172
+ context.pausedHistory = null;
3912
4173
  const result = applyOps(historyOps, true);
3913
4174
  batchUpdates(() => {
3914
4175
  notify(result.updates, doNotBatchUpdates);
3915
- state.redoStack.push(result.reverse);
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
- state.buffer.storageOperations.push(op);
4181
+ context.buffer.storageOperations.push(op);
3921
4182
  }
3922
4183
  }
3923
4184
  tryFlushing();
3924
4185
  }
3925
4186
  function canUndo() {
3926
- return state.undoStack.length > 0;
4187
+ return context.undoStack.length > 0;
3927
4188
  }
3928
4189
  function redo() {
3929
- if (state.activeBatch) {
4190
+ if (context.activeBatch) {
3930
4191
  throw new Error("redo is not allowed during a batch");
3931
4192
  }
3932
- const historyOps = state.redoStack.pop();
4193
+ const historyOps = context.redoStack.pop();
3933
4194
  if (historyOps === void 0) {
3934
4195
  return;
3935
4196
  }
3936
- state.pausedHistory = null;
4197
+ context.pausedHistory = null;
3937
4198
  const result = applyOps(historyOps, true);
3938
4199
  batchUpdates(() => {
3939
4200
  notify(result.updates, doNotBatchUpdates);
3940
- state.undoStack.push(result.reverse);
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
- state.buffer.storageOperations.push(op);
4206
+ context.buffer.storageOperations.push(op);
3946
4207
  }
3947
4208
  }
3948
4209
  tryFlushing();
3949
4210
  }
3950
4211
  function canRedo() {
3951
- return state.redoStack.length > 0;
4212
+ return context.redoStack.length > 0;
3952
4213
  }
3953
4214
  function batch(callback) {
3954
- if (state.activeBatch) {
4215
+ if (context.activeBatch) {
3955
4216
  return callback();
3956
4217
  }
3957
4218
  let returnValue = void 0;
3958
4219
  batchUpdates(() => {
3959
- state.activeBatch = {
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 = state.activeBatch;
3972
- state.activeBatch = null;
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
- state.redoStack = [];
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
- state.pausedHistory = [];
4250
+ context.pausedHistory = [];
3990
4251
  }
3991
4252
  function resumeHistory() {
3992
- const historyOps = state.pausedHistory;
3993
- state.pausedHistory = null;
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 (state.socket) {
4000
- state.socket = null;
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 (state.root === void 0) {
4271
+ if (context.root === void 0) {
4011
4272
  return "loading";
4012
4273
  }
4013
- return state.unacknowledgedOps.size === 0 ? "synchronized" : "synchronizing";
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: () => state.undoStack,
4033
- getItemsCount: () => state.nodes.size,
4302
+ getUndoStack: () => context.undoStack,
4303
+ getItemsCount: () => context.nodes.size,
4304
+ // Core
4034
4305
  connect,
4035
4306
  disconnect,
4036
4307
  reconnect,
4037
- subscribe,
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
- getConnectionState,
4062
- isSelfAware: () => isConnectionSelfAware(state.connection.current),
4333
+ // Core
4334
+ getConnectionState: () => context.connection.current.status,
4335
+ isSelfAware: () => isConnectionSelfAware(context.connection.current),
4063
4336
  getSelf: () => self.current,
4064
- getPresence,
4065
- getOthers,
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: () => state.others_forDevTools.current
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 state = defaultState(
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.subscribe,
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
- __INTERNAL_DO_NOT_USE: {
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
- getSelf_forDevTools: machine.getSelf_forDevTools,
4156
- getOthers_forDevTools: machine.getOthers_forDevTools
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=${true ? "1.0.2" : "dev"}`
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 || fetch,
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(options);
4596
+ const throttleDelay = getThrottleDelayFromOptions(clientOptions);
4271
4597
  const rooms = /* @__PURE__ */ new Map();
4272
4598
  function getRoom(roomId) {
4273
- const internalRoom = rooms.get(roomId);
4274
- return internalRoom ? internalRoom.room : null;
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 shouldConnect = options2.shouldInitiallyConnect === void 0 ? true : options2.shouldInitiallyConnect;
4279
- let internalRoom = rooms.get(roomId);
4280
- if (internalRoom) {
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
- internalRoom = createRoom(
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: (clientOptions == null ? void 0 : clientOptions.liveblocksServer) || "wss://api.liveblocks.io/v6",
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, internalRoom.room);
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 (((_b = clientOptions.polyfills) == null ? void 0 : _b.atob) === void 0) {
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
- internalRoom.connect();
4643
+ newRoom.__internal.connect();
4319
4644
  }
4320
- return internalRoom.room;
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" && typeof window.addEventListener !== "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
  }