@liveblocks/core 3.14.0-pre3 → 3.14.0-pre5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "3.14.0-pre3";
9
+ var PKG_VERSION = "3.14.0-pre5";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -567,6 +567,9 @@ var SortedList = class _SortedList {
567
567
  this.#lt = lt;
568
568
  this.#data = alreadySortedList;
569
569
  }
570
+ /**
571
+ * Creates an empty SortedList with the given "less than" function.
572
+ */
570
573
  static with(lt) {
571
574
  return _SortedList.fromAlreadySorted([], lt);
572
575
  }
@@ -588,10 +591,12 @@ var SortedList = class _SortedList {
588
591
  }
589
592
  /**
590
593
  * Adds a new item to the sorted list, such that it remains sorted.
594
+ * Returns the index where the item was inserted.
591
595
  */
592
596
  add(value) {
593
597
  const idx = bisectRight(this.#data, value, this.#lt);
594
598
  this.#data.splice(idx, 0, value);
599
+ return idx;
595
600
  }
596
601
  /**
597
602
  * Removes all values from the sorted list, making it empty again.
@@ -636,6 +641,60 @@ var SortedList = class _SortedList {
636
641
  }
637
642
  return false;
638
643
  }
644
+ /**
645
+ * Removes the item at the given index.
646
+ * Returns the removed item, or undefined if index is out of bounds.
647
+ */
648
+ removeAt(index) {
649
+ if (index < 0 || index >= this.#data.length) {
650
+ return void 0;
651
+ }
652
+ const [removed] = this.#data.splice(index, 1);
653
+ return removed;
654
+ }
655
+ /**
656
+ * Repositions an item to maintain sorted order after its sort key has
657
+ * been mutated in-place. For example:
658
+ *
659
+ * const item = sorted.at(3);
660
+ * item.updatedAt = new Date(); // mutate the item's sort key in-place
661
+ * sorted.reposition(item); // restore sorted order
662
+ *
663
+ * Returns the new index of the item. Throws if the item is not in the list.
664
+ *
665
+ * Semantically equivalent to remove(value) + add(value), but optimized
666
+ * to avoid array shifting when the item only moves a short distance.
667
+ */
668
+ reposition(value) {
669
+ const oldIdx = this.#data.indexOf(value);
670
+ if (oldIdx < 0) {
671
+ throw new Error("Cannot reposition item that is not in the list");
672
+ }
673
+ const prev = this.#data[oldIdx - 1];
674
+ const next = this.#data[oldIdx + 1];
675
+ const validLeft = prev === void 0 || this.#lt(prev, value);
676
+ const validRight = next === void 0 || this.#lt(value, next);
677
+ if (validLeft && validRight) {
678
+ return oldIdx;
679
+ }
680
+ let newIdx = oldIdx;
681
+ while (newIdx > 0 && this.#lt(value, this.#data[newIdx - 1])) {
682
+ this.#data[newIdx] = this.#data[newIdx - 1];
683
+ newIdx--;
684
+ }
685
+ if (newIdx < oldIdx) {
686
+ this.#data[newIdx] = value;
687
+ return newIdx;
688
+ }
689
+ while (newIdx < this.#data.length - 1 && !this.#lt(value, this.#data[newIdx + 1])) {
690
+ this.#data[newIdx] = this.#data[newIdx + 1];
691
+ newIdx++;
692
+ }
693
+ if (newIdx !== oldIdx) {
694
+ this.#data[newIdx] = value;
695
+ }
696
+ return newIdx;
697
+ }
639
698
  at(index) {
640
699
  return this.#data[index];
641
700
  }
@@ -5898,16 +5957,68 @@ function before(pos) {
5898
5957
  }
5899
5958
  return ONE;
5900
5959
  }
