@liveblocks/core 3.20.0-exp5 → 3.20.0-exp6

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.20.0-exp5";
9
+ var PKG_VERSION = "3.20.0-exp6";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -5804,6 +5804,9 @@ var UnacknowledgedOps = class {
5804
5804
  #createOpsByPosition = /* @__PURE__ */ new Map();
5805
5805
  // parentId -> (opId -> Create op)
5806
5806
  #createOpsByParent = /* @__PURE__ */ new Map();
5807
+ // opIds of pending ops that were in flight when a connection died, so the
5808
+ // server may already have processed them. See isPossiblyStored().
5809
+ #possiblyStoredOpIds = /* @__PURE__ */ new Set();
5807
5810
  #posKey(parentId, parentKey) {
5808
5811
  return `${parentId}
5809
5812
  ${parentKey}`;
@@ -5843,6 +5846,7 @@ ${parentKey}`;
5843
5846
  return;
5844
5847
  }
5845
5848
  this.#byOpId.delete(opId);
5849
+ this.#possiblyStoredOpIds.delete(opId);
5846
5850
  if (isCreateOp(op)) {
5847
5851
  const posKey = this.#posKey(op.parentId, op.parentKey);
5848
5852
  const atPosition = this.#createOpsByPosition.get(posKey);
@@ -5876,6 +5880,19 @@ ${parentKey}`;
5876
5880
  values() {
5877
5881
  return this.#byOpId.values();
5878
5882
  }
5883
+ isPossiblyStored(opId) {
5884
+ return this.#possiblyStoredOpIds.has(opId);
5885
+ }
5886
+ /**
5887
+ * Mark every currently pending op as possibly stored on the server. Called
5888
+ * when the connection dies: all of these ops were in flight, and their
5889
+ * (possibly lost) acks would have been the only way to know their fate.
5890
+ */
5891
+ markAllAsPossiblyStored() {
5892
+ for (const opId of this.#byOpId.keys()) {
5893
+ this.#possiblyStoredOpIds.add(opId);
5894
+ }
5895
+ }
5879
5896
  };
5880
5897
 
5881
5898
  // src/crdts/AbstractCrdt.ts
@@ -6472,7 +6489,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6472
6489
  }
6473
6490
  return result.modified.updates[0];
6474
6491
  }
6475
- #applyRemoteInsert(op, fromSnapshot) {
6492
+ #applyRemoteInsert(op) {
6476
6493
  if (this._pool === void 0) {
6477
6494
  throw new Error("Can't attach child if managed pool is not present");
6478
6495
  }
@@ -6482,7 +6499,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6482
6499
  this.#shiftItemPosition(existingItemIndex, key);
6483
6500
  }
6484
6501
  const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