5960
+ var VIEWPORT_START = 2;
5961
+ var VIEWPORT_STEP = 3;
5901
5962
  function after(pos) {
5902
- for (let i = 0; i <= pos.length - 1; i++) {
5963
+ for (let i = 0; i < pos.length; i++) {
5903
5964
  const code = pos.charCodeAt(i);
5904
- if (code >= MAX_CODE) {
5905
- continue;
5965
+ if (code < MIN_CODE || code > MAX_CODE) {
5966
+ return pos + ONE;
5906
5967
  }
5907
- return pos.substring(0, i) + String.fromCharCode(code + 1);
5968
+ }
5969
+ while (pos.length > 1 && pos.charCodeAt(pos.length - 1) === MIN_CODE) {
5970
+ pos = pos.slice(0, -1);
5971
+ }
5972
+ if (pos.length === 0 || pos === ZERO) {
5973
+ return ONE;
5974
+ }
5975
+ let viewport = VIEWPORT_START;
5976
+ if (pos.length > VIEWPORT_START) {
5977
+ viewport = VIEWPORT_START + Math.ceil((pos.length - VIEWPORT_START) / VIEWPORT_STEP) * VIEWPORT_STEP;
5978
+ }
5979
+ const result = incrementWithinViewport(pos, viewport);
5980
+ if (result !== null) {
5981
+ return result;
5982
+ }
5983
+ viewport += VIEWPORT_STEP;
5984
+ const extendedResult = incrementWithinViewport(pos, viewport);
5985
+ if (extendedResult !== null) {
5986
+ return extendedResult;
5908
5987
  }
5909
5988
  return pos + ONE;
5910
5989
  }
5990
+ function incrementWithinViewport(pos, viewport) {
5991
+ const digits = [];
5992
+ for (let i = 0; i < viewport; i++) {
5993
+ if (i < pos.length) {
5994
+ digits.push(pos.charCodeAt(i) - MIN_CODE);
5995
+ } else {
5996
+ digits.push(0);
5997
+ }
5998
+ }
5999
+ let carry = 1;
6000
+ for (let i = viewport - 1; i >= 0 && carry; i--) {
6001
+ const sum = digits[i] + carry;
6002
+ if (sum >= NUM_DIGITS) {
6003
+ digits[i] = 0;
6004
+ carry = 1;
6005
+ } else {
6006
+ digits[i] = sum;
6007
+ carry = 0;
6008
+ }
6009
+ }
6010
+ if (carry) {
6011
+ return null;
6012
+ }
6013
+ let result = "";
6014
+ for (const d of digits) {
6015
+ result += String.fromCharCode(d + MIN_CODE);
6016
+ }
6017
+ while (result.length > 1 && result.charCodeAt(result.length - 1) === MIN_CODE) {
6018
+ result = result.slice(0, -1);
6019
+ }
6020
+ return result;
6021
+ }
5911
6022
  function between(lo, hi) {
5912
6023
  if (lo < hi) {
5913
6024
  return _between(lo, hi);
@@ -6368,29 +6479,27 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
6368
6479
  };
6369
6480
 
6370
6481
  // src/crdts/LiveList.ts
6371
- function compareNodePosition(itemA, itemB) {
6372
- const posA = itemA._parentPos;
6373
- const posB = itemB._parentPos;
6374
- return posA === posB ? 0 : posA < posB ? -1 : 1;
6482
+ function childNodeLt(a, b) {
6483
+ return a._parentPos < b._parentPos;
6375
6484
  }
6376
6485
  var LiveList = class _LiveList extends AbstractCrdt {
6377
- // TODO: Naive array at first, find a better data structure. Maybe an Order statistics tree?
6378
6486
  #items;
6379
6487
  #implicitlyDeletedItems;
6380
6488
  #unacknowledgedSets;
6381
6489
  constructor(items) {
6382
6490
  super();
6383
- this.#items = [];
6384
6491
  this.#implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
6385
6492
  this.#unacknowledgedSets = /* @__PURE__ */ new Map();
6386
- let position = void 0;
6493
+ const nodes = [];
6494
+ let lastPos;
6387
6495
  for (const item of items) {
6388
- const newPosition = makePosition(position);
6496
+ const pos = makePosition(lastPos);
6389
6497
  const node = lsonToLiveNode(item);
6390
- node._setParentLink(this, newPosition);
6391
- this.#items.push(node);
6392
- position = newPosition;
6498
+ node._setParentLink(this, pos);
6499
+ nodes.push(node);
6500
+ lastPos = pos;
6393
6501
  }
6502
+ this.#items = SortedList.fromAlreadySorted(nodes, childNodeLt);
6394
6503
  }
6395
6504
  /** @internal */
6396
6505
  static _deserialize([id, _], parentToChildren, pool) {
@@ -6404,7 +6513,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6404
6513
  const crdt = node[1];
6405
6514
  const child = deserialize(node, parentToChildren, pool);
6406
6515
  child._setParentLink(list, crdt.parentKey);
6407
- list._insertAndSort(child);
6516
+ list.#insert(child);
6408
6517
  }
6409
6518
  return list;
6410
6519
  }
@@ -6440,19 +6549,33 @@ var LiveList = class _LiveList extends AbstractCrdt {
6440
6549
  return ops;
6441
6550
  }
6442
6551
  /**
6443
- * @internal
6444
- *
6445
- * Adds a new item into the sorted list, in the correct position.
6552
+ * Inserts a new child into the list in the correct location (binary search
6553
+ * finds correct position efficiently). Returns the insertion index.
6446
6554
  */
6447
- _insertAndSort(item) {
6448
- this.#items.push(item);
6449
- this._sortItems();
6555
+ #insert(childNode) {
6556
+ const index = this.#items.add(childNode);
6557
+ this.invalidate();
6558
+ return index;
6450
6559
  }
6451
- /** @internal */
6452
- _sortItems() {
6453
- this.#items.sort(compareNodePosition);
6560
+ /**
6561
+ * Updates an item's position and repositions it in the sorted list.
6562
+ * Encapsulates the remove -> mutate -> add cycle needed when changing sort keys.
6563
+ *
6564
+ * IMPORTANT: Item must exist in this list. List count remains unchanged.
6565
+ */
6566
+ #updateItemPosition(item, newKey) {
6567
+ item._setParentLink(this, newKey);
6568
+ this.#items.reposition(item);
6454
6569
  this.invalidate();
6455
6570
  }
6571
+ /**
6572
+ * Updates an item's position by index. Safer than #updateItemPosition when you have
6573
+ * an index, as it ensures the item exists and is from this list.
6574
+ */
6575
+ #updateItemPositionAt(index, newKey) {
6576
+ const item = nn(this.#items.at(index));
6577
+ this.#updateItemPosition(item, newKey);
6578
+ }
6456
6579
  /** @internal */
6457
6580
  _indexOfPosition(position) {
6458
6581
  return this.#items.findIndex(
@@ -6484,10 +6607,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
6484
6607
  const deletedId = op.deletedId;
6485
6608
  const indexOfItemWithSamePosition = this._indexOfPosition(key);
6486
6609
  if (indexOfItemWithSamePosition !== -1) {
6487
- const itemWithSamePosition = this.#items[indexOfItemWithSamePosition];
6610
+ const itemWithSamePosition = nn(
6611
+ this.#items.removeAt(indexOfItemWithSamePosition)
6612
+ );
6488
6613
  if (itemWithSamePosition._id === deletedId) {
6489
6614
  itemWithSamePosition._detach();
6490
- this.#items[indexOfItemWithSamePosition] = child;
6615
+ this.#items.add(child);
6491
6616
  return {
6492
6617
  modified: makeUpdate(this, [
6493
6618
  setDelta(indexOfItemWithSamePosition, child)
@@ -6496,7 +6621,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
6496
6621
  };
6497
6622
  } else {
6498
6623
  this.#implicitlyDeletedItems.add(itemWithSamePosition);
6499
- this.#items[indexOfItemWithSamePosition] = child;
6624
+ this.#items.remove(itemWithSamePosition);
6625
+ this.#items.add(child);
6500
6626
  const delta = [
6501
6627
  setDelta(indexOfItemWithSamePosition, child)
6502
6628
  ];
@@ -6519,7 +6645,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6519
6645
  if (deleteDelta2) {
6520
6646
  updates.push(deleteDelta2);
6521
6647
  }
6522
- this._insertAndSort(child);
6648
+ this.#insert(child);
6523
6649
  updates.push(insertDelta(this._indexOfPosition(key), child));
6524
6650
  return {
6525
6651
  reverse: [],
@@ -6554,16 +6680,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
6554
6680
  };
6555
6681
  }
6556
6682
  if (indexOfItemWithSamePosition !== -1) {
6557
- this.#implicitlyDeletedItems.add(
6558
- this.#items[indexOfItemWithSamePosition]
6683
+ const itemAtPosition = nn(
6684
+ this.#items.removeAt(indexOfItemWithSamePosition)
6559
6685
  );
6560
- const [prevNode] = this.#items.splice(indexOfItemWithSamePosition, 1);
6561
- delta.push(deleteDelta(indexOfItemWithSamePosition, prevNode));
6686
+ this.#implicitlyDeletedItems.add(itemAtPosition);
6687
+ delta.push(deleteDelta(indexOfItemWithSamePosition, itemAtPosition));
6562
6688
  }
6563
- const prevIndex = this.#items.indexOf(existingItem);
6564
- existingItem._setParentLink(this, op.parentKey);
6565
- this._sortItems();
6566
- const newIndex = this.#items.indexOf(existingItem);
6689
+ const prevIndex = this.#items.findIndex((item) => item === existingItem);
6690
+ this.#updateItemPosition(existingItem, op.parentKey);
6691
+ const newIndex = this.#items.findIndex((item) => item === existingItem);
6567
6692
  if (newIndex !== prevIndex) {
6568
6693
  delta.push(moveDelta(prevIndex, newIndex, existingItem));
6569
6694
  }
@@ -6576,8 +6701,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6576
6701
  if (orphan && this.#implicitlyDeletedItems.has(orphan)) {
6577
6702
  orphan._setParentLink(this, op.parentKey);
6578
6703
  this.#implicitlyDeletedItems.delete(orphan);
6579
- this._insertAndSort(orphan);
6580
- const recreatedItemIndex = this.#items.indexOf(orphan);
6704
+ const recreatedItemIndex = this.#insert(orphan);
6581
6705
  return {
6582
6706
  modified: makeUpdate(this, [
6583
6707
  // If there is an item at this position, update is a set, else it's an insert
@@ -6588,7 +6712,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6588
6712
  };
6589
6713
  } else {
6590
6714
  if (indexOfItemWithSamePosition !== -1) {
6591
- this.#items.splice(indexOfItemWithSamePosition, 1);
6715
+ nn(this.#items.removeAt(indexOfItemWithSamePosition));
6592
6716
  }
6593
6717
  const { newItem, newIndex } = this.#createAttachItemAndSort(
6594
6718
  op,
@@ -6647,12 +6771,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
6647
6771
  modified: false
6648
6772
  };
6649
6773
  } else {
6650
- const oldPositionIndex = this.#items.indexOf(existingItem);
6774
+ const oldPositionIndex = this.#items.findIndex(
6775
+ (item) => item === existingItem
6776
+ );
6651
6777
  if (itemIndexAtPosition !== -1) {
6652
6778
  this.#shiftItemPosition(itemIndexAtPosition, key);
6653
6779
  }
6654
- existingItem._setParentLink(this, key);
6655
- this._sortItems();
6780
+ this.#updateItemPosition(existingItem, key);
6656
6781
  const newIndex = this._indexOfPosition(key);
6657
6782
  if (newIndex === oldPositionIndex) {
6658
6783
  return { modified: false };
@@ -6669,7 +6794,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6669
6794
  if (orphan && this.#implicitlyDeletedItems.has(orphan)) {
6670
6795
  orphan._setParentLink(this, key);
6671
6796
  this.#implicitlyDeletedItems.delete(orphan);
6672
- this._insertAndSort(orphan);
6797
+ this.#insert(orphan);
6673
6798
  const newIndex = this._indexOfPosition(key);
6674
6799
  return {
6675
6800
  modified: makeUpdate(this, [insertDelta(newIndex, orphan)]),
@@ -6698,12 +6823,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
6698
6823
  const existingItemIndex = this._indexOfPosition(key);
6699
6824
  let newKey = key;
6700
6825
  if (existingItemIndex !== -1) {
6701
- const before2 = _optionalChain([this, 'access', _118 => _118.#items, 'access', _119 => _119[existingItemIndex], 'optionalAccess', _120 => _120._parentPos]);
6702
- const after2 = _optionalChain([this, 'access', _121 => _121.#items, 'access', _122 => _122[existingItemIndex + 1], 'optionalAccess', _123 => _123._parentPos]);
6826
+ const before2 = _optionalChain([this, 'access', _118 => _118.#items, 'access', _119 => _119.at, 'call', _120 => _120(existingItemIndex), 'optionalAccess', _121 => _121._parentPos]);
6827
+ const after2 = _optionalChain([this, 'access', _122 => _122.#items, 'access', _123 => _123.at, 'call', _124 => _124(existingItemIndex + 1), 'optionalAccess', _125 => _125._parentPos]);
6703
6828
  newKey = makePosition(before2, after2);
6704
6829
  child._setParentLink(this, newKey);
6705
6830
  }
6706
- this._insertAndSort(child);
6831
+ this.#insert(child);
6707
6832
  const newIndex = this._indexOfPosition(newKey);
6708
6833
  return {
6709
6834
  modified: makeUpdate(this, [insertDelta(newIndex, child)]),
@@ -6713,7 +6838,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6713
6838
  #applySetUndoRedo(op) {
6714
6839
  const { id, parentKey: key } = op;
6715
6840
  const child = creationOpToLiveNode(op);
6716
- if (_optionalChain([this, 'access', _124 => _124._pool, 'optionalAccess', _125 => _125.getNode, 'call', _126 => _126(id)]) !== void 0) {
6841
+ if (_optionalChain([this, 'access', _126 => _126._pool, 'optionalAccess', _127 => _127.getNode, 'call', _128 => _128(id)]) !== void 0) {
6717
6842
  return { modified: false };
6718
6843
  }
6719
6844
  this.#unacknowledgedSets.set(key, nn(op.opId));
@@ -6722,9 +6847,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
6722
6847
  child._setParentLink(this, key);
6723
6848
  const newKey = key;
6724
6849
  if (indexOfItemWithSameKey !== -1) {
6725
- const existingItem = this.#items[indexOfItemWithSameKey];
6850
+ const existingItem = this.#items.at(indexOfItemWithSameKey);
6726
6851
  existingItem._detach();
6727
- this.#items[indexOfItemWithSameKey] = child;
6852
+ this.#items.remove(existingItem);
6853
+ this.#items.add(child);
6728
6854
  const reverse = HACK_addIntentAndDeletedIdToOperation(
6729
6855
  existingItem._toOps(nn(this._id), key),
6730
6856
  op.id
@@ -6741,7 +6867,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6741
6867
  reverse
6742
6868
  };
6743
6869
  } else {
6744
- this._insertAndSort(child);
6870
+ this.#insert(child);
6745
6871
  this.#detachItemAssociatedToSetOperation(op.deletedId);
6746
6872
  const newIndex = this._indexOfPosition(newKey);
6747
6873
  return {
@@ -6783,13 +6909,14 @@ var LiveList = class _LiveList extends AbstractCrdt {
6783
6909
  if (child) {
6784
6910
  const parentKey = nn(child._parentKey);
6785
6911
  const reverse = child._toOps(nn(this._id), parentKey);
6786
- const indexToDelete = this.#items.indexOf(child);
6912
+ const indexToDelete = this.#items.findIndex((item) => item === child);
6787
6913
  if (indexToDelete === -1) {
6788
6914
  return {
6789
6915
  modified: false
6790
6916
  };
6791
6917
  }
6792
- const [previousNode] = this.#items.splice(indexToDelete, 1);
6918
+ const previousNode = this.#items.at(indexToDelete);
6919
+ this.#items.remove(child);
6793
6920
  this.invalidate();
6794
6921
  child._detach();
6795
6922
  return {
@@ -6803,8 +6930,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6803
6930
  if (this.#implicitlyDeletedItems.has(child)) {
6804
6931
  this.#implicitlyDeletedItems.delete(child);
6805
6932
  child._setParentLink(this, newKey);
6806
- this._insertAndSort(child);
6807
- const newIndex = this.#items.indexOf(child);
6933
+ const newIndex = this.#insert(child);
6808
6934
  return {
6809
6935
  modified: makeUpdate(this, [insertDelta(newIndex, child)]),
6810
6936
  reverse: []
@@ -6818,10 +6944,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
6818
6944
  }
6819
6945
  const existingItemIndex = this._indexOfPosition(newKey);
6820
6946
  if (existingItemIndex === -1) {
6821
- const previousIndex = this.#items.indexOf(child);
6822
- child._setParentLink(this, newKey);
6823
- this._sortItems();
6824
- const newIndex = this.#items.indexOf(child);
6947
+ const previousIndex = this.#items.findIndex((item) => item === child);
6948
+ this.#updateItemPosition(child, newKey);
6949
+ const newIndex = this.#items.findIndex((item) => item === child);
6825
6950
  if (newIndex === previousIndex) {
6826
6951
  return {
6827
6952
  modified: false
@@ -6832,14 +6957,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
6832
6957
  reverse: []
6833
6958
  };
6834
6959
  } else {
6835
- this.#items[existingItemIndex]._setParentLink(
6836
- this,
6837
- makePosition(newKey, _optionalChain([this, 'access', _127 => _127.#items, 'access', _128 => _128[existingItemIndex + 1], 'optionalAccess', _129 => _129._parentPos]))
6960
+ this.#updateItemPositionAt(
6961
+ existingItemIndex,
6962
+ makePosition(newKey, _optionalChain([this, 'access', _129 => _129.#items, 'access', _130 => _130.at, 'call', _131 => _131(existingItemIndex + 1), 'optionalAccess', _132 => _132._parentPos]))
6838
6963
  );
6839
- const previousIndex = this.#items.indexOf(child);
6840
- child._setParentLink(this, newKey);
6841
- this._sortItems();
6842
- const newIndex = this.#items.indexOf(child);
6964
+ const previousIndex = this.#items.findIndex((item) => item === child);
6965
+ this.#updateItemPosition(child, newKey);
6966
+ const newIndex = this.#items.findIndex((item) => item === child);
6843
6967
  if (newIndex === previousIndex) {
6844
6968
  return {
6845
6969
  modified: false
@@ -6857,14 +6981,18 @@ var LiveList = class _LiveList extends AbstractCrdt {
6857
6981
  const existingItemIndex = this._indexOfPosition(newKey);
6858
6982
  this.#implicitlyDeletedItems.delete(child);
6859
6983
  if (existingItemIndex !== -1) {
6860
- this.#items[existingItemIndex]._setParentLink(
6984
+ const existingItem = this.#items.at(existingItemIndex);
6985
+ existingItem._setParentLink(
6861
6986
  this,
6862
- makePosition(newKey, _optionalChain([this, 'access', _130 => _130.#items, 'access', _131 => _131[existingItemIndex + 1], 'optionalAccess', _132 => _132._parentPos]))
6987
+ makePosition(
6988
+ newKey,
6989
+ _optionalChain([this, 'access', _133 => _133.#items, 'access', _134 => _134.at, 'call', _135 => _135(existingItemIndex + 1), 'optionalAccess', _136 => _136._parentPos])
6990
+ )
6863
6991
  );
6992
+ this.#items.reposition(existingItem);
6864
6993
  }
6865
6994
  child._setParentLink(this, newKey);
6866
- this._insertAndSort(child);
6867
- const newIndex = this.#items.indexOf(child);
6995
+ const newIndex = this.#insert(child);
6868
6996
  return {
6869
6997
  modified: makeUpdate(this, [insertDelta(newIndex, child)]),
6870
6998
  reverse: []
@@ -6875,17 +7003,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
6875
7003
  modified: false
6876
7004
  };
6877
7005
  }
6878
- const previousIndex = this.#items.indexOf(child);
7006
+ const previousIndex = this.#items.findIndex((item) => item === child);
6879
7007
  const existingItemIndex = this._indexOfPosition(newKey);
6880
7008
  if (existingItemIndex !== -1) {
6881
- this.#items[existingItemIndex]._setParentLink(
6882
- this,
6883
- makePosition(newKey, _optionalChain([this, 'access', _133 => _133.#items, 'access', _134 => _134[existingItemIndex + 1], 'optionalAccess', _135 => _135._parentPos]))
7009
+ this.#updateItemPositionAt(
7010
+ existingItemIndex,
7011
+ makePosition(
7012
+ newKey,
7013
+ _optionalChain([this, 'access', _137 => _137.#items, 'access', _138 => _138.at, 'call', _139 => _139(existingItemIndex + 1), 'optionalAccess', _140 => _140._parentPos])
7014
+ )
6884
7015
  );
6885
7016
  }
6886
- child._setParentLink(this, newKey);
6887
- this._sortItems();
6888
- const newIndex = this.#items.indexOf(child);
7017
+ this.#updateItemPosition(child, newKey);
7018
+ const newIndex = this.#items.findIndex((item) => item === child);
6889
7019
  if (previousIndex === newIndex) {
6890
7020
  return {
6891
7021
  modified: false
@@ -6902,18 +7032,17 @@ var LiveList = class _LiveList extends AbstractCrdt {
6902
7032
  }
6903
7033
  #applySetChildKeyUndoRedo(newKey, child) {
6904
7034
  const previousKey = nn(child._parentKey);
6905
- const previousIndex = this.#items.indexOf(child);
7035
+ const previousIndex = this.#items.findIndex((item) => item === child);
6906
7036
  const existingItemIndex = this._indexOfPosition(newKey);
6907
7037
  let actualNewKey = newKey;
6908
7038
  if (existingItemIndex !== -1) {
6909
7039
  actualNewKey = makePosition(
6910
7040
  newKey,
6911
- _optionalChain([this, 'access', _136 => _136.#items, 'access', _137 => _137[existingItemIndex + 1], 'optionalAccess', _138 => _138._parentPos])
7041
+ _optionalChain([this, 'access', _141 => _141.#items, 'access', _142 => _142.at, 'call', _143 => _143(existingItemIndex + 1), 'optionalAccess', _144 => _144._parentPos])
6912
7042
  );
6913
7043
  }
6914
- child._setParentLink(this, actualNewKey);
6915
- this._sortItems();
6916
- const newIndex = this.#items.indexOf(child);
7044
+ this.#updateItemPosition(child, actualNewKey);
7045
+ const newIndex = this.#items.findIndex((item) => item === child);
6917
7046
  if (previousIndex === newIndex) {
6918
7047
  return {
6919
7048
  modified: false
@@ -6966,7 +7095,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6966
7095
  * @param element The element to add to the end of the LiveList.
6967
7096
  */
6968
7097
  push(element) {
6969
- _optionalChain([this, 'access', _139 => _139._pool, 'optionalAccess', _140 => _140.assertStorageIsWritable, 'call', _141 => _141()]);
7098
+ _optionalChain([this, 'access', _145 => _145._pool, 'optionalAccess', _146 => _146.assertStorageIsWritable, 'call', _147 => _147()]);
6970
7099
  return this.insert(element, this.length);
6971
7100
  }
6972
7101
  /**
@@ -6975,18 +7104,18 @@ var LiveList = class _LiveList extends AbstractCrdt {
6975
7104
  * @param index The index at which you want to insert the element.
6976
7105
  */
6977
7106
  insert(element, index) {
6978
- _optionalChain([this, 'access', _142 => _142._pool, 'optionalAccess', _143 => _143.assertStorageIsWritable, 'call', _144 => _144()]);
7107
+ _optionalChain([this, 'access', _148 => _148._pool, 'optionalAccess', _149 => _149.assertStorageIsWritable, 'call', _150 => _150()]);
6979
7108
  if (index < 0 || index > this.#items.length) {
6980
7109
  throw new Error(
6981
7110
  `Cannot insert list item at index "${index}". index should be between 0 and ${this.#items.length}`
6982
7111
  );
6983
7112
  }
6984
- const before2 = this.#items[index - 1] ? this.#items[index - 1]._parentPos : void 0;
6985
- const after2 = this.#items[index] ? this.#items[index]._parentPos : void 0;
7113
+ const before2 = _optionalChain([this, 'access', _151 => _151.#items, 'access', _152 => _152.at, 'call', _153 => _153(index - 1), 'optionalAccess', _154 => _154._parentPos]);
7114
+ const after2 = _optionalChain([this, 'access', _155 => _155.#items, 'access', _156 => _156.at, 'call', _157 => _157(index), 'optionalAccess', _158 => _158._parentPos]);
6986
7115
  const position = makePosition(before2, after2);
6987
7116
  const value = lsonToLiveNode(element);
6988
7117
  value._setParentLink(this, position);
6989
- this._insertAndSort(value);
7118
+ this.#insert(value);
6990
7119
  if (this._pool && this._id) {
6991
7120
  const id = this._pool.generateId();
6992
7121
  value._attach(id, this._pool);
@@ -7005,7 +7134,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7005
7134
  * @param targetIndex The index where the element should be after moving.
7006
7135
  */
7007
7136
  move(index, targetIndex) {
7008
- _optionalChain([this, 'access', _145 => _145._pool, 'optionalAccess', _146 => _146.assertStorageIsWritable, 'call', _147 => _147()]);
7137
+ _optionalChain([this, 'access', _159 => _159._pool, 'optionalAccess', _160 => _160.assertStorageIsWritable, 'call', _161 => _161()]);
7009
7138
  if (targetIndex < 0) {
7010
7139
  throw new Error("targetIndex cannot be less than 0");
7011
7140
  }
@@ -7023,17 +7152,16 @@ var LiveList = class _LiveList extends AbstractCrdt {
7023
7152
  let beforePosition = null;
7024
7153
  let afterPosition = null;
7025
7154
  if (index < targetIndex) {
7026
- afterPosition = targetIndex === this.#items.length - 1 ? void 0 : this.#items[targetIndex + 1]._parentPos;
7027
- beforePosition = this.#items[targetIndex]._parentPos;
7155
+ afterPosition = targetIndex === this.#items.length - 1 ? void 0 : _optionalChain([this, 'access', _162 => _162.#items, 'access', _163 => _163.at, 'call', _164 => _164(targetIndex + 1), 'optionalAccess', _165 => _165._parentPos]);
7156
+ beforePosition = this.#items.at(targetIndex)._parentPos;
7028
7157
  } else {
7029
- afterPosition = this.#items[targetIndex]._parentPos;
7030
- beforePosition = targetIndex === 0 ? void 0 : this.#items[targetIndex - 1]._parentPos;
7158
+ afterPosition = this.#items.at(targetIndex)._parentPos;
7159
+ beforePosition = targetIndex === 0 ? void 0 : _optionalChain([this, 'access', _166 => _166.#items, 'access', _167 => _167.at, 'call', _168 => _168(targetIndex - 1), 'optionalAccess', _169 => _169._parentPos]);
7031
7160
  }
7032
7161
  const position = makePosition(beforePosition, afterPosition);
7033
- const item = this.#items[index];
7162
+ const item = this.#items.at(index);
7034
7163
  const previousPosition = item._getParentKeyOrThrow();
7035
- item._setParentLink(this, position);
7036
- this._sortItems();
7164
+ this.#updateItemPositionAt(index, position);
7037
7165
  if (this._pool && this._id) {
7038
7166
  const storageUpdates = /* @__PURE__ */ new Map([
7039
7167
  [this._id, makeUpdate(this, [moveDelta(index, targetIndex, item)])]
@@ -7063,15 +7191,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
7063
7191
  * @param index The index of the element to delete
7064
7192
  */
7065
7193
  delete(index) {
7066
- _optionalChain([this, 'access', _148 => _148._pool, 'optionalAccess', _149 => _149.assertStorageIsWritable, 'call', _150 => _150()]);
7194
+ _optionalChain([this, 'access', _170 => _170._pool, 'optionalAccess', _171 => _171.assertStorageIsWritable, 'call', _172 => _172()]);
7067
7195
  if (index < 0 || index >= this.#items.length) {
7068
7196
  throw new Error(
7069
7197
  `Cannot delete list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
7070
7198
  );
7071
7199
  }
7072
- const item = this.#items[index];
7200
+ const item = this.#items.at(index);
7073
7201
  item._detach();
7074
- const [prev] = this.#items.splice(index, 1);
7202
+ this.#items.remove(item);
7075
7203
  this.invalidate();
7076
7204
  if (this._pool) {
7077
7205
  const childRecordId = item._id;
@@ -7079,7 +7207,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7079
7207
  const storageUpdates = /* @__PURE__ */ new Map();
7080
7208
  storageUpdates.set(
7081
7209
  nn(this._id),
7082
- makeUpdate(this, [deleteDelta(index, prev)])
7210
+ makeUpdate(this, [deleteDelta(index, item)])
7083
7211
  );
7084
7212
  this._pool.dispatch(
7085
7213
  [
@@ -7096,7 +7224,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7096
7224
  }
7097
7225
  }
7098
7226
  clear() {
7099
- _optionalChain([this, 'access', _151 => _151._pool, 'optionalAccess', _152 => _152.assertStorageIsWritable, 'call', _153 => _153()]);
7227
+ _optionalChain([this, 'access', _173 => _173._pool, 'optionalAccess', _174 => _174.assertStorageIsWritable, 'call', _175 => _175()]);
7100
7228
  if (this._pool) {
7101
7229
  const ops = [];
7102
7230
  const reverseOps = [];
@@ -7116,7 +7244,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7116
7244
  updateDelta.push(deleteDelta(0, item));
7117
7245
  }
7118
7246
  }
7119
- this.#items = [];
7247
+ this.#items.clear();
7120
7248
  this.invalidate();
7121
7249
  const storageUpdates = /* @__PURE__ */ new Map();
7122
7250
  storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta));
@@ -7125,24 +7253,25 @@ var LiveList = class _LiveList extends AbstractCrdt {
7125
7253
  for (const item of this.#items) {
7126
7254
  item._detach();
7127
7255
  }
7128
- this.#items = [];
7256
+ this.#items.clear();
7129
7257
  this.invalidate();
7130
7258
  }
7131
7259
  }
7132
7260
  set(index, item) {
7133
- _optionalChain([this, 'access', _154 => _154._pool, 'optionalAccess', _155 => _155.assertStorageIsWritable, 'call', _156 => _156()]);
7261
+ _optionalChain([this, 'access', _176 => _176._pool, 'optionalAccess', _177 => _177.assertStorageIsWritable, 'call', _178 => _178()]);
7134
7262
  if (index < 0 || index >= this.#items.length) {
7135
7263
  throw new Error(
7136
7264
  `Cannot set list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
7137
7265
  );
7138
7266
  }
7139
- const existingItem = this.#items[index];
7267
+ const existingItem = this.#items.at(index);
7140
7268
  const position = existingItem._getParentKeyOrThrow();
7141
7269
  const existingId = existingItem._id;
7142
7270
  existingItem._detach();
7143
7271
  const value = lsonToLiveNode(item);
7144
7272
  value._setParentLink(this, position);
7145
- this.#items[index] = value;
7273
+ this.#items.remove(existingItem);
7274
+ this.#items.add(value);
7146
7275
  this.invalidate();
7147
7276
  if (this._pool && this._id) {
7148
7277
  const id = this._pool.generateId();
@@ -7165,11 +7294,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7165
7294
  * Returns an Array of all the elements in the LiveList.
7166
7295
  */
7167
7296
  toArray() {
7168
- return this.#items.map(
7169
- (entry) => liveNodeToLson(entry)
7170
- // ^^^^^^^^
7171
- // FIXME! This isn't safe.
7172
- );
7297
+ return Array.from(this.#items, (entry) => liveNodeToLson(entry));
7173
7298
  }
7174
7299
  /**
7175
7300
  * Tests whether all elements pass the test implemented by the provided function.
@@ -7219,7 +7344,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
7219
7344
  if (index < 0 || index >= this.#items.length) {
7220
7345
  return void 0;
7221
7346
  }
7222
- return liveNodeToLson(this.#items[index]);
7347
+ const item = this.#items.at(index);
7348
+ return item ? liveNodeToLson(item) : void 0;
7223
7349
  }
7224
7350
  /**
7225
7351
  * Returns the first index at which a given element can be found in the LiveList, or -1 if it is not present.
@@ -7245,14 +7371,20 @@ var LiveList = class _LiveList extends AbstractCrdt {
7245
7371
  * @returns An array with each element being the result of the callback function.
7246
7372
  */
7247
7373
  map(callback) {
7248
- return this.#items.map(
7249
- (entry, i) => callback(
7250
- liveNodeToLson(entry),
7251
- // ^^^^^^^^
7252
- // FIXME! This isn't safe.
7253
- i
7254
- )
7255
- );
7374
+ const result = [];
7375
+ let i = 0;
7376
+ for (const entry of this.#items) {
7377
+ result.push(
7378
+ callback(
7379
+ liveNodeToLson(entry),
7380
+ // ^^^^^^^^
7381
+ // FIXME! This isn't safe.
7382
+ i
7383
+ )
7384
+ );
7385
+ i++;
7386
+ }
7387
+ return result;
7256
7388
  }
7257
7389
  /**
7258
7390
  * Tests whether at least one element in the LiveList passes the test implemented by the provided function.
@@ -7269,26 +7401,30 @@ var LiveList = class _LiveList extends AbstractCrdt {
7269
7401
  const newItem = creationOpToLiveNode(op);
7270
7402
  newItem._attach(op.id, nn(this._pool));
7271
7403
  newItem._setParentLink(this, key);
7272
- this._insertAndSort(newItem);
7404
+ this.#insert(newItem);
7273
7405
  const newIndex = this._indexOfPosition(key);
7274
7406
  return { newItem, newIndex };
7275
7407
  }
7276
7408
  #shiftItemPosition(index, key) {
7277
7409
  const shiftedPosition = makePosition(
7278
7410
  key,
7279
- this.#items.length > index + 1 ? _optionalChain([this, 'access', _157 => _157.#items, 'access', _158 => _158[index + 1], 'optionalAccess', _159 => _159._parentPos]) : void 0
7411
+ this.#items.length > index + 1 ? _optionalChain([this, 'access', _179 => _179.#items, 'access', _180 => _180.at, 'call', _181 => _181(index + 1), 'optionalAccess', _182 => _182._parentPos]) : void 0
7280
7412
  );
7281
- this.#items[index]._setParentLink(this, shiftedPosition);
7413
+ this.#updateItemPositionAt(index, shiftedPosition);
7282
7414
  }
7283
7415
  /** @internal */
7284
7416
  _toTreeNode(key) {
7417
+ const payload = [];
7418
+ let index = 0;
7419
+ for (const item of this.#items) {
7420
+ payload.push(item.toTreeNode(index.toString()));
7421
+ index++;
7422
+ }
7285
7423
  return {
7286
7424
  type: "LiveList",
7287
7425
  id: _nullishCoalesce(this._id, () => ( nanoid())),
7288
7426
  key,
7289
- payload: this.#items.map(
7290
- (item, index) => item.toTreeNode(index.toString())
7291
- )
7427
+ payload
7292
7428
  };
7293
7429
  }
7294
7430
  toImmutable() {
@@ -7296,11 +7432,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
7296
7432
  }
7297
7433
  /** @internal */
7298
7434
  _toImmutable() {
7299
- const result = this.#items.map((node) => node.toImmutable());
7435
+ const result = Array.from(this.#items, (node) => node.toImmutable());
7300
7436
  return process.env.NODE_ENV === "production" ? result : Object.freeze(result);
7301
7437
  }
7302
7438
  clone() {
7303
- return new _LiveList(this.#items.map((item) => item.clone()));
7439
+ return new _LiveList(
7440
+ Array.from(this.#items, (item) => item.clone())
7441
+ );
7304
7442
  }
7305
7443
  };
7306
7444
  var LiveListIterator = class {
@@ -7541,7 +7679,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
7541
7679
  * @param value The value of the element to add. Should be serializable to JSON.
7542
7680
  */
7543
7681
  set(key, value) {
7544
- _optionalChain([this, 'access', _160 => _160._pool, 'optionalAccess', _161 => _161.assertStorageIsWritable, 'call', _162 => _162()]);
7682
+ _optionalChain([this, 'access', _183 => _183._pool, 'optionalAccess', _184 => _184.assertStorageIsWritable, 'call', _185 => _185()]);
7545
7683
  const oldValue = this.#map.get(key);
7546
7684
  if (oldValue) {
7547
7685
  oldValue._detach();
@@ -7587,7 +7725,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
7587
7725
  * @returns true if an element existed and has been removed, or false if the element does not exist.
7588
7726
  */
7589
7727
  delete(key) {
7590
- _optionalChain([this, 'access', _163 => _163._pool, 'optionalAccess', _164 => _164.assertStorageIsWritable, 'call', _165 => _165()]);
7728
+ _optionalChain([this, 'access', _186 => _186._pool, 'optionalAccess', _187 => _187.assertStorageIsWritable, 'call', _188 => _188()]);
7591
7729
  const item = this.#map.get(key);
7592
7730
  if (item === void 0) {
7593
7731
  return false;
@@ -8068,7 +8206,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8068
8206
  * @param value The value of the property to add
8069
8207
  */
8070
8208
  set(key, value) {
8071
- _optionalChain([this, 'access', _166 => _166._pool, 'optionalAccess', _167 => _167.assertStorageIsWritable, 'call', _168 => _168()]);
8209
+ _optionalChain([this, 'access', _189 => _189._pool, 'optionalAccess', _190 => _190.assertStorageIsWritable, 'call', _191 => _191()]);
8072
8210
  this.update({ [key]: value });
8073
8211
  }
8074
8212
  /**
@@ -8083,7 +8221,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8083
8221
  * @param key The key of the property to delete
8084
8222
  */
8085
8223
  delete(key) {
8086
- _optionalChain([this, 'access', _169 => _169._pool, 'optionalAccess', _170 => _170.assertStorageIsWritable, 'call', _171 => _171()]);
8224
+ _optionalChain([this, 'access', _192 => _192._pool, 'optionalAccess', _193 => _193.assertStorageIsWritable, 'call', _194 => _194()]);
8087
8225
  const keyAsString = key;
8088
8226
  const oldValue = this.#map.get(keyAsString);
8089
8227
  if (oldValue === void 0) {
@@ -8138,7 +8276,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8138
8276
  * @param patch The object used to overrides properties
8139
8277
  */
8140
8278
  update(patch) {
8141
- _optionalChain([this, 'access', _172 => _172._pool, 'optionalAccess', _173 => _173.assertStorageIsWritable, 'call', _174 => _174()]);
8279
+ _optionalChain([this, 'access', _195 => _195._pool, 'optionalAccess', _196 => _196.assertStorageIsWritable, 'call', _197 => _197()]);
8142
8280
  if (_LiveObject.detectLargeObjects) {
8143
8281
  const data = {};
8144
8282
  for (const [key, value] of this.#map) {
@@ -8869,15 +9007,15 @@ function installBackgroundTabSpy() {
8869
9007
  const doc = typeof document !== "undefined" ? document : void 0;
8870
9008
  const inBackgroundSince = { current: null };
8871
9009
  function onVisibilityChange() {
8872
- if (_optionalChain([doc, 'optionalAccess', _175 => _175.visibilityState]) === "hidden") {
9010
+ if (_optionalChain([doc, 'optionalAccess', _198 => _198.visibilityState]) === "hidden") {
8873
9011
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
8874
9012
  } else {
8875
9013
  inBackgroundSince.current = null;
8876
9014
  }
8877
9015
  }
8878
- _optionalChain([doc, 'optionalAccess', _176 => _176.addEventListener, 'call', _177 => _177("visibilitychange", onVisibilityChange)]);
9016
+ _optionalChain([doc, 'optionalAccess', _199 => _199.addEventListener, 'call', _200 => _200("visibilitychange", onVisibilityChange)]);
8879
9017
  const unsub = () => {
8880
- _optionalChain([doc, 'optionalAccess', _178 => _178.removeEventListener, 'call', _179 => _179("visibilitychange", onVisibilityChange)]);
9018
+ _optionalChain([doc, 'optionalAccess', _201 => _201.removeEventListener, 'call', _202 => _202("visibilitychange", onVisibilityChange)]);
8881
9019
  };
8882
9020
  return [inBackgroundSince, unsub];
8883
9021
  }
@@ -9063,7 +9201,7 @@ function createRoom(options, config) {
9063
9201
  }
9064
9202
  }
9065
9203
  function isStorageWritable() {
9066
- const scopes = _optionalChain([context, 'access', _180 => _180.dynamicSessionInfoSig, 'access', _181 => _181.get, 'call', _182 => _182(), 'optionalAccess', _183 => _183.scopes]);
9204
+ const scopes = _optionalChain([context, 'access', _203 => _203.dynamicSessionInfoSig, 'access', _204 => _204.get, 'call', _205 => _205(), 'optionalAccess', _206 => _206.scopes]);
9067
9205
  return scopes !== void 0 ? canWriteStorage(scopes) : true;
9068
9206
  }
9069
9207
  const eventHub = {
@@ -9194,7 +9332,7 @@ function createRoom(options, config) {
9194
9332
  // be stuck in "synchronizing" forever).
9195
9333
  case "experimental-fallback-to-http": {
9196
9334
  warn("Message is too large for websockets, so sending over HTTP instead");
9197
- const nonce = _nullishCoalesce(_optionalChain([context, 'access', _184 => _184.dynamicSessionInfoSig, 'access', _185 => _185.get, 'call', _186 => _186(), 'optionalAccess', _187 => _187.nonce]), () => ( raise("Session is not authorized to send message over HTTP")));
9335
+ const nonce = _nullishCoalesce(_optionalChain([context, 'access', _207 => _207.dynamicSessionInfoSig, 'access', _208 => _208.get, 'call', _209 => _209(), 'optionalAccess', _210 => _210.nonce]), () => ( raise("Session is not authorized to send message over HTTP")));
9198
9336
  void httpClient.sendMessagesOverHTTP({ roomId, nonce, messages }).then((resp) => {
9199
9337
  if (!resp.ok && resp.status === 403) {
9200
9338
  managedSocket.reconnect();
@@ -9241,15 +9379,24 @@ function createRoom(options, config) {
9241
9379
  (me) => me !== null ? userToTreeNode("Me", me) : null
9242
9380
  );
9243
9381
  function createOrUpdateRootFromMessage(nodes) {
9382
+ if (nodes.size === 0) {
9383
+ throw new Error("Internal error: cannot load storage without items");
9384
+ }
9244
9385
  if (context.root !== void 0) {
9245
- updateRoot(nodes);
9386
+ const currentItems = /* @__PURE__ */ new Map();
9387
+ for (const [id, crdt] of context.pool.nodes) {
9388
+ currentItems.set(id, crdt._serialize());
9389
+ }
9390
+ const ops = getTreesDiffOperations(currentItems, nodes);
9391
+ const result = applyRemoteOps(ops);
9392
+ notify(result.updates);
9246
9393
  } else {
9247
9394
  context.root = LiveObject._fromItems(
9248
9395
  nodes,
9249
9396
  context.pool
9250
9397
  );
9251
9398
  }
9252
- const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _188 => _188.get, 'call', _189 => _189(), 'optionalAccess', _190 => _190.canWrite]), () => ( true));
9399
+ const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _211 => _211.get, 'call', _212 => _212(), 'optionalAccess', _213 => _213.canWrite]), () => ( true));
9253
9400
  const stackSizeBefore = context.undoStack.length;
9254
9401
  for (const key in context.initialStorage) {
9255
9402
  if (context.root.get(key) === void 0) {
@@ -9264,21 +9411,6 @@ function createRoom(options, config) {
9264
9411
  }
9265
9412
  context.undoStack.length = stackSizeBefore;
9266
9413
  }
9267
- function updateRoot(nodes) {
9268
- if (nodes.size === 0) {
9269
- throw new Error("Internal error: cannot load storage without items");
9270
- }
9271
- if (context.root === void 0) {
9272
- return;
9273
- }
9274
- const currentItems = /* @__PURE__ */ new Map();
9275
- for (const [id, crdt] of context.pool.nodes) {
9276
- currentItems.set(id, crdt._serialize());
9277
- }
9278
- const ops = getTreesDiffOperations(currentItems, nodes);
9279
- const result = applyRemoteOps(ops);
9280
- notify(result.updates);
9281
- }
9282
9414
  function _addToRealUndoStack(frames) {
9283
9415
  if (context.undoStack.length >= 50) {
9284
9416
  context.undoStack.shift();
@@ -9468,7 +9600,7 @@ function createRoom(options, config) {
9468
9600
  }
9469
9601
  context.myPresence.patch(patch);
9470
9602
  if (context.activeBatch) {
9471
- if (_optionalChain([options2, 'optionalAccess', _191 => _191.addToHistory])) {
9603
+ if (_optionalChain([options2, 'optionalAccess', _214 => _214.addToHistory])) {
9472
9604
  context.activeBatch.reverseOps.pushLeft({
9473
9605
  type: "presence",
9474
9606
  data: oldValues
@@ -9477,7 +9609,7 @@ function createRoom(options, config) {
9477
9609
  context.activeBatch.updates.presence = true;
9478
9610
  } else {
9479
9611
  flushNowOrSoon();
9480
- if (_optionalChain([options2, 'optionalAccess', _192 => _192.addToHistory])) {
9612
+ if (_optionalChain([options2, 'optionalAccess', _215 => _215.addToHistory])) {
9481
9613
  addToUndoStack([{ type: "presence", data: oldValues }]);
9482
9614
  }
9483
9615
  notify({ presence: true });
@@ -9802,7 +9934,7 @@ function createRoom(options, config) {
9802
9934
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
9803
9935
  createOrUpdateRootFromMessage(nodes);
9804
9936
  applyAndSendOfflineOps(unacknowledgedOps);
9805
- _optionalChain([_resolveStoragePromise, 'optionalCall', _193 => _193()]);
9937
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _216 => _216()]);
9806
9938
  notifyStorageStatus();
9807
9939
  eventHub.storageDidLoad.notify();
9808
9940
  }
@@ -10022,8 +10154,8 @@ function createRoom(options, config) {
10022
10154
  async function getThreads(options2) {
10023
10155
  return httpClient.getThreads({
10024
10156
  roomId,
10025
- query: _optionalChain([options2, 'optionalAccess', _194 => _194.query]),
10026
- cursor: _optionalChain([options2, 'optionalAccess', _195 => _195.cursor])
10157
+ query: _optionalChain([options2, 'optionalAccess', _217 => _217.query]),
10158
+ cursor: _optionalChain([options2, 'optionalAccess', _218 => _218.cursor])
10027
10159
  });
10028
10160
  }
10029
10161
  async function getThread(threadId) {
@@ -10145,7 +10277,7 @@ function createRoom(options, config) {
10145
10277
  function getSubscriptionSettings(options2) {
10146
10278
  return httpClient.getSubscriptionSettings({
10147
10279
  roomId,
10148
- signal: _optionalChain([options2, 'optionalAccess', _196 => _196.signal])
10280
+ signal: _optionalChain([options2, 'optionalAccess', _219 => _219.signal])
10149
10281
  });
10150
10282
  }
10151
10283
  function updateSubscriptionSettings(settings) {
@@ -10167,7 +10299,7 @@ function createRoom(options, config) {
10167
10299
  {
10168
10300
  [kInternal]: {
10169
10301
  get presenceBuffer() {
10170
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _197 => _197.buffer, 'access', _198 => _198.presenceUpdates, 'optionalAccess', _199 => _199.data]), () => ( null)));
10302
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _220 => _220.buffer, 'access', _221 => _221.presenceUpdates, 'optionalAccess', _222 => _222.data]), () => ( null)));
10171
10303
  },
10172
10304
  // prettier-ignore
10173
10305
  get undoStack() {
@@ -10182,9 +10314,9 @@ function createRoom(options, config) {
10182
10314
  return context.yjsProvider;
10183
10315
  },
10184
10316
  setYjsProvider(newProvider) {
10185
- _optionalChain([context, 'access', _200 => _200.yjsProvider, 'optionalAccess', _201 => _201.off, 'call', _202 => _202("status", yjsStatusDidChange)]);
10317
+ _optionalChain([context, 'access', _223 => _223.yjsProvider, 'optionalAccess', _224 => _224.off, 'call', _225 => _225("status", yjsStatusDidChange)]);
10186
10318
  context.yjsProvider = newProvider;
10187
- _optionalChain([newProvider, 'optionalAccess', _203 => _203.on, 'call', _204 => _204("status", yjsStatusDidChange)]);
10319
+ _optionalChain([newProvider, 'optionalAccess', _226 => _226.on, 'call', _227 => _227("status", yjsStatusDidChange)]);
10188
10320
  context.yjsProviderDidChange.notify();
10189
10321
  },
10190
10322
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
@@ -10230,7 +10362,7 @@ function createRoom(options, config) {
10230
10362
  source.dispose();
10231
10363
  }
10232
10364
  eventHub.roomWillDestroy.notify();
10233
- _optionalChain([context, 'access', _205 => _205.yjsProvider, 'optionalAccess', _206 => _206.off, 'call', _207 => _207("status", yjsStatusDidChange)]);
10365
+ _optionalChain([context, 'access', _228 => _228.yjsProvider, 'optionalAccess', _229 => _229.off, 'call', _230 => _230("status", yjsStatusDidChange)]);
10234
10366
  syncSourceForStorage.destroy();
10235
10367
  syncSourceForYjs.destroy();
10236
10368
  uninstallBgTabSpy();
@@ -10381,7 +10513,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
10381
10513
  }
10382
10514
  if (isLiveNode(first)) {
10383
10515
  const node = first;
10384
- if (_optionalChain([options, 'optionalAccess', _208 => _208.isDeep])) {
10516
+ if (_optionalChain([options, 'optionalAccess', _231 => _231.isDeep])) {
10385
10517
  const storageCallback = second;
10386
10518
  return subscribeToLiveStructureDeeply(node, storageCallback);
10387
10519
  } else {
@@ -10463,8 +10595,8 @@ function createClient(options) {
10463
10595
  const authManager = createAuthManager(options, (token) => {
10464
10596
  currentUserId.set(() => token.uid);
10465
10597
  });
10466
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _209 => _209.polyfills, 'optionalAccess', _210 => _210.fetch]) || /* istanbul ignore next */
10467
- _optionalChain([globalThis, 'access', _211 => _211.fetch, 'optionalAccess', _212 => _212.bind, 'call', _213 => _213(globalThis)]);
10598
+ const fetchPolyfill = _optionalChain([clientOptions, 'access', _232 => _232.polyfills, 'optionalAccess', _233 => _233.fetch]) || /* istanbul ignore next */
10599
+ _optionalChain([globalThis, 'access', _234 => _234.fetch, 'optionalAccess', _235 => _235.bind, 'call', _236 => _236(globalThis)]);
10468
10600
  const httpClient = createApiClient({
10469
10601
  baseUrl,
10470
10602
  fetchPolyfill,
@@ -10482,7 +10614,7 @@ function createClient(options) {
10482
10614
  delegates: {
10483
10615
  createSocket: makeCreateSocketDelegateForAi(
10484
10616
  baseUrl,
10485
- _optionalChain([clientOptions, 'access', _214 => _214.polyfills, 'optionalAccess', _215 => _215.WebSocket])
10617
+ _optionalChain([clientOptions, 'access', _237 => _237.polyfills, 'optionalAccess', _238 => _238.WebSocket])
10486
10618
  ),
10487
10619
  authenticate: async () => {
10488
10620
  const resp = await authManager.getAuthValue({
@@ -10542,7 +10674,7 @@ function createClient(options) {
10542
10674
  createSocket: makeCreateSocketDelegateForRoom(
10543
10675
  roomId,
10544
10676
  baseUrl,
10545
- _optionalChain([clientOptions, 'access', _216 => _216.polyfills, 'optionalAccess', _217 => _217.WebSocket]),
10677
+ _optionalChain([clientOptions, 'access', _239 => _239.polyfills, 'optionalAccess', _240 => _240.WebSocket]),
10546
10678
  options2.engine
10547
10679
  ),
10548
10680
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
@@ -10567,7 +10699,7 @@ function createClient(options) {
10567
10699
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
10568
10700
  if (shouldConnect) {
10569
10701
  if (typeof atob === "undefined") {
10570
- if (_optionalChain([clientOptions, 'access', _218 => _218.polyfills, 'optionalAccess', _219 => _219.atob]) === void 0) {
10702
+ if (_optionalChain([clientOptions, 'access', _241 => _241.polyfills, 'optionalAccess', _242 => _242.atob]) === void 0) {
10571
10703
  throw new Error(
10572
10704
  "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"
10573
10705
  );
@@ -10579,7 +10711,7 @@ function createClient(options) {
10579
10711
  return leaseRoom(newRoomDetails);
10580
10712
  }
10581
10713
  function getRoom(roomId) {
10582
- const room = _optionalChain([roomsById, 'access', _220 => _220.get, 'call', _221 => _221(roomId), 'optionalAccess', _222 => _222.room]);
10714
+ const room = _optionalChain([roomsById, 'access', _243 => _243.get, 'call', _244 => _244(roomId), 'optionalAccess', _245 => _245.room]);
10583
10715
  return room ? room : null;
10584
10716
  }
10585
10717
  function logout() {
@@ -10595,7 +10727,7 @@ function createClient(options) {
10595
10727
  const batchedResolveUsers = new Batch(
10596
10728
  async (batchedUserIds) => {
10597
10729
  const userIds = batchedUserIds.flat();
10598
- const users = await _optionalChain([resolveUsers, 'optionalCall', _223 => _223({ userIds })]);
10730
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _246 => _246({ userIds })]);
10599
10731
  warnOnceIf(
10600
10732
  !resolveUsers,
10601
10733
  "Set the resolveUsers option in createClient to specify user info."
@@ -10612,7 +10744,7 @@ function createClient(options) {
10612
10744
  const batchedResolveRoomsInfo = new Batch(
10613
10745
  async (batchedRoomIds) => {
10614
10746
  const roomIds = batchedRoomIds.flat();
10615
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _224 => _224({ roomIds })]);
10747
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _247 => _247({ roomIds })]);
10616
10748
  warnOnceIf(
10617
10749
  !resolveRoomsInfo,
10618
10750
  "Set the resolveRoomsInfo option in createClient to specify room info."
@@ -10629,7 +10761,7 @@ function createClient(options) {
10629
10761
  const batchedResolveGroupsInfo = new Batch(
10630
10762
  async (batchedGroupIds) => {
10631
10763
  const groupIds = batchedGroupIds.flat();
10632
- const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _225 => _225({ groupIds })]);
10764
+ const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _248 => _248({ groupIds })]);
10633
10765
  warnOnceIf(
10634
10766
  !resolveGroupsInfo,
10635
10767
  "Set the resolveGroupsInfo option in createClient to specify group info."
@@ -10685,7 +10817,7 @@ function createClient(options) {
10685
10817
  }
10686
10818
  };
10687
10819
  const win = typeof window !== "undefined" ? window : void 0;
10688
- _optionalChain([win, 'optionalAccess', _226 => _226.addEventListener, 'call', _227 => _227("beforeunload", maybePreventClose)]);
10820
+ _optionalChain([win, 'optionalAccess', _249 => _249.addEventListener, 'call', _250 => _250("beforeunload", maybePreventClose)]);
10689
10821
  }
10690
10822
  async function getNotificationSettings(options2) {
10691
10823
  const plainSettings = await httpClient.getNotificationSettings(options2);
@@ -10812,7 +10944,7 @@ var commentBodyElementsTypes = {
10812
10944
  mention: "inline"
10813
10945
  };
10814
10946
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
10815
- if (!body || !_optionalChain([body, 'optionalAccess', _228 => _228.content])) {
10947
+ if (!body || !_optionalChain([body, 'optionalAccess', _251 => _251.content])) {
10816
10948
  return;
10817
10949
  }
10818
10950
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -10822,13 +10954,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
10822
10954
  for (const block of body.content) {
10823
10955
  if (type === "all" || type === "block") {
10824
10956
  if (guard(block)) {
10825
- _optionalChain([visitor, 'optionalCall', _229 => _229(block)]);
10957
+ _optionalChain([visitor, 'optionalCall', _252 => _252(block)]);
10826
10958
  }
10827
10959
  }
10828
10960
  if (type === "all" || type === "inline") {
10829
10961
  for (const inline of block.children) {
10830
10962
  if (guard(inline)) {
10831
- _optionalChain([visitor, 'optionalCall', _230 => _230(inline)]);
10963
+ _optionalChain([visitor, 'optionalCall', _253 => _253(inline)]);
10832
10964
  }
10833
10965
  }
10834
10966
  }
@@ -10998,7 +11130,7 @@ var stringifyCommentBodyPlainElements = {
10998
11130
  text: ({ element }) => element.text,
10999
11131
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
11000
11132
  mention: ({ element, user, group }) => {
11001
- return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _231 => _231.name]), () => ( _optionalChain([group, 'optionalAccess', _232 => _232.name]))), () => ( element.id))}`;
11133
+ return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _254 => _254.name]), () => ( _optionalChain([group, 'optionalAccess', _255 => _255.name]))), () => ( element.id))}`;
11002
11134
  }
11003
11135
  };
11004
11136
  var stringifyCommentBodyHtmlElements = {
@@ -11028,7 +11160,7 @@ var stringifyCommentBodyHtmlElements = {
11028
11160
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
11029
11161
  },
11030
11162
  mention: ({ element, user, group }) => {
11031
- return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _233 => _233.name]) ? html`${_optionalChain([user, 'optionalAccess', _234 => _234.name])}` : _optionalChain([group, 'optionalAccess', _235 => _235.name]) ? html`${_optionalChain([group, 'optionalAccess', _236 => _236.name])}` : element.id}</span>`;
11163
+ return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _256 => _256.name]) ? html`${_optionalChain([user, 'optionalAccess', _257 => _257.name])}` : _optionalChain([group, 'optionalAccess', _258 => _258.name]) ? html`${_optionalChain([group, 'optionalAccess', _259 => _259.name])}` : element.id}</span>`;
11032
11164
  }
11033
11165
  };
11034
11166
  var stringifyCommentBodyMarkdownElements = {
@@ -11058,20 +11190,20 @@ var stringifyCommentBodyMarkdownElements = {
11058
11190
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
11059
11191
  },
11060
11192
  mention: ({ element, user, group }) => {
11061
- return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _237 => _237.name]), () => ( _optionalChain([group, 'optionalAccess', _238 => _238.name]))), () => ( element.id))}`;
11193
+ return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _260 => _260.name]), () => ( _optionalChain([group, 'optionalAccess', _261 => _261.name]))), () => ( element.id))}`;
11062
11194
  }
11063
11195
  };
11064
11196
  async function stringifyCommentBody(body, options) {
11065
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _239 => _239.format]), () => ( "plain"));
11066
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _240 => _240.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
11197
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _262 => _262.format]), () => ( "plain"));
11198
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _263 => _263.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
11067
11199
  const elements = {
11068
11200
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
11069
- ..._optionalChain([options, 'optionalAccess', _241 => _241.elements])
11201
+ ..._optionalChain([options, 'optionalAccess', _264 => _264.elements])
11070
11202
  };
11071
11203
  const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
11072
11204
  body,
11073
- _optionalChain([options, 'optionalAccess', _242 => _242.resolveUsers]),
11074
- _optionalChain([options, 'optionalAccess', _243 => _243.resolveGroupsInfo])
11205
+ _optionalChain([options, 'optionalAccess', _265 => _265.resolveUsers]),
11206
+ _optionalChain([options, 'optionalAccess', _266 => _266.resolveGroupsInfo])
11075
11207
  );
11076
11208
  const blocks = body.content.flatMap((block, blockIndex) => {
11077
11209
  switch (block.type) {
@@ -11358,12 +11490,12 @@ function legacy_patchImmutableNode(state, path, update) {
11358
11490
  }
11359
11491
  const newState = Object.assign({}, state);
11360
11492
  for (const key in update.updates) {
11361
- if (_optionalChain([update, 'access', _244 => _244.updates, 'access', _245 => _245[key], 'optionalAccess', _246 => _246.type]) === "update") {
11493
+ if (_optionalChain([update, 'access', _267 => _267.updates, 'access', _268 => _268[key], 'optionalAccess', _269 => _269.type]) === "update") {
11362
11494
  const val = update.node.get(key);
11363
11495
  if (val !== void 0) {
11364
11496
  newState[key] = lsonToJson(val);
11365
11497
  }
11366
- } else if (_optionalChain([update, 'access', _247 => _247.updates, 'access', _248 => _248[key], 'optionalAccess', _249 => _249.type]) === "delete") {
11498
+ } else if (_optionalChain([update, 'access', _270 => _270.updates, 'access', _271 => _271[key], 'optionalAccess', _272 => _272.type]) === "delete") {
11367
11499
  delete newState[key];
11368
11500
  }
11369
11501
  }
@@ -11424,12 +11556,12 @@ function legacy_patchImmutableNode(state, path, update) {
11424
11556
  }
11425
11557
  const newState = Object.assign({}, state);
11426
11558
  for (const key in update.updates) {
11427
- if (_optionalChain([update, 'access', _250 => _250.updates, 'access', _251 => _251[key], 'optionalAccess', _252 => _252.type]) === "update") {
11559
+ if (_optionalChain([update, 'access', _273 => _273.updates, 'access', _274 => _274[key], 'optionalAccess', _275 => _275.type]) === "update") {
11428
11560
  const value = update.node.get(key);
11429
11561
  if (value !== void 0) {
11430
11562
  newState[key] = lsonToJson(value);
11431
11563
  }
11432
- } else if (_optionalChain([update, 'access', _253 => _253.updates, 'access', _254 => _254[key], 'optionalAccess', _255 => _255.type]) === "delete") {
11564
+ } else if (_optionalChain([update, 'access', _276 => _276.updates, 'access', _277 => _277[key], 'optionalAccess', _278 => _278.type]) === "delete") {
11433
11565
  delete newState[key];
11434
11566
  }
11435
11567
  }
@@ -11509,9 +11641,9 @@ function makePoller(callback, intervalMs, options) {
11509
11641
  const startTime = performance.now();
11510
11642
  const doc = typeof document !== "undefined" ? document : void 0;
11511
11643
  const win = typeof window !== "undefined" ? window : void 0;
11512
- const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _256 => _256.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
11644
+ const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _279 => _279.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
11513
11645
  const context = {
11514
- inForeground: _optionalChain([doc, 'optionalAccess', _257 => _257.visibilityState]) !== "hidden",
11646
+ inForeground: _optionalChain([doc, 'optionalAccess', _280 => _280.visibilityState]) !== "hidden",
11515
11647
  lastSuccessfulPollAt: startTime,
11516
11648
  count: 0,
11517
11649
  backoff: 0
@@ -11592,11 +11724,11 @@ function makePoller(callback, intervalMs, options) {
11592
11724
  pollNowIfStale();
11593
11725
  }
11594
11726
  function onVisibilityChange() {
11595
- setInForeground(_optionalChain([doc, 'optionalAccess', _258 => _258.visibilityState]) !== "hidden");
11727
+ setInForeground(_optionalChain([doc, 'optionalAccess', _281 => _281.visibilityState]) !== "hidden");
11596
11728
  }
11597
- _optionalChain([doc, 'optionalAccess', _259 => _259.addEventListener, 'call', _260 => _260("visibilitychange", onVisibilityChange)]);
11598
- _optionalChain([win, 'optionalAccess', _261 => _261.addEventListener, 'call', _262 => _262("online", onVisibilityChange)]);
11599
- _optionalChain([win, 'optionalAccess', _263 => _263.addEventListener, 'call', _264 => _264("focus", pollNowIfStale)]);
11729
+ _optionalChain([doc, 'optionalAccess', _282 => _282.addEventListener, 'call', _283 => _283("visibilitychange", onVisibilityChange)]);
11730
+ _optionalChain([win, 'optionalAccess', _284 => _284.addEventListener, 'call', _285 => _285("online", onVisibilityChange)]);
11731
+ _optionalChain([win, 'optionalAccess', _286 => _286.addEventListener, 'call', _287 => _287("focus", pollNowIfStale)]);
11600
11732
  fsm.start();
11601
11733
  return {
11602
11734
  inc,