6485
- const bumpDeltas = fromSnapshot ? [] : this.#bumpUnackedPushesAbove(key);
6502
+ const bumpDeltas = this.#bumpUnackedPushesAbove(key);
6486
6503
  return {
6487
6504
  modified: makeUpdate(this, [
6488
6505
  insertDelta(newIndex, newItem),
@@ -6497,6 +6514,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
6497
6514
  * the single source of truth, so an item drops out the instant its op is
6498
6515
  * acked, with no per-instance membership to leak. Yielded in push order.
6499
6516
  *
6517
+ * Excludes ops that may already be stored on the server (they were in
6518
+ * flight when a connection died, so their fate is unknown): the bump
6519
+ * prediction assumes the server has not processed the op yet, which is only
6520
+ * guaranteed for ops sent on the current connection. For these excluded
6521
+ * ops, the server's (re-)ack states the authoritative position; predicting
6522
+ * locally could produce a wrong position that no ack would correct.
6523
+ *
6500
6524
  * Restricted to items currently in `#items`: a pushed node whose op is still
6501
6525
  * pending may have been pulled out of the list (e.g. implicitly deleted by a
6502
6526
  * remote set, or removed by an undo) while still living in the pool, and such
@@ -6510,6 +6534,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
6510
6534
  if (op.intent !== "push") {
6511
6535
  continue;
6512
6536
  }
6537
+ if (this._pool.unacknowledgedOps.isPossiblyStored(op.opId)) {
6538
+ continue;
6539
+ }
6513
6540
  const node = this._pool.getNode(op.id);
6514
6541
  if (node !== void 0 && this.#items.includes(node)) {
6515
6542
  yield node;
@@ -6674,7 +6701,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6674
6701
  }
6675
6702
  }
6676
6703
  /** @internal */
6677
- _attachChild(op, source, fromSnapshot = false) {
6704
+ _attachChild(op, source) {
6678
6705
  if (this._pool === void 0) {
6679
6706
  throw new Error("Can't attach child if managed pool is not present");
6680
6707
  }
@@ -6689,7 +6716,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6689
6716
  }
6690
6717
  } else {
6691
6718
  if (source === 1 /* THEIRS */) {
6692
- result = this.#applyRemoteInsert(op, fromSnapshot);
6719
+ result = this.#applyRemoteInsert(op);
6693
6720
  } else if (source === 2 /* OURS */) {
6694
6721
  result = this.#applyInsertAck(op);
6695
6722
  } else {
@@ -10354,6 +10381,7 @@ function createRoom(options, config) {
10354
10381
  }
10355
10382
  function onDidDisconnect() {
10356
10383
  clearTimeout(context.buffer.flushTimerID);
10384
+ context.unacknowledgedOps.markAllAsPossiblyStored();
10357
10385
  }
10358
10386
  managedSocket.events.onMessage.subscribe(handleServerMessage);
10359
10387
  managedSocket.events.statusDidChange.subscribe(onStatusDidChange);
@@ -10495,11 +10523,7 @@ function createRoom(options, config) {
10495
10523
  currentItems.set(id, crdt._serialize());
10496
10524
  }
10497
10525
  const ops = getTreesDiffOperations(currentItems, nodes);
10498
- const result = applyRemoteOps(
10499
- ops,
10500
- /* fromSnapshot */
10501
- true
10502
- );
10526
+ const result = applyRemoteOps(ops);
10503
10527
  notify(result.updates);
10504
10528
  } else {
10505
10529
  context.root = LiveObject._fromItems(
@@ -10581,16 +10605,15 @@ function createRoom(options, config) {
10581
10605
  );
10582
10606
  return { opsToEmit: opsWithOpIds, reverse, updates };
10583
10607
  }
10584
- function applyRemoteOps(ops, fromSnapshot = false) {
10608
+ function applyRemoteOps(ops) {
10585
10609
  return applyOps(
10586
10610
  [],
10587
10611
  ops,
10588
10612
  /* isLocal */
10589
- false,
10590
- fromSnapshot
10613
+ false
10591
10614
  );
10592
10615
  }
10593
- function applyOps(pframes, ops, isLocal, fromSnapshot = false) {
10616
+ function applyOps(pframes, ops, isLocal) {
10594
10617
  const output = {
10595
10618
  reverse: new Deque(),
10596
10619
  storageUpdates: /* @__PURE__ */ new Map(),
@@ -10626,7 +10649,7 @@ function createRoom(options, config) {
10626
10649
  } else {
10627
10650
  source = 1 /* THEIRS */;
10628
10651
  }
10629
- const applyOpResult = applyOp(op, source, fromSnapshot);
10652
+ const applyOpResult = applyOp(op, source);
10630
10653
  if (applyOpResult.modified) {
10631
10654
  const nodeId = applyOpResult.modified.node._id;
10632
10655
  if (!(nodeId && createdNodeIds.has(nodeId))) {
@@ -10652,7 +10675,7 @@ function createRoom(options, config) {
10652
10675
  }
10653
10676
  };
10654
10677
  }
10655
- function applyOp(op, source, fromSnapshot = false) {
10678
+ function applyOp(op, source) {
10656
10679
  if (isIgnoredOp(op)) {
10657
10680
  return { modified: false };
10658
10681
  }
@@ -10693,7 +10716,7 @@ function createRoom(options, config) {
10693
10716
  if (parentNode === void 0) {
10694
10717
  return { modified: false };
10695
10718
  }
10696
- return parentNode._attachChild(op, source, fromSnapshot);
10719
+ return parentNode._attachChild(op, source);
10697
10720
  }
10698
10721
  }
10699
10722
  }