@liveblocks/core 3.23.1-exp2 → 3.23.1

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.23.1-exp2";
9
+ var PKG_VERSION = "3.23.1";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -988,15 +988,14 @@ var OpCode = Object.freeze({
988
988
  DELETE_OBJECT_KEY: 6,
989
989
  CREATE_MAP: 7,
990
990
  CREATE_REGISTER: 8,
991
- CREATE_TEXT: 9,
992
- UPDATE_TEXT: 10,
991
+ // TODO: 9 and 10 are used by LiveText, wait until it's merged.
993
992
  CREATE_FILE: 11
994
993
  });
995
994
  function isIgnoredOp(op) {
996
995
  return op.type === OpCode.DELETE_CRDT && op.id === "ACK";
997
996
  }
998
997
  function isCreateOp(op) {
999
- return op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_REGISTER || op.type === OpCode.CREATE_FILE || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_TEXT;
998
+ return op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_REGISTER || op.type === OpCode.CREATE_FILE || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_LIST;
1000
999
  }
1001
1000
 
1002
1001
  // src/protocol/StorageNode.ts
@@ -1005,7 +1004,7 @@ var CrdtType = Object.freeze({
1005
1004
  LIST: 1,
1006
1005
  MAP: 2,
1007
1006
  REGISTER: 3,
1008
- TEXT: 4,
1007
+ // TODO: 4 is used by LiveText, wait until it's merged.
1009
1008
  FILE: 5
1010
1009
  });
1011
1010
  function isRootStorageNode(node) {
@@ -1023,9 +1022,6 @@ function isMapStorageNode(node) {
1023
1022
  function isRegisterStorageNode(node) {
1024
1023
  return node[1].type === CrdtType.REGISTER;
1025
1024
  }
1026
- function isTextStorageNode(node) {
1027
- return node[1].type === CrdtType.TEXT;
1028
- }
1029
1025
  function isFileStorageNode(node) {
1030
1026
  return node[1].type === CrdtType.FILE;
1031
1027
  }
@@ -1051,9 +1047,6 @@ function* compactNodesToNodeStream(compactNodes) {
1051
1047
  case CrdtType.REGISTER:
1052
1048
  yield [cnode[0], { type: CrdtType.REGISTER, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
1053
1049
  break;
1054
- case CrdtType.TEXT:
1055
- yield [cnode[0], { type: CrdtType.TEXT, parentId: cnode[2], parentKey: cnode[3], data: cnode[4], version: cnode[5] }];
1056
- break;
1057
1050
  case CrdtType.FILE:
1058
1051
  yield [cnode[0], { type: CrdtType.FILE, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
1059
1052
  break;
@@ -1085,17 +1078,6 @@ function* nodeStreamToCompactNodes(nodes) {
1085
1078
  const id = node[0];
1086
1079
  const crdt = node[1];
1087
1080
  yield [id, CrdtType.REGISTER, crdt.parentId, crdt.parentKey, crdt.data];
1088
- } else if (isTextStorageNode(node)) {
1089
- const id = node[0];
1090
- const crdt = node[1];
1091
- yield [
1092
- id,
1093
- CrdtType.TEXT,
1094
- crdt.parentId,
1095
- crdt.parentKey,
1096
- crdt.data,
1097
- crdt.version
1098
- ];
1099
1081
  } else if (isFileStorageNode(node)) {
1100
1082
  const id = node[0];
1101
1083
  const crdt = node[1];
@@ -1105,9 +1087,6 @@ function* nodeStreamToCompactNodes(nodes) {
1105
1087
  }
1106
1088
  }
1107
1089
 
1108
- // src/internal.ts
1109
- var kInternal = /* @__PURE__ */ Symbol();
1110
-
1111
1090
  // src/lib/position.ts
1112
1091
  var MIN_CODE = 32;
1113
1092
  var MAX_CODE = 126;
@@ -1287,18 +1266,6 @@ function asPos(str) {
1287
1266
  return isPos(str) ? str : convertToPos(str);
1288
1267
  }
1289
1268
 
1290
- // src/crdts/StorageUpdates.ts
1291
- var REMOTE = freeze({ origin: "remote" });
1292
- var LOCAL_EDIT = freeze({ origin: "local", via: "edit" });
1293
- var LOCAL_UNDO = freeze({ origin: "local", via: "undo" });
1294
- var LOCAL_REDO = freeze({ origin: "local", via: "redo" });
1295
- function toUpdateSource(source) {
1296
- return source.origin === "remote" ? source : (
1297
- // Removes `optimistic` field, which is not public
1298
- { origin: "local", via: source.via }
1299
- );
1300
- }
1301
-
1302
1269
  // src/crdts/UnacknowledgedOps.ts
1303
1270
  var UnacknowledgedOps = class {
1304
1271
  // opId -> op
@@ -1317,10 +1284,6 @@ ${parentKey}`;
1317
1284
  get size() {
1318
1285
  return this.#byOpId.size;
1319
1286
  }
1320
- /** The still-unacknowledged op with the given opId, if any. */
1321
- get(opId) {
1322
- return this.#byOpId.get(opId);
1323
- }
1324
1287
  /**
1325
1288
  * Mark the given Op as still unacknowledged.
1326
1289
  */
@@ -1420,8 +1383,8 @@ function createManagedPool(options) {
1420
1383
  deleteNode: (id) => void nodes.delete(id),
1421
1384
  generateId: () => `${getCurrentConnectionId()}:${clock++}`,
1422
1385
  generateOpId: () => `${getCurrentConnectionId()}:${opClock++}`,
1423
- dispatch(ops, reverse, storageUpdates, options2) {
1424
- _optionalChain([onDispatch, 'optionalCall', _23 => _23(ops, reverse, storageUpdates, options2)]);
1386
+ dispatch(ops, reverse, storageUpdates) {
1387
+ _optionalChain([onDispatch, 'optionalCall', _23 => _23(ops, reverse, storageUpdates)]);
1425
1388
  },
1426
1389
  assertStorageIsWritable: () => {
1427
1390
  if (!isStorageWritable()) {
@@ -1444,17 +1407,10 @@ function Orphaned(oldKey, oldPos = asPos(oldKey)) {
1444
1407
  return Object.freeze({ type: "Orphaned", oldKey, oldPos });
1445
1408
  }
1446
1409
  var AbstractCrdt = class {
1410
+ // ^^^^^^^^^^^^ TODO: Make this an interface
1447
1411
  #pool;
1448
1412
  #id;
1449
1413
  #parent = NoParent;
1450
- constructor() {
1451
- Object.defineProperty(this, kInternal, {
1452
- value: {
1453
- getId: () => this.#id
1454
- },
1455
- enumerable: false
1456
- });
1457
- }
1458
1414
  /** @internal */
1459
1415
  _getParentKeyOrThrow() {
1460
1416
  switch (this.parent.type) {
@@ -1507,14 +1463,11 @@ var AbstractCrdt = class {
1507
1463
  }
1508
1464
  }
1509
1465
  /** @internal */
1510
- _apply(op, source) {
1466
+ _apply(op, _isLocal) {
1511
1467
  switch (op.type) {
1512
1468
  case OpCode.DELETE_CRDT: {
1513
1469
  if (this.parent.type === "HasParent") {
1514
- return this.parent.node._detachChild(
1515
- crdtAsLiveNode(this),
1516
- toUpdateSource(source)
1517
- );
1470
+ return this.parent.node._detachChild(crdtAsLiveNode(this));
1518
1471
  }
1519
1472
  return { modified: false };
1520
1473
  }
@@ -1704,8 +1657,8 @@ var LiveFile = class _LiveFile extends AbstractCrdt {
1704
1657
  throw new Error("A LiveFile node cannot have children");
1705
1658
  }
1706
1659
  /** @internal */
1707
- _apply(op, source) {
1708
- return super._apply(op, source);
1660
+ _apply(op, isLocal) {
1661
+ return super._apply(op, isLocal);
1709
1662
  }
1710
1663
  /** @internal */
1711
1664
  _toTreeNode(key) {
@@ -4924,6 +4877,9 @@ var ManagedSocket = class {
4924
4877
  }
4925
4878
  };
4926
4879
 
4880
+ // src/internal.ts
4881
+ var kInternal = /* @__PURE__ */ Symbol();
4882
+
4927
4883
  // src/lib/IncrementalJsonParser.ts
4928
4884
  var EMPTY_OBJECT = Object.freeze({});
4929
4885
  var NULL_KEYWORD_CHARS = Array.from(new Set("null"));
@@ -6925,8 +6881,8 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
6925
6881
  throw new Error("Method not implemented.");
6926
6882
  }
6927
6883
  /** @internal */
6928
- _apply(op, source) {
6929
- return super._apply(op, source);
6884
+ _apply(op, isLocal) {
6885
+ return super._apply(op, isLocal);
6930
6886
  }
6931
6887
  /** @internal */
6932
6888
  _toTreeNode(key) {
@@ -7087,7 +7043,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7087
7043
  item._detach();
7088
7044
  }
7089
7045
  }
7090
- #applyRemoteSet(op) {
7046
+ #applySetRemote(op) {
7091
7047
  if (this._pool === void 0) {
7092
7048
  throw new Error("Can't attach child if managed pool is not present");
7093
7049
  }
@@ -7105,11 +7061,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
7105
7061
  itemWithSamePosition._detach();
7106
7062
  this.#items.add(child);
7107
7063
  return {
7108
- modified: makeUpdate(
7109
- this,
7110
- [setDelta(indexOfItemWithSamePosition, child)],
7111
- REMOTE
7112
- ),
7064
+ modified: makeUpdate(this, [
7065
+ setDelta(indexOfItemWithSamePosition, child)
7066
+ ]),
7113
7067
  reverse: []
7114
7068
  };
7115
7069
  } else {
@@ -7120,22 +7074,20 @@ var LiveList = class _LiveList extends AbstractCrdt {
7120
7074
  setDelta(indexOfItemWithSamePosition, child)
7121
7075
  ];
7122
7076
  const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
7123
- op.deletedId,
7124
- REMOTE
7077
+ op.deletedId
7125
7078
  );
7126
7079
  if (deleteDelta2) {
7127
7080
  delta.push(deleteDelta2);
7128
7081
  }
7129
7082
  return {
7130
- modified: makeUpdate(this, delta, REMOTE),
7083
+ modified: makeUpdate(this, delta),
7131
7084
  reverse: []
7132
7085
  };
7133
7086
  }
7134
7087
  } else {
7135
7088
  const updates = [];
7136
7089
  const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
7137
- op.deletedId,
7138
- REMOTE
7090
+ op.deletedId
7139
7091
  );
7140
7092
  if (deleteDelta2) {
7141
7093
  updates.push(deleteDelta2);
@@ -7144,32 +7096,29 @@ var LiveList = class _LiveList extends AbstractCrdt {
7144
7096
  updates.push(insertDelta(this._indexOfPosition(key), child));
7145
7097
  return {
7146
7098
  reverse: [],
7147
- modified: makeUpdate(this, updates, REMOTE)
7099
+ modified: makeUpdate(this, updates)
7148
7100
  };
7149
7101
  }
7150
7102
  }
7151
- #applySetAck(op, source) {
7103
+ #applySetAck(op) {
7152
7104
  if (this._pool === void 0) {
7153
7105
  throw new Error("Can't attach child if managed pool is not present");
7154
7106
  }
7155
7107
  const delta = [];
7156
- const deletedDelta = this.#detachItemAssociatedToSetOperation(
7157
- op.deletedId,
7158
- source
7159
- );
7108
+ const deletedDelta = this.#detachItemAssociatedToSetOperation(op.deletedId);
7160
7109
  if (deletedDelta) {
7161
7110
  delta.push(deletedDelta);
7162
7111
  }
7163
7112
  const unacknowledgedOpId = this.#unacknowledgedSetOpIdAt(op.parentKey);
7164
7113
  if (unacknowledgedOpId !== void 0 && unacknowledgedOpId !== op.opId) {
7165
- return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta, source), reverse: [] };
7114
+ return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
7166
7115
  }
7167
7116
  const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey);
7168
7117
  const existingItem = this.#items.find((item) => item._id === op.id);
7169
7118
  if (existingItem !== void 0) {
7170
7119
  if (existingItem._parentKey === op.parentKey) {
7171
7120
  return {
7172
- modified: delta.length > 0 ? makeUpdate(this, delta, source) : false,
7121
+ modified: delta.length > 0 ? makeUpdate(this, delta) : false,
7173
7122
  reverse: []
7174
7123
  };
7175
7124
  }
@@ -7187,7 +7136,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7187
7136
  delta.push(moveDelta(prevIndex, newIndex, existingItem));
7188
7137
  }
7189
7138
  return {
7190
- modified: delta.length > 0 ? makeUpdate(this, delta, source) : false,
7139
+ modified: delta.length > 0 ? makeUpdate(this, delta) : false,
7191
7140
  reverse: []
7192
7141
  };
7193
7142
  } else {
@@ -7197,15 +7146,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
7197
7146
  this.#implicitlyDeletedItems.delete(orphan);
7198
7147
  const recreatedItemIndex = this.#insert(orphan);
7199
7148
  return {
7200
- modified: makeUpdate(
7201
- this,
7202
- [
7203
- // If there is an item at this position, update is a set, else it's an insert
7204
- indexOfItemWithSamePosition === -1 ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan),
7205
- ...delta
7206
- ],
7207
- source
7208
- ),
7149
+ modified: makeUpdate(this, [
7150
+ // If there is an item at this position, update is a set, else it's an insert
7151
+ indexOfItemWithSamePosition === -1 ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan),
7152
+ ...delta
7153
+ ]),
7209
7154
  reverse: []
7210
7155
  };
7211
7156
  } else {
@@ -7220,15 +7165,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
7220
7165
  op.parentKey
7221
7166
  );
7222
7167
  return {
7223
- modified: makeUpdate(
7224
- this,
7225
- [
7226
- // If there is an item at this position, update is a set, else it's an insert
7227
- indexOfItemWithSamePosition === -1 ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem),
7228
- ...delta
7229
- ],
7230
- source
7231
- ),
7168
+ modified: makeUpdate(this, [
7169
+ // If there is an item at this position, update is a set, else it's an insert
7170
+ indexOfItemWithSamePosition === -1 ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem),
7171
+ ...delta
7172
+ ]),
7232
7173
  reverse: []
7233
7174
  };
7234
7175
  }
@@ -7237,7 +7178,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7237
7178
  /**
7238
7179
  * Returns the update delta of the deletion or null
7239
7180
  */
7240
- #detachItemAssociatedToSetOperation(deletedId, source) {
7181
+ #detachItemAssociatedToSetOperation(deletedId) {
7241
7182
  if (deletedId === void 0 || this._pool === void 0) {
7242
7183
  return null;
7243
7184
  }
@@ -7245,7 +7186,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7245
7186
  if (deletedItem === void 0) {
7246
7187
  return null;
7247
7188
  }
7248
- const result = this._detachChild(deletedItem, source);
7189
+ const result = this._detachChild(deletedItem);
7249
7190
  if (result.modified === false) {
7250
7191
  return null;
7251
7192
  }
@@ -7263,11 +7204,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
7263
7204
  const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
7264
7205
  const bumpDeltas = this.#bumpUnackedPushesAbove(key);
7265
7206
  return {
7266
- modified: makeUpdate(
7267
- this,
7268
- [insertDelta(newIndex, newItem), ...bumpDeltas],
7269
- REMOTE
7270
- ),
7207
+ modified: makeUpdate(this, [
7208
+ insertDelta(newIndex, newItem),
7209
+ ...bumpDeltas
7210
+ ]),
7271
7211
  reverse: []
7272
7212
  };
7273
7213
  }
@@ -7348,7 +7288,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7348
7288
  }
7349
7289
  return deltas;
7350
7290
  }
7351
- #applyInsertAck(op, source) {
7291
+ #applyInsertAck(op) {
7352
7292
  const existingItem = this.#items.find((item) => item._id === op.id);
7353
7293
  const key = asPos(op.parentKey);
7354
7294
  const itemIndexAtPosition = this._indexOfPosition(key);
@@ -7370,11 +7310,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
7370
7310
  return { modified: false };
7371
7311
  }
7372
7312
  return {
7373
- modified: makeUpdate(
7374
- this,
7375
- [moveDelta(oldPositionIndex, newIndex, existingItem)],
7376
- source
7377
- ),
7313
+ modified: makeUpdate(this, [
7314
+ moveDelta(oldPositionIndex, newIndex, existingItem)
7315
+ ]),
7378
7316
  reverse: []
7379
7317
  };
7380
7318
  }
@@ -7386,7 +7324,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7386
7324
  this.#insert(orphan);
7387
7325
  const newIndex = this._indexOfPosition(key);
7388
7326
  return {
7389
- modified: makeUpdate(this, [insertDelta(newIndex, orphan)], source),
7327
+ modified: makeUpdate(this, [insertDelta(newIndex, orphan)]),
7390
7328
  reverse: []
7391
7329
  };
7392
7330
  } else {
@@ -7395,13 +7333,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
7395
7333
  }
7396
7334
  const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
7397
7335
  return {
7398
- modified: makeUpdate(this, [insertDelta(newIndex, newItem)], source),
7336
+ modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
7399
7337
  reverse: []
7400
7338
  };
7401
7339
  }
7402
7340
  }
7403
7341
  }
7404
- #applyLocalInsert(op, source) {
7342
+ #applyInsertUndoRedo(op) {
7405
7343
  const { id, parentKey: key } = op;
7406
7344
  const child = creationOpToLiveNode(op);
7407
7345
  if (_optionalChain([this, 'access', _151 => _151._pool, 'optionalAccess', _152 => _152.getNode, 'call', _153 => _153(id)]) !== void 0) {
@@ -7420,11 +7358,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
7420
7358
  this.#insert(child);
7421
7359
  const newIndex = this._indexOfPosition(newKey);
7422
7360
  return {
7423
- modified: makeUpdate(this, [insertDelta(newIndex, child)], source),
7361
+ modified: makeUpdate(this, [insertDelta(newIndex, child)]),
7424
7362
  reverse: [{ type: OpCode.DELETE_CRDT, id }]
7425
7363
  };
7426
7364
  }
7427
- #applyLocalSet(op, source) {
7365
+ #applySetUndoRedo(op) {
7428
7366
  const { id, parentKey: key } = op;
7429
7367
  const child = creationOpToLiveNode(op);
7430
7368
  if (_optionalChain([this, 'access', _162 => _162._pool, 'optionalAccess', _163 => _163.getNode, 'call', _164 => _164(id)]) !== void 0) {
@@ -7446,48 +7384,46 @@ var LiveList = class _LiveList extends AbstractCrdt {
7446
7384
  );
7447
7385
  const delta = [setDelta(indexOfItemWithSameKey, child)];
7448
7386
  const deletedDelta = this.#detachItemAssociatedToSetOperation(
7449
- op.deletedId,
7450
- source
7387
+ op.deletedId
7451
7388
  );
7452
7389
  if (deletedDelta) {
7453
7390
  delta.push(deletedDelta);
7454
7391
  }
7455
7392
  return {
7456
- modified: makeUpdate(this, delta, source),
7393
+ modified: makeUpdate(this, delta),
7457
7394
  reverse
7458
7395
  };
7459
7396
  } else {
7460
7397
  this.#insert(child);
7461
- this.#detachItemAssociatedToSetOperation(op.deletedId, source);
7398
+ this.#detachItemAssociatedToSetOperation(op.deletedId);
7462
7399
  const newIndex = this._indexOfPosition(newKey);
7463
7400
  return {
7464
7401
  reverse: [{ type: OpCode.DELETE_CRDT, id }],
7465
- modified: makeUpdate(this, [insertDelta(newIndex, child)], source)
7402
+ modified: makeUpdate(this, [insertDelta(newIndex, child)])
7466
7403
  };
7467
7404
  }
7468
7405
  }
7469
7406
  /** @internal */
7470
- _attachChild(op, opSource) {
7471
- const source = toUpdateSource(opSource);
7407
+ _attachChild(op, source) {
7472
7408
  if (this._pool === void 0) {
7473
7409
  throw new Error("Can't attach child if managed pool is not present");
7474
7410
  }
7475
7411
  let result;
7476
7412
  if (op.intent === "set") {
7477
- if (opSource.origin === "remote") {
7478
- result = this.#applyRemoteSet(op);
7479
- } else if (!opSource.optimistic) {
7480
- result = this.#applySetAck(op, source);
7413
+ if (source === 1 /* THEIRS */) {
7414
+ result = this.#applySetRemote(op);
7415
+ } else if (source === 2 /* OURS */) {
7416
+ result = this.#applySetAck(op);
7481
7417
  } else {
7482
- result = this.#applyLocalSet(op, source);
7418
+ result = this.#applySetUndoRedo(op);
7483
7419
  }
7484
7420
  } else {
7485
- if (opSource.origin === "remote") {
7421
+ if (source === 1 /* THEIRS */) {
7486
7422
  result = this.#applyRemoteInsert(op);
7487
- } else if (!opSource.optimistic) {
7488
- result = this.#applyInsertAck(op, source);
7423
+ } else if (source === 2 /* OURS */) {
7424
+ result = this.#applyInsertAck(op);
7489
7425
  } else {
7490
- result = this.#applyLocalInsert(op, source);
7426
+ result = this.#applyInsertUndoRedo(op);
7491
7427
  }
7492
7428
  }
7493
7429
  if (result.modified !== false) {
@@ -7496,7 +7432,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7496
7432
  return result;
7497
7433
  }
7498
7434
  /** @internal */
7499
- _detachChild(child, source) {
7435
+ _detachChild(child) {
7500
7436
  if (child) {
7501
7437
  const parentKey = nn(child._parentKey);
7502
7438
  const reverse = child._toOps(nn(this._id), parentKey);
@@ -7511,23 +7447,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
7511
7447
  this.invalidate();
7512
7448
  child._detach();
7513
7449
  return {
7514
- modified: makeUpdate(
7515
- this,
7516
- [deleteDelta(indexToDelete, previousNode)],
7517
- source
7518
- ),
7450
+ modified: makeUpdate(this, [deleteDelta(indexToDelete, previousNode)]),
7519
7451
  reverse
7520
7452
  };
7521
7453
  }
7522
7454
  return { modified: false };
7523
7455
  }
7524
- #applyRemoteSetChildKey(newKey, child) {
7456
+ #applySetChildKeyRemote(newKey, child) {
7525
7457
  if (this.#implicitlyDeletedItems.has(child)) {
7526
7458
  this.#implicitlyDeletedItems.delete(child);
7527
7459
  child._setParentLink(this, newKey);
7528
7460
  const newIndex = this.#insert(child);
7529
7461
  return {
7530
- modified: makeUpdate(this, [insertDelta(newIndex, child)], REMOTE),
7462
+ modified: makeUpdate(this, [insertDelta(newIndex, child)]),
7531
7463
  reverse: []
7532
7464
  };
7533
7465
  }
@@ -7548,11 +7480,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7548
7480
  };
7549
7481
  }
7550
7482
  return {
7551
- modified: makeUpdate(
7552
- this,
7553
- [moveDelta(previousIndex, newIndex, child)],
7554
- REMOTE
7555
- ),
7483
+ modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
7556
7484
  reverse: []
7557
7485
  };
7558
7486
  } else {
@@ -7569,16 +7497,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
7569
7497
  };
7570
7498
  }
7571
7499
  return {
7572
- modified: makeUpdate(
7573
- this,
7574
- [moveDelta(previousIndex, newIndex, child)],
7575
- REMOTE
7576
- ),
7500
+ modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
7577
7501
  reverse: []
7578
7502
  };
7579
7503
  }
7580
7504
  }
7581
- #applySetChildKeyAck(newKey, child, source) {
7505
+ #applySetChildKeyAck(newKey, child) {
7582
7506
  const previousKey = nn(child._parentKey);
7583
7507
  if (this.#implicitlyDeletedItems.has(child)) {
7584
7508
  const existingItemIndex = this._indexOfPosition(newKey);
@@ -7597,7 +7521,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7597
7521
  child._setParentLink(this, newKey);
7598
7522
  const newIndex = this.#insert(child);
7599
7523
  return {
7600
- modified: makeUpdate(this, [insertDelta(newIndex, child)], source),
7524
+ modified: makeUpdate(this, [insertDelta(newIndex, child)]),
7601
7525
  reverse: []
7602
7526
  };
7603
7527
  } else {
@@ -7625,17 +7549,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
7625
7549
  };
7626
7550
  } else {
7627
7551
  return {
7628
- modified: makeUpdate(
7629
- this,
7630
- [moveDelta(previousIndex, newIndex, child)],
7631
- source
7632
- ),
7552
+ modified: makeUpdate(this, [
7553
+ moveDelta(previousIndex, newIndex, child)
7554
+ ]),
7633
7555
  reverse: []
7634
7556
  };
7635
7557
  }
7636
7558
  }
7637
7559
  }
7638
- #applyLocalSetChildKey(newKey, child, source) {
7560
+ #applySetChildKeyUndoRedo(newKey, child) {
7639
7561
  const previousKey = nn(child._parentKey);
7640
7562
  const previousIndex = this.#items.findIndex((item) => item === child);
7641
7563
  const existingItemIndex = this._indexOfPosition(newKey);
@@ -7654,11 +7576,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7654
7576
  };
7655
7577
  }
7656
7578
  return {
7657
- modified: makeUpdate(
7658
- this,
7659
- [moveDelta(previousIndex, newIndex, child)],
7660
- source
7661
- ),
7579
+ modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
7662
7580
  reverse: [
7663
7581
  {
7664
7582
  type: OpCode.SET_PARENT_KEY,
@@ -7669,19 +7587,18 @@ var LiveList = class _LiveList extends AbstractCrdt {
7669
7587
  };
7670
7588
  }
7671
7589
  /** @internal */
7672
- _setChildKey(newKey, child, opSource) {
7673
- const source = toUpdateSource(opSource);
7674
- if (opSource.origin === "remote") {
7675
- return this.#applyRemoteSetChildKey(newKey, child);
7676
- } else if (!opSource.optimistic) {
7677
- return this.#applySetChildKeyAck(newKey, child, source);
7590
+ _setChildKey(newKey, child, source) {
7591
+ if (source === 1 /* THEIRS */) {
7592
+ return this.#applySetChildKeyRemote(newKey, child);
7593
+ } else if (source === 2 /* OURS */) {
7594
+ return this.#applySetChildKeyAck(newKey, child);
7678
7595
  } else {
7679
- return this.#applyLocalSetChildKey(newKey, child, source);
7596
+ return this.#applySetChildKeyUndoRedo(newKey, child);
7680
7597
  }
7681
7598
  }
7682
7599
  /** @internal */
7683
- _apply(op, source) {
7684
- return super._apply(op, source);
7600
+ _apply(op, isLocal) {
7601
+ return super._apply(op, isLocal);
7685
7602
  }
7686
7603
  /** @internal */
7687
7604
  _serialize() {
@@ -7742,7 +7659,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7742
7659
  intent === "push" ? addIntentToRootOp(ops, "push") : ops,
7743
7660
  [{ type: OpCode.DELETE_CRDT, id }],
7744
7661
  /* @__PURE__ */ new Map([
7745
- [this._id, makeUpdate(this, [insertDelta(index, value)], LOCAL_EDIT)]
7662
+ [this._id, makeUpdate(this, [insertDelta(index, value)])]
7746
7663
  ])
7747
7664
  );
7748
7665
  }
@@ -7783,10 +7700,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7783
7700
  this.#updateItemPositionAt(index, position);
7784
7701
  if (this._pool && this._id) {
7785
7702
  const storageUpdates = /* @__PURE__ */ new Map([
7786
- [
7787
- this._id,
7788
- makeUpdate(this, [moveDelta(index, targetIndex, item)], LOCAL_EDIT)
7789
- ]
7703
+ [this._id, makeUpdate(this, [moveDelta(index, targetIndex, item)])]
7790
7704
  ]);
7791
7705
  this._pool.dispatch(
7792
7706
  [
@@ -7829,7 +7743,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7829
7743
  const storageUpdates = /* @__PURE__ */ new Map();
7830
7744
  storageUpdates.set(
7831
7745
  nn(this._id),
7832
- makeUpdate(this, [deleteDelta(index, item)], LOCAL_EDIT)
7746
+ makeUpdate(this, [deleteDelta(index, item)])
7833
7747
  );
7834
7748
  this._pool.dispatch(
7835
7749
  [
@@ -7869,10 +7783,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7869
7783
  this.#items.clear();
7870
7784
  this.invalidate();
7871
7785
  const storageUpdates = /* @__PURE__ */ new Map();
7872
- storageUpdates.set(
7873
- nn(this._id),
7874
- makeUpdate(this, updateDelta, LOCAL_EDIT)
7875
- );
7786
+ storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta));
7876
7787
  this._pool.dispatch(ops, reverseOps, storageUpdates);
7877
7788
  } else {
7878
7789
  for (const item of this.#items) {
@@ -7902,10 +7813,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7902
7813
  const id = this._pool.generateId();
7903
7814
  value._attach(id, this._pool);
7904
7815
  const storageUpdates = /* @__PURE__ */ new Map();
7905
- storageUpdates.set(
7906
- this._id,
7907
- makeUpdate(this, [setDelta(index, value)], LOCAL_EDIT)
7908
- );
7816
+ storageUpdates.set(this._id, makeUpdate(this, [setDelta(index, value)]));
7909
7817
  const ops = addIntentToRootOp(
7910
7818
  value._toOpsWithOpId(this._id, position, this._pool),
7911
7819
  "set",
@@ -8078,12 +7986,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
8078
7986
  );
8079
7987
  }
8080
7988
  };
8081
- function makeUpdate(liveList, deltaUpdates, source) {
7989
+ function makeUpdate(liveList, deltaUpdates) {
8082
7990
  return {
8083
7991
  node: liveList,
8084
7992
  type: "LiveList",
8085
- updates: deltaUpdates,
8086
- source
7993
+ updates: deltaUpdates
8087
7994
  };
8088
7995
  }
8089
7996
  function setDelta(index, item) {
@@ -8202,9 +8109,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8202
8109
  if (this._pool.getNode(id) !== void 0) {
8203
8110
  return { modified: false };
8204
8111
  }
8205
- if (source.origin === "remote") {
8206
- this.#unacknowledgedSet.delete(key);
8207
- } else if (!source.optimistic) {
8112
+ if (source === 2 /* OURS */) {
8208
8113
  const lastUpdateOpId = this.#unacknowledgedSet.get(key);
8209
8114
  if (lastUpdateOpId === opId) {
8210
8115
  this.#unacknowledgedSet.delete(key);
@@ -8212,6 +8117,8 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8212
8117
  } else if (lastUpdateOpId !== void 0) {
8213
8118
  return { modified: false };
8214
8119
  }
8120
+ } else if (source === 1 /* THEIRS */) {
8121
+ this.#unacknowledgedSet.delete(key);
8215
8122
  }
8216
8123
  const previousValue = this.#map.get(key);
8217
8124
  let reverse;
@@ -8230,8 +8137,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8230
8137
  modified: {
8231
8138
  node: this,
8232
8139
  type: "LiveMap",
8233
- updates: { [key]: { type: "update" } },
8234
- source: toUpdateSource(source)
8140
+ updates: { [key]: { type: "update" } }
8235
8141
  },
8236
8142
  reverse
8237
8143
  };
@@ -8244,7 +8150,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8244
8150
  }
8245
8151
  }
8246
8152
  /** @internal */
8247
- _detachChild(child, source) {
8153
+ _detachChild(child) {
8248
8154
  const id = nn(this._id);
8249
8155
  const parentKey = nn(child._parentKey);
8250
8156
  const reverse = child._toOps(id, parentKey);
@@ -8263,8 +8169,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8263
8169
  type: "delete",
8264
8170
  deletedItem: liveNodeToLson(child)
8265
8171
  }
8266
- },
8267
- source
8172
+ }
8268
8173
  };
8269
8174
  return { modified: storageUpdate, reverse };
8270
8175
  }
@@ -8313,8 +8218,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8313
8218
  storageUpdates.set(this._id, {
8314
8219
  node: this,
8315
8220
  type: "LiveMap",
8316
- updates: { [key]: { type: "update" } },
8317
- source: LOCAL_EDIT
8221
+ updates: { [key]: { type: "update" } }
8318
8222
  });
8319
8223
  const ops = item._toOpsWithOpId(this._id, key, this._pool);
8320
8224
  this.#unacknowledgedSet.set(key, nn(ops[0].opId));
@@ -8363,8 +8267,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
8363
8267
  type: "delete",
8364
8268
  deletedItem: liveNodeToLson(item)
8365
8269
  }
8366
- },
8367
- source: LOCAL_EDIT
8270
+ }
8368
8271
  });
8369
8272
  this._pool.dispatch(
8370
8273
  [
@@ -8729,7 +8632,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8729
8632
  }
8730
8633
  return { modified: false };
8731
8634
  }
8732
- if (source.origin === "local" && source.optimistic) {
8635
+ if (source === 0 /* LOCAL */) {
8733
8636
  this.#unackedOpsByKey.set(key, nn(opId));
8734
8637
  } else if (this.#unackedOpsByKey.get(key) === void 0) {
8735
8638
  } else if (this.#unackedOpsByKey.get(key) === opId) {
@@ -8767,13 +8670,12 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8767
8670
  modified: {
8768
8671
  node: this,
8769
8672
  type: "LiveObject",
8770
- updates: { [key]: { type: "update" } },
8771
- source: toUpdateSource(source)
8673
+ updates: { [key]: { type: "update" } }
8772
8674
  }
8773
8675
  };
8774
8676
  }
8775
8677
  /** @internal */
8776
- _detachChild(child, source) {
8678
+ _detachChild(child) {
8777
8679
  if (child) {
8778
8680
  const id = nn(this._id);
8779
8681
  const parentKey = nn(child._parentKey);
@@ -8791,8 +8693,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8791
8693
  type: "LiveObject",
8792
8694
  updates: {
8793
8695
  [parentKey]: { type: "delete", deletedItem }
8794
- },
8795
- source
8696
+ }
8796
8697
  };
8797
8698
  return { modified: storageUpdate, reverse };
8798
8699
  }
@@ -8808,13 +8709,13 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8808
8709
  }
8809
8710
  }
8810
8711
  /** @internal */
8811
- _apply(op, source) {
8712
+ _apply(op, isLocal) {
8812
8713
  if (op.type === OpCode.UPDATE_OBJECT) {
8813
- return this.#applyUpdate(op, source);
8714
+ return this.#applyUpdate(op, isLocal);
8814
8715
  } else if (op.type === OpCode.DELETE_OBJECT_KEY) {
8815
- return this.#applyDeleteObjectKey(op, source);
8716
+ return this.#applyDeleteObjectKey(op, isLocal);
8816
8717
  }
8817
- return super._apply(op, source);
8718
+ return super._apply(op, isLocal);
8818
8719
  }
8819
8720
  /** @internal */
8820
8721
  _serialize() {
@@ -8838,7 +8739,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8838
8739
  };
8839
8740
  }
8840
8741
  }
8841
- #applyUpdate(op, source) {
8742
+ #applyUpdate(op, isLocal) {
8842
8743
  let isModified = false;
8843
8744
  const id = nn(this._id);
8844
8745
  const reverse = [];
@@ -8866,7 +8767,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8866
8767
  if (value === void 0) {
8867
8768
  continue;
8868
8769
  }
8869
- if (source.origin === "local" && source.optimistic) {
8770
+ if (isLocal) {
8870
8771
  this.#unackedOpsByKey.set(key, nn(op.opId));
8871
8772
  } else if (this.#unackedOpsByKey.get(key) === void 0) {
8872
8773
  isModified = true;
@@ -8893,19 +8794,18 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8893
8794
  modified: {
8894
8795
  node: this,
8895
8796
  type: "LiveObject",
8896
- updates: updateDelta,
8897
- source: toUpdateSource(source)
8797
+ updates: updateDelta
8898
8798
  },
8899
8799
  reverse
8900
8800
  } : { modified: false };
8901
8801
  }
8902
- #applyDeleteObjectKey(op, source) {
8802
+ #applyDeleteObjectKey(op, isLocal) {
8903
8803
  const key = op.key;
8904
8804
  const oldValue = this.#synced.get(key);
8905
8805
  if (oldValue === void 0) {
8906
8806
  return { modified: false };
8907
8807
  }
8908
- if (!(source.origin === "local" && source.optimistic) && this.#unackedOpsByKey.get(key) !== void 0) {
8808
+ if (!isLocal && this.#unackedOpsByKey.get(key) !== void 0) {
8909
8809
  return { modified: false };
8910
8810
  }
8911
8811
  const id = nn(this._id);
@@ -8931,8 +8831,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8931
8831
  type: "LiveObject",
8932
8832
  updates: {
8933
8833
  [op.key]: { type: "delete", deletedItem: oldValue }
8934
- },
8935
- source: toUpdateSource(source)
8834
+ }
8936
8835
  },
8937
8836
  reverse
8938
8837
  };
@@ -8978,8 +8877,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8978
8877
  updates: {
8979
8878
  ..._optionalChain([existing, 'optionalAccess', _228 => _228.updates]),
8980
8879
  [key]: { type: "update" }
8981
- },
8982
- source: LOCAL_EDIT
8880
+ }
8983
8881
  });
8984
8882
  this._pool.dispatch(ops, reverse, storageUpdates);
8985
8883
  }
@@ -9013,8 +8911,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
9013
8911
  type: "delete",
9014
8912
  deletedItem: oldValue2
9015
8913
  }
9016
- },
9017
- source: LOCAL_EDIT
8914
+ }
9018
8915
  });
9019
8916
  return [[], [], storageUpdates2];
9020
8917
  }
@@ -9062,8 +8959,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
9062
8959
  type: "LiveObject",
9063
8960
  updates: {
9064
8961
  [key]: { type: "delete", deletedItem: oldValue }
9065
- },
9066
- source: LOCAL_EDIT
8962
+ }
9067
8963
  });
9068
8964
  return [ops, reverse, storageUpdates];
9069
8965
  }
@@ -9201,8 +9097,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
9201
9097
  storageUpdates.set(this._id, {
9202
9098
  node: this,
9203
9099
  type: "LiveObject",
9204
- updates: updateDelta,
9205
- source: LOCAL_EDIT
9100
+ updates: updateDelta
9206
9101
  });
9207
9102
  this._pool.dispatch(ops, reverseOps, storageUpdates);
9208
9103
  }
@@ -9284,1352 +9179,172 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
9284
9179
  }
9285
9180
  }, _class2.__initStatic(), _class2);
9286
9181
 
9287
- // src/crdts/liveTextOps.ts
9288
- function attributesEqual(left, right) {
9289
- if (left === right) {
9290
- return true;
9182
+ // src/crdts/liveblocks-helpers.ts
9183
+ function creationOpToLiveNode(op) {
9184
+ return lsonToLiveNode(creationOpToLson(op));
9185
+ }
9186
+ function creationOpToLson(op) {
9187
+ switch (op.type) {
9188
+ case OpCode.CREATE_FILE:
9189
+ return new LiveFile(op.data);
9190
+ case OpCode.CREATE_REGISTER:
9191
+ return op.data;
9192
+ case OpCode.CREATE_OBJECT:
9193
+ return new LiveObject(op.data);
9194
+ case OpCode.CREATE_MAP:
9195
+ return new LiveMap();
9196
+ case OpCode.CREATE_LIST:
9197
+ return new LiveList([]);
9198
+ default:
9199
+ return assertNever(op, "Unknown creation Op");
9291
9200
  }
9292
- if (left === void 0 || right === void 0) {
9293
- return false;
9201
+ }
9202
+ function isSameNodeOrChildOf(node, parent) {
9203
+ if (node === parent) {
9204
+ return true;
9294
9205
  }
9295
- const leftKeys = Object.keys(left);
9296
- const rightKeys = Object.keys(right);
9297
- if (leftKeys.length !== rightKeys.length) {
9298
- return false;
9206
+ if (node.parent.type === "HasParent") {
9207
+ return isSameNodeOrChildOf(node.parent.node, parent);
9299
9208
  }
9300
- for (const key of leftKeys) {
9301
- if (left[key] !== right[key]) {
9302
- return false;
9209
+ return false;
9210
+ }
9211
+ function liveObjectFromNodeStream(nodes) {
9212
+ const pool = createManagedPool({
9213
+ getCurrentConnectionId: () => {
9214
+ throw new Error(
9215
+ "Cannot mutate a historic storage version: it is a read-only snapshot"
9216
+ );
9303
9217
  }
9304
- }
9305
- return true;
9218
+ });
9219
+ return LiveObject._fromItems(nodes, pool);
9306
9220
  }
9307
- function cloneAttributes(attributes) {
9308
- return attributes === void 0 ? void 0 : freeze({ ...attributes });
9221
+ function deserialize(node, parentToChildren, pool) {
9222
+ if (isObjectStorageNode(node)) {
9223
+ return LiveObject._deserialize(node, parentToChildren, pool);
9224
+ } else if (isListStorageNode(node)) {
9225
+ return LiveList._deserialize(node, parentToChildren, pool);
9226
+ } else if (isMapStorageNode(node)) {
9227
+ return LiveMap._deserialize(node, parentToChildren, pool);
9228
+ } else if (isRegisterStorageNode(node)) {
9229
+ return LiveRegister._deserialize(node, parentToChildren, pool);
9230
+ } else if (isFileStorageNode(node)) {
9231
+ return LiveFile._deserialize(node, parentToChildren, pool);
9232
+ } else {
9233
+ throw new Error("Unexpected CRDT type");
9234
+ }
9309
9235
  }
9310
- function normalizeSegments(segments) {
9311
- const normalized = [];
9312
- for (const segment of segments) {
9313
- if (segment.text.length === 0) {
9314
- continue;
9315
- }
9316
- const last = normalized.at(-1);
9317
- const attributes = cloneAttributes(segment.attributes);
9318
- if (last !== void 0 && attributesEqual(last.attributes, attributes)) {
9319
- last.text += segment.text;
9320
- } else {
9321
- normalized.push({ text: segment.text, attributes });
9322
- }
9236
+ function deserializeToLson(node, parentToChildren, pool) {
9237
+ if (isObjectStorageNode(node)) {
9238
+ return LiveObject._deserialize(node, parentToChildren, pool);
9239
+ } else if (isListStorageNode(node)) {
9240
+ return LiveList._deserialize(node, parentToChildren, pool);
9241
+ } else if (isMapStorageNode(node)) {
9242
+ return LiveMap._deserialize(node, parentToChildren, pool);
9243
+ } else if (isRegisterStorageNode(node)) {
9244
+ return node[1].data;
9245
+ } else if (isFileStorageNode(node)) {
9246
+ return LiveFile._deserialize(node, parentToChildren, pool);
9247
+ } else {
9248
+ throw new Error("Unexpected CRDT type");
9323
9249
  }
9324
- return normalized;
9325
9250
  }
9326
- function dataToSegments(data) {
9327
- return normalizeSegments(
9328
- data.map(([text, attributes]) => ({
9329
- text,
9330
- attributes
9331
- }))
9332
- );
9251
+ function isLiveStructure(value) {
9252
+ return isLiveList(value) || isLiveMap(value) || isLiveObject(value) || isLiveFile(value);
9333
9253
  }
9334
- function segmentsToData(segments) {
9335
- return segments.map(
9336
- (segment) => segment.attributes === void 0 ? [segment.text] : [segment.text, { ...segment.attributes }]
9337
- );
9254
+ function isLiveNode(value) {
9255
+ return isLiveStructure(value) || isLiveRegister(value);
9338
9256
  }
9339
- function textLength(segments) {
9340
- return segments.reduce((sum, segment) => sum + segment.text.length, 0);
9257
+ function isLiveList(value) {
9258
+ return value instanceof LiveList;
9341
9259
  }
9342
- function splitSegmentsAt(segments, index) {
9343
- const result = [];
9344
- let offset = 0;
9345
- for (const segment of segments) {
9346
- const end = offset + segment.text.length;
9347
- if (index > offset && index < end) {
9348
- const before2 = segment.text.slice(0, index - offset);
9349
- const after2 = segment.text.slice(index - offset);
9350
- result.push({ text: before2, attributes: segment.attributes });
9351
- result.push({ text: after2, attributes: segment.attributes });
9352
- } else {
9353
- result.push({ text: segment.text, attributes: segment.attributes });
9354
- }
9355
- offset = end;
9356
- }
9357
- return result;
9260
+ function isLiveMap(value) {
9261
+ return value instanceof LiveMap;
9358
9262
  }
9359
- function clipRange(index, length, contentLength) {
9360
- const clippedIndex = Math.max(0, Math.min(index, contentLength));
9361
- const clippedEnd = Math.max(
9362
- clippedIndex,
9363
- Math.min(index + length, contentLength)
9364
- );
9365
- return { index: clippedIndex, length: clippedEnd - clippedIndex };
9263
+ function isLiveObject(value) {
9264
+ return value instanceof LiveObject;
9366
9265
  }
9367
- function isInSurrogatePair(text, index) {
9368
- const previous = text.charCodeAt(index - 1);
9369
- const next = text.charCodeAt(index);
9370
- return previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343;
9266
+ function isLiveFile(value) {
9267
+ return value instanceof LiveFile;
9371
9268
  }
9372
- function clipIndexToCodePointBoundary(text, index) {
9373
- const clippedIndex = Math.max(0, Math.min(index, text.length));
9374
- return isInSurrogatePair(text, clippedIndex) ? clippedIndex - 1 : clippedIndex;
9269
+ function isLiveRegister(value) {
9270
+ return value instanceof LiveRegister;
9375
9271
  }
9376
- function clipRangeToCodePointBoundaries(text, index, length) {
9377
- const clipped = clipRange(index, length, text.length);
9378
- if (clipped.length === 0) {
9379
- return {
9380
- index: clipIndexToCodePointBoundary(text, clipped.index),
9381
- length: 0
9382
- };
9383
- }
9384
- const clippedEnd = clipped.index + clipped.length;
9385
- const normalizedIndex = isInSurrogatePair(text, clipped.index) ? clipped.index - 1 : clipped.index;
9386
- const normalizedEnd = isInSurrogatePair(text, clippedEnd) ? clippedEnd + 1 : clippedEnd;
9387
- return {
9388
- index: normalizedIndex,
9389
- length: normalizedEnd - normalizedIndex
9390
- };
9272
+ function cloneLson(value) {
9273
+ return value === void 0 ? void 0 : isLiveStructure(value) ? value.clone() : deepClone(value);
9391
9274
  }
9392
- function applyInsert(segments, index, text, attributes) {
9393
- if (text.length === 0) {
9394
- return normalizeSegments(segments);
9395
- }
9396
- const split = splitSegmentsAt(segments, index);
9397
- const result = [];
9398
- let offset = 0;
9399
- let inserted = false;
9400
- for (const segment of split) {
9401
- if (!inserted && offset === index) {
9402
- result.push({ text, attributes });
9403
- inserted = true;
9404
- }
9405
- result.push(segment);
9406
- offset += segment.text.length;
9407
- }
9408
- if (!inserted) {
9409
- result.push({ text, attributes });
9275
+ function liveNodeToLson(obj) {
9276
+ if (obj instanceof LiveRegister) {
9277
+ return obj.data;
9278
+ } else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject || obj instanceof LiveFile) {
9279
+ return obj;
9280
+ } else {
9281
+ return assertNever(obj, "Unknown AbstractCrdt");
9410
9282
  }
9411
- return normalizeSegments(result);
9412
9283
  }
9413
- function extractDeletedSegments(segments, index, length) {
9414
- const split = splitSegmentsAt(
9415
- splitSegmentsAt(segments, index),
9416
- index + length
9417
- );
9418
- const deleted = [];
9419
- let offset = 0;
9420
- for (const segment of split) {
9421
- const end = offset + segment.text.length;
9422
- if (offset >= index && end <= index + length) {
9423
- deleted.push({
9424
- text: segment.text,
9425
- attributes: segment.attributes
9426
- });
9427
- }
9428
- offset = end;
9284
+ function lsonToLiveNode(value) {
9285
+ if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList || value instanceof LiveFile) {
9286
+ return value;
9287
+ } else {
9288
+ return new LiveRegister(value);
9429
9289
  }
9430
- return normalizeSegments(deleted);
9431
9290
  }
9432
- function applyDelete(segments, index, length) {
9433
- const deletedSegments = extractDeletedSegments(segments, index, length);
9434
- const split = splitSegmentsAt(
9435
- splitSegmentsAt(segments, index),
9436
- index + length
9437
- );
9438
- const result = [];
9439
- let offset = 0;
9440
- let deletedText = "";
9441
- for (const segment of split) {
9442
- const end = offset + segment.text.length;
9443
- if (offset >= index && end <= index + length) {
9444
- deletedText += segment.text;
9291
+ function dumpPool(pool) {
9292
+ const rows = Array.from(pool.nodes.values(), (node) => {
9293
+ const parent = node.parent;
9294
+ const parentId = parent.type === "HasParent" ? _nullishCoalesce(parent.node._id, () => ( "?")) : parent.type === "Orphaned" ? "<orphaned>" : "-";
9295
+ let value;
9296
+ if (node instanceof LiveRegister) {
9297
+ value = stringifyOrLog(node.data);
9298
+ } else if (node instanceof LiveList) {
9299
+ value = "<LiveList>";
9300
+ } else if (node instanceof LiveMap) {
9301
+ value = "<LiveMap>";
9302
+ } else if (node instanceof LiveFile) {
9303
+ value = stringifyOrLog(node.data);
9445
9304
  } else {
9446
- result.push(segment);
9305
+ value = "<LiveObject>";
9447
9306
  }
9448
- offset = end;
9449
- }
9450
- return {
9451
- segments: normalizeSegments(result),
9452
- deletedText,
9453
- deletedSegments
9454
- };
9307
+ return { id: nn(node._id), parentId, key: _nullishCoalesce(node._parentKey, () => ( "")), value };
9308
+ });
9309
+ rows.sort((a, b) => {
9310
+ if (a.parentId !== b.parentId) return a.parentId < b.parentId ? -1 : 1;
9311
+ if (a.key !== b.key) return a.key < b.key ? -1 : 1;
9312
+ return 0;
9313
+ });
9314
+ return rows.map(
9315
+ (r) => ` ${r.id} parent=${r.parentId} key=${r.key || "\u2014"} ${r.value}`
9316
+ ).join("\n");
9455
9317
  }
9456
- function applyFormat(segments, index, length, attributes) {
9457
- const split = splitSegmentsAt(
9458
- splitSegmentsAt(segments, index),
9459
- index + length
9460
- );
9461
- const result = [];
9462
- let offset = 0;
9463
- for (const segment of split) {
9464
- const end = offset + segment.text.length;
9465
- if (offset >= index && end <= index + length) {
9466
- const nextAttributes = {
9467
- ..._nullishCoalesce(segment.attributes, () => ( {}))
9468
- };
9469
- for (const [key, value] of Object.entries(attributes)) {
9470
- if (value === null) {
9471
- delete nextAttributes[key];
9472
- } else {
9473
- nextAttributes[key] = value;
9474
- }
9475
- }
9476
- result.push({
9477
- text: segment.text,
9478
- attributes: Object.keys(nextAttributes).length === 0 ? void 0 : freeze(nextAttributes)
9479
- });
9480
- } else {
9481
- result.push(segment);
9482
- }
9483
- offset = end;
9318
+ function isJsonEq(a, b) {
9319
+ if (a === b) {
9320
+ return true;
9484
9321
  }
9485
- return normalizeSegments(result);
9486
- }
9487
- function formatReverseOperations(segments, index, length, patch) {
9488
- const split = splitSegmentsAt(
9489
- splitSegmentsAt(segments, index),
9490
- index + length
9491
- );
9492
- const result = [];
9493
- let offset = 0;
9494
- for (const segment of split) {
9495
- const end = offset + segment.text.length;
9496
- if (offset >= index && end <= index + length) {
9497
- const attributes = {};
9498
- const current = _nullishCoalesce(segment.attributes, () => ( {}));
9499
- for (const key of Object.keys(patch)) {
9500
- const value = Object.hasOwn(current, key) ? current[key] : void 0;
9501
- attributes[key] = _nullishCoalesce(value, () => ( null));
9502
- }
9503
- result.push({
9504
- type: "format",
9505
- index: offset,
9506
- length: segment.text.length,
9507
- attributes
9508
- });
9509
- }
9510
- offset = end;
9322
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
9323
+ return false;
9511
9324
  }
9512
- return result;
9513
- }
9514
- function mapIndexThroughOperation(index, op) {
9515
- if (op.type === "insert") {
9516
- return op.index <= index ? index + op.text.length : index;
9517
- } else if (op.type === "delete") {
9518
- if (op.index >= index) {
9519
- return index;
9325
+ if (Array.isArray(a) || Array.isArray(b)) {
9326
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
9327
+ return false;
9520
9328
  }
9521
- return Math.max(op.index, index - op.length);
9522
- } else {
9523
- return index;
9329
+ for (let i = 0; i < a.length; i++) {
9330
+ if (!isJsonEq(a[i], b[i])) {
9331
+ return false;
9332
+ }
9333
+ }
9334
+ return true;
9524
9335
  }
9525
- }
9526
- function mapTextIndexThroughOperations(index, ops) {
9527
- let mapped = index;
9528
- for (const op of ops) {
9529
- mapped = mapIndexThroughOperation(mapped, op);
9336
+ const aKeys = Object.keys(a);
9337
+ if (aKeys.length !== Object.keys(b).length) {
9338
+ return false;
9530
9339
  }
9531
- return mapped;
9532
- }
9533
- function inverseMapIndexThroughOperation(index, op) {
9534
- if (op.type === "insert") {
9535
- if (index <= op.index) {
9536
- return index;
9340
+ for (const key of aKeys) {
9341
+ if (!isJsonEq(a[key], b[key])) {
9342
+ return false;
9537
9343
  }
9538
- return Math.max(op.index, index - op.text.length);
9539
- } else if (op.type === "delete") {
9540
- return op.index <= index ? index + op.length : index;
9541
- } else {
9542
- return index;
9543
- }
9544
- }
9545
- function inverseMapTextIndexThroughOperations(index, ops) {
9546
- let mapped = index;
9547
- for (let i = ops.length - 1; i >= 0; i--) {
9548
- mapped = inverseMapIndexThroughOperation(mapped, ops[i]);
9549
9344
  }
9550
- return mapped;
9551
- }
9552
- function oppositeOrder(order) {
9553
- return order === "before" ? "after" : "before";
9345
+ return true;
9554
9346
  }
9555
- function mapIndexOverDelete(index, deleteIndex, deleteLength) {
9556
- if (deleteIndex >= index) {
9557
- return index;
9558
- }
9559
- return Math.max(deleteIndex, index - deleteLength);
9560
- }
9561
- function transformInsert(op, over, order) {
9562
- if (over.type === "insert") {
9563
- const shifts = over.index < op.index || over.index === op.index && order === "after";
9564
- return [shifts ? { ...op, index: op.index + over.text.length } : { ...op }];
9565
- } else if (over.type === "delete") {
9566
- return [
9567
- { ...op, index: mapIndexOverDelete(op.index, over.index, over.length) }
9568
- ];
9569
- } else {
9570
- return [{ ...op }];
9571
- }
9572
- }
9573
- function transformDelete(op, over) {
9574
- const start = op.index;
9575
- const end = op.index + op.length;
9576
- if (over.type === "insert") {
9577
- const at = over.index;
9578
- const len = over.text.length;
9579
- if (at <= start) {
9580
- return [{ ...op, index: start + len }];
9581
- }
9582
- if (at >= end) {
9583
- return [{ ...op }];
9584
- }
9585
- return [
9586
- { type: "delete", index: start, length: at - start },
9587
- { type: "delete", index: start + len, length: end - at }
9588
- ];
9589
- } else if (over.type === "delete") {
9590
- const newStart = mapIndexOverDelete(start, over.index, over.length);
9591
- const newEnd = mapIndexOverDelete(end, over.index, over.length);
9592
- return newEnd - newStart > 0 ? [{ type: "delete", index: newStart, length: newEnd - newStart }] : [];
9593
- } else {
9594
- return [{ ...op }];
9595
- }
9596
- }
9597
- function transformFormat(op, over, order) {
9598
- const start = op.index;
9599
- const end = op.index + op.length;
9600
- if (over.type === "insert") {
9601
- const at = over.index;
9602
- const len = over.text.length;
9603
- if (at <= start) {
9604
- return [{ ...op, index: start + len }];
9605
- }
9606
- if (at >= end) {
9607
- return [{ ...op }];
9608
- }
9609
- return [
9610
- {
9611
- type: "format",
9612
- index: start,
9613
- length: at - start,
9614
- attributes: op.attributes
9615
- },
9616
- {
9617
- type: "format",
9618
- index: at + len,
9619
- length: end - at,
9620
- attributes: op.attributes
9621
- }
9622
- ];
9623
- } else if (over.type === "delete") {
9624
- const newStart = mapIndexOverDelete(start, over.index, over.length);
9625
- const newEnd = mapIndexOverDelete(end, over.index, over.length);
9626
- return newEnd - newStart > 0 ? [
9627
- {
9628
- type: "format",
9629
- index: newStart,
9630
- length: newEnd - newStart,
9631
- attributes: op.attributes
9632
- }
9633
- ] : [];
9634
- } else {
9635
- if (order === "after") {
9636
- return [{ ...op }];
9637
- }
9638
- const overlapStart = Math.max(start, over.index);
9639
- const overlapEnd = Math.min(end, over.index + over.length);
9640
- if (overlapStart >= overlapEnd) {
9641
- return [{ ...op }];
9642
- }
9643
- const hasConflict = Object.keys(op.attributes).some(
9644
- (key) => Object.hasOwn(over.attributes, key)
9645
- );
9646
- if (!hasConflict) {
9647
- return [{ ...op }];
9648
- }
9649
- const reduced = {};
9650
- for (const [key, value] of Object.entries(op.attributes)) {
9651
- if (!Object.hasOwn(over.attributes, key)) {
9652
- reduced[key] = value;
9653
- }
9654
- }
9655
- const pieces = [];
9656
- if (start < overlapStart) {
9657
- pieces.push({
9658
- type: "format",
9659
- index: start,
9660
- length: overlapStart - start,
9661
- attributes: op.attributes
9662
- });
9663
- }
9664
- if (Object.keys(reduced).length > 0) {
9665
- pieces.push({
9666
- type: "format",
9667
- index: overlapStart,
9668
- length: overlapEnd - overlapStart,
9669
- attributes: reduced
9670
- });
9671
- }
9672
- if (overlapEnd < end) {
9673
- pieces.push({
9674
- type: "format",
9675
- index: overlapEnd,
9676
- length: end - overlapEnd,
9677
- attributes: op.attributes
9678
- });
9679
- }
9680
- return pieces;
9681
- }
9682
- }
9683
- function transformSingle(op, over, order) {
9684
- switch (op.type) {
9685
- case "insert":
9686
- return transformInsert(op, over, order);
9687
- case "delete":
9688
- return transformDelete(op, over);
9689
- case "format":
9690
- return transformFormat(op, over, order);
9691
- }
9692
- }
9693
- function transformTextOperationsX(a, b, order) {
9694
- if (a.length === 0 || b.length === 0) {
9695
- return [[...a], [...b]];
9696
- }
9697
- if (a.length === 1 && b.length === 1) {
9698
- return [
9699
- transformSingle(a[0], b[0], order),
9700
- transformSingle(b[0], a[0], oppositeOrder(order))
9701
- ];
9702
- }
9703
- if (a.length > 1) {
9704
- const [headA1, b1] = transformTextOperationsX([a[0]], b, order);
9705
- const [restA1, b2] = transformTextOperationsX(a.slice(1), b1, order);
9706
- return [[...headA1, ...restA1], b2];
9707
- }
9708
- const [a1, headB1] = transformTextOperationsX(a, [b[0]], order);
9709
- const [a2, restB1] = transformTextOperationsX(a1, b.slice(1), order);
9710
- return [a2, [...headB1, ...restB1]];
9711
- }
9712
- function transformTextOperations(ops, over, order) {
9713
- return transformTextOperationsX(ops, over, order)[0];
9714
- }
9715
- function textOperationsEqual(a, b) {
9716
- return a === b || stableStringify(a) === stableStringify(b);
9717
- }
9718
- function applyTextOperationsToSegments(segments, ops) {
9719
- let next = [...segments];
9720
- for (const op of ops) {
9721
- if (op.type === "insert") {
9722
- const index = Math.max(0, Math.min(op.index, textLength(next)));
9723
- next = applyInsert(next, index, op.text, op.attributes);
9724
- } else if (op.type === "delete") {
9725
- const index = Math.max(0, Math.min(op.index, textLength(next)));
9726
- const clipped = clipRange(index, op.length, textLength(next));
9727
- next = applyDelete(next, clipped.index, clipped.length).segments;
9728
- } else {
9729
- const index = Math.max(0, Math.min(op.index, textLength(next)));
9730
- const clipped = clipRange(index, op.length, textLength(next));
9731
- next = applyFormat(next, clipped.index, clipped.length, op.attributes);
9732
- }
9733
- }
9734
- return next;
9735
- }
9736
- function applyLiveTextOperations(data, ops) {
9737
- return segmentsToData(
9738
- applyTextOperationsToSegments(dataToSegments(data), ops)
9739
- );
9740
- }
9741
- function invertTextOperations(segments, ops) {
9742
- let shadow = [...segments];
9743
- const reverse = [];
9744
- for (const op of ops) {
9745
- if (op.type === "insert") {
9746
- shadow = applyInsert(shadow, op.index, op.text, op.attributes);
9747
- reverse.unshift({
9748
- type: "delete",
9749
- index: op.index,
9750
- length: op.text.length
9751
- });
9752
- } else if (op.type === "delete") {
9753
- const deletedSegments = extractDeletedSegments(
9754
- shadow,
9755
- op.index,
9756
- op.length
9757
- );
9758
- shadow = applyDelete(shadow, op.index, op.length).segments;
9759
- const inserts = [];
9760
- let insertIndex = op.index;
9761
- for (const segment of deletedSegments) {
9762
- inserts.push({
9763
- type: "insert",
9764
- index: insertIndex,
9765
- text: segment.text,
9766
- attributes: segment.attributes
9767
- });
9768
- insertIndex += segment.text.length;
9769
- }
9770
- for (let index = inserts.length - 1; index >= 0; index--) {
9771
- reverse.unshift(inserts[index]);
9772
- }
9773
- } else {
9774
- const inverse = formatReverseOperations(
9775
- shadow,
9776
- op.index,
9777
- op.length,
9778
- op.attributes
9779
- );
9780
- shadow = applyFormat(shadow, op.index, op.length, op.attributes);
9781
- reverse.unshift(...inverse.reverse());
9782
- }
9783
- }
9784
- return reverse;
9785
- }
9786
-
9787
- // src/crdts/LiveText.ts
9788
- var ACCEPTED_OPS_HISTORY_LIMIT = 1e3;
9789
- var LiveText = class _LiveText extends AbstractCrdt {
9790
- /** The local document: #confirmed ⊕ #inFlightOps ⊕ #queuedOps. */
9791
- #segments;
9792
- /** The server-confirmed document (only authoritative ops applied). */
9793
- #confirmed;
9794
- #version;
9795
- /** The op currently awaiting server acknowledgement (at most one). */
9796
- #inFlightOpId;
9797
- /** Its ops, continuously re-expressed against current server state. */
9798
- #inFlightOps = [];
9799
- /** Local edits made while an op is in flight; sent after the ack. */
9800
- #queuedOps = [];
9801
- #acceptedOps = [];
9802
- /**
9803
- * Creates a new LiveText document.
9804
- *
9805
- * @param textOrData Initial plain text, or an array of `[text]` /
9806
- * `[text, attributes]` segments. Defaults to an empty document.
9807
- *
9808
- * @example
9809
- * new LiveText();
9810
- * new LiveText("Hello world");
9811
- * new LiveText([["Hello ", { bold: true }], ["world"]]);
9812
- */
9813
- constructor(textOrData = "", version = 0) {
9814
- super();
9815
- this.#segments = typeof textOrData === "string" ? textOrData.length === 0 ? [] : [{ text: textOrData }] : dataToSegments(textOrData);
9816
- this.#confirmed = [...this.#segments];
9817
- this.#version = version;
9818
- Object.assign(this[kInternal], {
9819
- encodeIndex: (localIndex) => this.#encodeIndex(localIndex),
9820
- decodeIndex: (index, fromVersion) => this.#decodeIndex(index, fromVersion)
9821
- });
9822
- }
9823
- get version() {
9824
- return this.#version;
9825
- }
9826
- get length() {
9827
- return textLength(this.#segments);
9828
- }
9829
- /** @internal */
9830
- static _deserialize([id, item], _parentToChildren, pool) {
9831
- const text = new _LiveText(item.data, item.version);
9832
- text._attach(id, pool);
9833
- return text;
9834
- }
9835
- /** @internal */
9836
- _toOps(parentId, parentKey) {
9837
- if (this._id === void 0) {
9838
- throw new Error("Cannot serialize LiveText if it is not attached");
9839
- }
9840
- return [
9841
- {
9842
- type: OpCode.CREATE_TEXT,
9843
- id: this._id,
9844
- parentId,
9845
- parentKey,
9846
- data: this.toJSON(),
9847
- version: this.#version
9848
- }
9849
- ];
9850
- }
9851
- /** @internal */
9852
- _serialize() {
9853
- if (this.parent.type !== "HasParent") {
9854
- throw new Error("Cannot serialize LiveText if parent is missing");
9855
- }
9856
- return {
9857
- type: CrdtType.TEXT,
9858
- parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
9859
- parentKey: this.parent.key,
9860
- data: this.toJSON(),
9861
- version: this.#version
9862
- };
9863
- }
9864
- /** @internal */
9865
- _attachChild(_op) {
9866
- throw new Error("LiveText cannot contain child nodes");
9867
- }
9868
- /** @internal */
9869
- _detachChild(_crdt) {
9870
- throw new Error("LiveText cannot contain child nodes");
9871
- }
9872
- /** @internal */
9873
- _apply(op, source) {
9874
- if (op.type !== OpCode.UPDATE_TEXT) {
9875
- return super._apply(op, source);
9876
- }
9877
- if (source.origin === "local" && source.optimistic) {
9878
- return this.#applyLocal(op, toUpdateSource(source));
9879
- }
9880
- if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
9881
- return this.#applyAck(op, toUpdateSource(source));
9882
- }
9883
- if (op.opId !== void 0 && this.#acceptedOps.some((entry) => entry.opId === op.opId)) {
9884
- this.#version = Math.max(this.#version, _nullishCoalesce(op.version, () => ( op.baseVersion + 1)));
9885
- return { modified: false };
9886
- }
9887
- return this.#applyRemote(op, toUpdateSource(source));
9888
- }
9889
- /**
9890
- * Inserts text at the given index.
9891
- *
9892
- * @param index Character index at which to insert. Values outside the
9893
- * document range are clipped.
9894
- * @param text Text to insert.
9895
- * @param attributes Optional inline attributes for the inserted text.
9896
- *
9897
- * @example
9898
- * const text = new LiveText("Hello");
9899
- * text.insert(5, " world");
9900
- * text.insert(0, "Say: ", { italic: true });
9901
- */
9902
- insert(index, text, attributes) {
9903
- const clippedIndex = clipIndexToCodePointBoundary(this.toString(), index);
9904
- this.#dispatch([{ type: "insert", index: clippedIndex, text, attributes }]);
9905
- }
9906
- /**
9907
- * Deletes `length` characters starting at `index`.
9908
- *
9909
- * @example
9910
- * const text = new LiveText("Hello world");
9911
- * text.delete(5, 6); // "Hello"
9912
- */
9913
- delete(index, length) {
9914
- const clipped = clipRangeToCodePointBoundaries(
9915
- this.toString(),
9916
- index,
9917
- length
9918
- );
9919
- if (clipped.length === 0) {
9920
- return;
9921
- }
9922
- this.#dispatch([
9923
- { type: "delete", index: clipped.index, length: clipped.length }
9924
- ]);
9925
- }
9926
- /**
9927
- * Replaces a range of text with new text.
9928
- *
9929
- * @example
9930
- * const text = new LiveText("Hello world");
9931
- * text.replace(0, 5, "Hi"); // "Hi world"
9932
- */
9933
- replace(index, length, text, attributes) {
9934
- const clipped = clipRangeToCodePointBoundaries(
9935
- this.toString(),
9936
- index,
9937
- length
9938
- );
9939
- const ops = [];
9940
- if (clipped.length > 0) {
9941
- ops.push({
9942
- type: "delete",
9943
- index: clipped.index,
9944
- length: clipped.length
9945
- });
9946
- }
9947
- if (text.length > 0) {
9948
- ops.push({ type: "insert", index: clipped.index, text, attributes });
9949
- }
9950
- this.#dispatch(ops);
9951
- }
9952
- /**
9953
- * Encode a local-document index (an offset into this LiveText's current
9954
- * #segments, which CodeMirror or any consumer mirrors as its document)
9955
- * into server-confirmed coordinates suitable for broadcasting to peers via
9956
- * presence or any other side channel.
9957
- *
9958
- * The returned index is in this LiveText's current #confirmed coordinates
9959
- * — that is, with this client's local pending ops inverse-mapped out.
9960
- * Pair it with the current {@link LiveText.version} when sending so the
9961
- * receiver can call {@link PrivateLiveTextApi.decodeIndex} to land the
9962
- * position in their own local document coordinates regardless of their
9963
- * private pending ops.
9964
- *
9965
- * Index ambiguity at boundaries is resolved by an inverse-of-forward
9966
- * convention: a position at or before a local insertion is reported as
9967
- * the position right before the insertion in #confirmed; a position past
9968
- * the insertion shifts left by the insertion's length. Positions inside
9969
- * an own-pending insertion collapse to the insertion point.
9970
- */
9971
- #encodeIndex(localIndex) {
9972
- let mapped = Math.max(0, Math.min(localIndex, this.length));
9973
- mapped = inverseMapTextIndexThroughOperations(mapped, this.#queuedOps);
9974
- mapped = inverseMapTextIndexThroughOperations(mapped, this.#inFlightOps);
9975
- return mapped;
9976
- }
9977
- /**
9978
- * Decode an `(index, fromVersion)` pair produced by
9979
- * {@link PrivateLiveTextApi.encodeIndex} — typically on a peer — into an
9980
- * offset in this LiveText's current local document (an index suitable for
9981
- * placing a CodeMirror marker, an annotation anchor, or anything else that
9982
- * lives over #segments).
9983
- *
9984
- * Composes the accepted ops applied since `fromVersion` (drawn from
9985
- * #acceptedOps in locally-applied form) with this client's own local
9986
- * pending ops, in that order. The result is in current #segments
9987
- * coordinates.
9988
- *
9989
- * Returns `null` when the position cannot be decoded against the current
9990
- * state:
9991
- * - `fromVersion` is greater than this LiveText's current version: the
9992
- * peer is ahead of us. The caller should park the message and retry
9993
- * after more accepted ops arrive.
9994
- * - `fromVersion` falls outside the retained accepted-ops history. This
9995
- * only happens after very long-lived disconnections; the caller can
9996
- * fall back to using the raw index and letting subsequent local
9997
- * transactions map it (with bounded drift).
9998
- */
9999
- #decodeIndex(index, fromVersion) {
10000
- if (fromVersion > this.#version) {
10001
- return null;
10002
- }
10003
- if (fromVersion < this.#version) {
10004
- const oldest = _optionalChain([this, 'access', _238 => _238.#acceptedOps, 'access', _239 => _239[0], 'optionalAccess', _240 => _240.version]);
10005
- if (oldest === void 0 || oldest > fromVersion + 1) {
10006
- return null;
10007
- }
10008
- }
10009
- let mapped = index;
10010
- for (const entry of this.#acceptedOps) {
10011
- if (entry.version <= fromVersion) continue;
10012
- if (entry.version > this.#version) break;
10013
- if (entry.ops.length === 0) continue;
10014
- mapped = mapTextIndexThroughOperations(mapped, entry.ops);
10015
- }
10016
- mapped = mapTextIndexThroughOperations(mapped, this.#inFlightOps);
10017
- mapped = mapTextIndexThroughOperations(mapped, this.#queuedOps);
10018
- return Math.max(0, Math.min(mapped, this.length));
10019
- }
10020
- /**
10021
- * Applies or removes inline attributes on a range of text.
10022
- *
10023
- * Set an attribute to `null` to remove it from the range.
10024
- *
10025
- * @example
10026
- * const text = new LiveText("Hello world");
10027
- * text.format(0, 5, { bold: true });
10028
- * text.format(0, 5, { bold: null });
10029
- */
10030
- format(index, length, attributes) {
10031
- const clipped = clipRangeToCodePointBoundaries(
10032
- this.toString(),
10033
- index,
10034
- length
10035
- );
10036
- if (clipped.length === 0) {
10037
- return;
10038
- }
10039
- this.#dispatch([
10040
- {
10041
- type: "format",
10042
- index: clipped.index,
10043
- length: clipped.length,
10044
- attributes
10045
- }
10046
- ]);
10047
- }
10048
- /** Local edits made through the public API. */
10049
- #dispatch(ops) {
10050
- if (ops.length === 0) {
10051
- return;
10052
- }
10053
- _optionalChain([this, 'access', _241 => _241._pool, 'optionalAccess', _242 => _242.assertStorageIsWritable, 'call', _243 => _243()]);
10054
- const attached = this._pool !== void 0 && this._id !== void 0;
10055
- const reverse = attached ? this.#invertOperations(ops) : [];
10056
- const changes = this.#applyOperationsLocally(ops);
10057
- if (!attached) {
10058
- return;
10059
- }
10060
- const pool = nn(this._pool);
10061
- const id = nn(this._id);
10062
- const updates = /* @__PURE__ */ new Map([
10063
- [
10064
- id,
10065
- {
10066
- type: "LiveText",
10067
- node: this,
10068
- version: this.#version,
10069
- updates: changes,
10070
- source: LOCAL_EDIT
10071
- }
10072
- ]
10073
- ]);
10074
- if (this.#inFlightOpId === void 0) {
10075
- const opId = pool.generateOpId();
10076
- this.#inFlightOpId = opId;
10077
- this.#inFlightOps = [...ops];
10078
- pool.dispatch(
10079
- [
10080
- {
10081
- type: OpCode.UPDATE_TEXT,
10082
- id,
10083
- opId,
10084
- baseVersion: this.#version,
10085
- ops: [...ops]
10086
- }
10087
- ],
10088
- reverse,
10089
- updates
10090
- );
10091
- } else {
10092
- this.#queuedOps.push(...ops);
10093
- pool.dispatch([], reverse, updates, { clearRedoStack: true });
10094
- }
10095
- }
10096
- /**
10097
- * A local replay of an existing wire op: an undo/redo frame, or an
10098
- * unacknowledged op re-sent after a reconnect.
10099
- */
10100
- #applyLocal(op, source) {
10101
- const mutableOp = op;
10102
- if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
10103
- this.#inFlightOps = [...this.#inFlightOps, ...this.#queuedOps];
10104
- this.#queuedOps = [];
10105
- mutableOp.baseVersion = this.#version;
10106
- mutableOp.ops = [...this.#inFlightOps];
10107
- return { modified: false };
10108
- }
10109
- let ops = op.ops;
10110
- for (const entry of this.#acceptedOps) {
10111
- if (entry.version > op.baseVersion && entry.ops.length > 0) {
10112
- ops = transformTextOperations(ops, entry.ops, "after");
10113
- }
10114
- }
10115
- const reverse = this.#invertOperations(ops);
10116
- const changes = this.#applyOperationsLocally(ops);
10117
- if (this.#inFlightOpId === void 0 && ops.length > 0) {
10118
- this.#inFlightOpId = nn(op.opId, "Local ops must have an opId");
10119
- this.#inFlightOps = [...ops];
10120
- mutableOp.baseVersion = this.#version;
10121
- mutableOp.ops = [...ops];
10122
- } else {
10123
- this.#queuedOps.push(...ops);
10124
- mutableOp.baseVersion = this.#version;
10125
- mutableOp.ops = [];
10126
- }
10127
- if (changes.length === 0) {
10128
- return { modified: false };
10129
- }
10130
- return {
10131
- reverse,
10132
- modified: {
10133
- type: "LiveText",
10134
- node: this,
10135
- version: this.#version,
10136
- updates: changes,
10137
- source
10138
- }
10139
- };
10140
- }
10141
- /** Server acknowledgement of our in-flight op. */
10142
- #applyAck(op, source) {
10143
- const ackedVersion = _nullishCoalesce(op.version, () => ( Math.max(this.#version, op.baseVersion + 1)));
10144
- const predicted = this.#inFlightOps;
10145
- const opId = this.#inFlightOpId;
10146
- this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
10147
- this.#inFlightOpId = void 0;
10148
- this.#inFlightOps = [];
10149
- let appliedOps = [];
10150
- let result = { modified: false };
10151
- if (!textOperationsEqual(op.ops, predicted)) {
10152
- error2(
10153
- "LiveText: acknowledgement did not match the local prediction; resynchronizing"
10154
- );
10155
- const rebuilt = this.#rebuildLocalFromConfirmed();
10156
- appliedOps = rebuilt.appliedOps;
10157
- if (rebuilt.changes.length > 0) {
10158
- result = {
10159
- reverse: [],
10160
- modified: {
10161
- type: "LiveText",
10162
- node: this,
10163
- version: ackedVersion,
10164
- updates: rebuilt.changes,
10165
- source
10166
- }
10167
- };
10168
- }
10169
- }
10170
- this.#version = Math.max(this.#version, ackedVersion);
10171
- this.#recordAccepted(ackedVersion, appliedOps, opId);
10172
- this.#flushQueued();
10173
- return result;
10174
- }
10175
- /** An accepted op from another client (or a server-fabricated fix op). */
10176
- #applyRemote(op, source) {
10177
- const version = _nullishCoalesce(op.version, () => ( this.#version + 1));
10178
- this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
10179
- const [overInFlight, inFlight] = transformTextOperationsX(
10180
- op.ops,
10181
- this.#inFlightOps,
10182
- "before"
10183
- );
10184
- const [applied, queued] = transformTextOperationsX(
10185
- overInFlight,
10186
- this.#queuedOps,
10187
- "before"
10188
- );
10189
- this.#inFlightOps = inFlight;
10190
- this.#queuedOps = queued;
10191
- this.#recordAccepted(version, applied, op.opId);
10192
- if (applied.length === 0) {
10193
- this.#version = Math.max(this.#version, version);
10194
- return { modified: false };
10195
- }
10196
- const reverse = this.#invertOperations(applied);
10197
- const changes = this.#applyOperationsLocally(applied);
10198
- this.#version = Math.max(this.#version, version);
10199
- return {
10200
- reverse,
10201
- modified: {
10202
- type: "LiveText",
10203
- node: this,
10204
- version: this.#version,
10205
- updates: changes,
10206
- source
10207
- }
10208
- };
10209
- }
10210
- /** Send the queued ops as the next in-flight op (after an ack). */
10211
- #flushQueued() {
10212
- if (this.#queuedOps.length === 0 || this._pool === void 0 || this._id === void 0) {
10213
- return;
10214
- }
10215
- const opId = this._pool.generateOpId();
10216
- this.#inFlightOpId = opId;
10217
- this.#inFlightOps = this.#queuedOps;
10218
- this.#queuedOps = [];
10219
- this._pool.dispatch(
10220
- [
10221
- {
10222
- type: OpCode.UPDATE_TEXT,
10223
- id: this._id,
10224
- opId,
10225
- baseVersion: this.#version,
10226
- ops: [...this.#inFlightOps]
10227
- }
10228
- ],
10229
- [],
10230
- /* @__PURE__ */ new Map(),
10231
- // The local content was already applied (and made undoable) when the
10232
- // edits happened; this is purely an outbound flush.
10233
- { clearRedoStack: false }
10234
- );
10235
- }
10236
- /**
10237
- * Rebuild the local document as confirmed ⊕ queued ops, returning the
10238
- * coarse delta that was applied. Only used by defensive recovery paths.
10239
- */
10240
- #rebuildLocalFromConfirmed() {
10241
- const before2 = this.#segments;
10242
- const after2 = applyTextOperationsToSegments(this.#confirmed, [
10243
- ...this.#inFlightOps,
10244
- ...this.#queuedOps
10245
- ]);
10246
- if (stableStringify(segmentsToData(before2)) === stableStringify(segmentsToData(after2))) {
10247
- this.#segments = after2;
10248
- return { appliedOps: [], changes: [] };
10249
- }
10250
- const beforeText = before2.map((segment) => segment.text).join("");
10251
- this.#segments = after2;
10252
- this.invalidate();
10253
- const appliedOps = [];
10254
- const changes = [];
10255
- if (beforeText.length > 0) {
10256
- appliedOps.push({ type: "delete", index: 0, length: beforeText.length });
10257
- changes.push({
10258
- type: "delete",
10259
- index: 0,
10260
- length: beforeText.length,
10261
- deletedText: beforeText
10262
- });
10263
- }
10264
- let index = 0;
10265
- for (const segment of after2) {
10266
- appliedOps.push({
10267
- type: "insert",
10268
- index,
10269
- text: segment.text,
10270
- attributes: segment.attributes
10271
- });
10272
- changes.push({
10273
- type: "insert",
10274
- index,
10275
- text: segment.text,
10276
- attributes: segment.attributes
10277
- });
10278
- index += segment.text.length;
10279
- }
10280
- return { appliedOps, changes };
10281
- }
10282
- /**
10283
- * Reconcile this node against an authoritative storage snapshot (e.g.
10284
- * after a reconnect). The confirmed state and version are replaced by the
10285
- * snapshot's; pending (in-flight + queued) ops are preserved on top and
10286
- * will be re-sent by the offline-ops replay.
10287
- *
10288
- * @internal
10289
- */
10290
- _resyncText(data, version, source) {
10291
- this.#confirmed = dataToSegments(data);
10292
- this.#version = version;
10293
- this.#acceptedOps = [];
10294
- const rebuilt = this.#rebuildLocalFromConfirmed();
10295
- if (rebuilt.changes.length === 0) {
10296
- return void 0;
10297
- }
10298
- return {
10299
- type: "LiveText",
10300
- node: this,
10301
- version: this.#version,
10302
- updates: rebuilt.changes,
10303
- source
10304
- };
10305
- }
10306
- /**
10307
- * Called when the server rejected one of our ops. Drops all pending state
10308
- * for this node (edits queued behind a rejected op cannot be trusted
10309
- * either); the room follows up with a storage resync.
10310
- *
10311
- * @internal
10312
- */
10313
- _rejectPendingOp(opId) {
10314
- if (opId !== this.#inFlightOpId) {
10315
- return;
10316
- }
10317
- this.#inFlightOpId = void 0;
10318
- this.#inFlightOps = [];
10319
- this.#queuedOps = [];
10320
- }
10321
- #recordAccepted(version, ops, opId) {
10322
- if (this.#acceptedOps.some((entry) => entry.version === version)) {
10323
- return;
10324
- }
10325
- this.#acceptedOps.push({ version, opId, ops: [...ops] });
10326
- this.#acceptedOps.sort((left, right) => left.version - right.version);
10327
- if (this.#acceptedOps.length > ACCEPTED_OPS_HISTORY_LIMIT) {
10328
- this.#acceptedOps.splice(
10329
- 0,
10330
- this.#acceptedOps.length - ACCEPTED_OPS_HISTORY_LIMIT
10331
- );
10332
- }
10333
- }
10334
- #applyOperationsLocally(ops) {
10335
- const changes = [];
10336
- for (const op of ops) {
10337
- if (op.type === "insert") {
10338
- this.#segments = applyInsert(
10339
- this.#segments,
10340
- op.index,
10341
- op.text,
10342
- op.attributes
10343
- );
10344
- changes.push({
10345
- type: "insert",
10346
- index: op.index,
10347
- text: op.text,
10348
- attributes: op.attributes
10349
- });
10350
- } else if (op.type === "delete") {
10351
- const result = applyDelete(this.#segments, op.index, op.length);
10352
- this.#segments = result.segments;
10353
- changes.push({
10354
- type: "delete",
10355
- index: op.index,
10356
- length: op.length,
10357
- deletedText: result.deletedText
10358
- });
10359
- } else {
10360
- this.#segments = applyFormat(
10361
- this.#segments,
10362
- op.index,
10363
- op.length,
10364
- op.attributes
10365
- );
10366
- changes.push({
10367
- type: "format",
10368
- index: op.index,
10369
- length: op.length,
10370
- attributes: op.attributes
10371
- });
10372
- }
10373
- }
10374
- this.invalidate();
10375
- return changes;
10376
- }
10377
- #invertOperations(ops) {
10378
- return [
10379
- {
10380
- type: OpCode.UPDATE_TEXT,
10381
- id: nn(this._id),
10382
- baseVersion: this.#version,
10383
- ops: invertTextOperations(this.#segments, ops)
10384
- }
10385
- ];
10386
- }
10387
- /** Returns the plain text content without attributes. Equivalent to joining the text from each segment in {@link LiveText.toJSON}. */
10388
- toString() {
10389
- return this.#segments.map((segment) => segment.text).join("");
10390
- }
10391
- /**
10392
- * Returns a JSON-compatible snapshot of the document as a {@link LiveTextData}
10393
- * array.
10394
- *
10395
- * @example
10396
- * new LiveText([["Hello ", { bold: true }], ["world"]]).toJSON();
10397
- * // [["Hello ", { bold: true }], ["world"]]
10398
- */
10399
- toJSON() {
10400
- return super.toJSON();
10401
- }
10402
- /** @internal */
10403
- _toJSON() {
10404
- return segmentsToData(this.#segments);
10405
- }
10406
- /** @internal */
10407
- toTreeNode(key) {
10408
- return super.toTreeNode(key);
10409
- }
10410
- /** @internal */
10411
- _toTreeNode(key) {
10412
- const nodeId = _nullishCoalesce(this._id, () => ( nanoid()));
10413
- const payload = this.toJSON().map(
10414
- (segment, index) => ({
10415
- type: "Json",
10416
- id: `${nodeId}:${index}`,
10417
- key: String(index),
10418
- payload: segment
10419
- })
10420
- );
10421
- payload.push({
10422
- type: "Json",
10423
- id: `${nodeId}:version`,
10424
- key: "version",
10425
- payload: this.version
10426
- });
10427
- return {
10428
- type: "LiveText",
10429
- id: nodeId,
10430
- key,
10431
- payload
10432
- };
10433
- }
10434
- clone() {
10435
- return new _LiveText(this.toJSON(), this.#version);
10436
- }
10437
- };
10438
-
10439
- // src/crdts/liveblocks-helpers.ts
10440
- function creationOpToLiveNode(op) {
10441
- return lsonToLiveNode(creationOpToLson(op));
10442
- }
10443
- function creationOpToLson(op) {
10444
- switch (op.type) {
10445
- case OpCode.CREATE_FILE:
10446
- return new LiveFile(op.data);
10447
- case OpCode.CREATE_REGISTER:
10448
- return op.data;
10449
- case OpCode.CREATE_OBJECT:
10450
- return new LiveObject(op.data);
10451
- case OpCode.CREATE_MAP:
10452
- return new LiveMap();
10453
- case OpCode.CREATE_LIST:
10454
- return new LiveList([]);
10455
- case OpCode.CREATE_TEXT:
10456
- return new LiveText(op.data, op.version);
10457
- default:
10458
- return assertNever(op, "Unknown creation Op");
10459
- }
10460
- }
10461
- function isSameNodeOrChildOf(node, parent) {
10462
- if (node === parent) {
10463
- return true;
10464
- }
10465
- if (node.parent.type === "HasParent") {
10466
- return isSameNodeOrChildOf(node.parent.node, parent);
10467
- }
10468
- return false;
10469
- }
10470
- function liveObjectFromNodeStream(nodes) {
10471
- const pool = createManagedPool({
10472
- getCurrentConnectionId: () => {
10473
- throw new Error(
10474
- "Cannot mutate a historic storage version: it is a read-only snapshot"
10475
- );
10476
- }
10477
- });
10478
- return LiveObject._fromItems(nodes, pool);
10479
- }
10480
- function deserialize(node, parentToChildren, pool) {
10481
- if (isObjectStorageNode(node)) {
10482
- return LiveObject._deserialize(node, parentToChildren, pool);
10483
- } else if (isListStorageNode(node)) {
10484
- return LiveList._deserialize(node, parentToChildren, pool);
10485
- } else if (isMapStorageNode(node)) {
10486
- return LiveMap._deserialize(node, parentToChildren, pool);
10487
- } else if (isRegisterStorageNode(node)) {
10488
- return LiveRegister._deserialize(node, parentToChildren, pool);
10489
- } else if (isTextStorageNode(node)) {
10490
- return LiveText._deserialize(node, parentToChildren, pool);
10491
- } else if (isFileStorageNode(node)) {
10492
- return LiveFile._deserialize(node, parentToChildren, pool);
10493
- } else {
10494
- throw new Error("Unexpected CRDT type");
10495
- }
10496
- }
10497
- function deserializeToLson(node, parentToChildren, pool) {
10498
- if (isObjectStorageNode(node)) {
10499
- return LiveObject._deserialize(node, parentToChildren, pool);
10500
- } else if (isListStorageNode(node)) {
10501
- return LiveList._deserialize(node, parentToChildren, pool);
10502
- } else if (isMapStorageNode(node)) {
10503
- return LiveMap._deserialize(node, parentToChildren, pool);
10504
- } else if (isRegisterStorageNode(node)) {
10505
- return node[1].data;
10506
- } else if (isTextStorageNode(node)) {
10507
- return LiveText._deserialize(node, parentToChildren, pool);
10508
- } else if (isFileStorageNode(node)) {
10509
- return LiveFile._deserialize(node, parentToChildren, pool);
10510
- } else {
10511
- throw new Error("Unexpected CRDT type");
10512
- }
10513
- }
10514
- function isLiveStructure(value) {
10515
- return isLiveList(value) || isLiveMap(value) || isLiveObject(value) || isLiveText(value) || isLiveFile(value);
10516
- }
10517
- function isLiveNode(value) {
10518
- return isLiveStructure(value) || isLiveRegister(value);
10519
- }
10520
- function isLiveList(value) {
10521
- return value instanceof LiveList;
10522
- }
10523
- function isLiveMap(value) {
10524
- return value instanceof LiveMap;
10525
- }
10526
- function isLiveObject(value) {
10527
- return value instanceof LiveObject;
10528
- }
10529
- function isLiveText(value) {
10530
- return value instanceof LiveText;
10531
- }
10532
- function isLiveFile(value) {
10533
- return value instanceof LiveFile;
10534
- }
10535
- function isLiveRegister(value) {
10536
- return value instanceof LiveRegister;
10537
- }
10538
- function cloneLson(value) {
10539
- return value === void 0 ? void 0 : isLiveStructure(value) ? value.clone() : deepClone(value);
10540
- }
10541
- function liveNodeToLson(obj) {
10542
- if (obj instanceof LiveRegister) {
10543
- return obj.data;
10544
- } else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject || obj instanceof LiveText || obj instanceof LiveFile) {
10545
- return obj;
10546
- } else {
10547
- return assertNever(obj, "Unknown AbstractCrdt");
10548
- }
10549
- }
10550
- function lsonToLiveNode(value) {
10551
- if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList || value instanceof LiveText || value instanceof LiveFile) {
10552
- return value;
10553
- } else {
10554
- return new LiveRegister(value);
10555
- }
10556
- }
10557
- function dumpPool(pool) {
10558
- const rows = Array.from(pool.nodes.values(), (node) => {
10559
- const parent = node.parent;
10560
- const parentId = parent.type === "HasParent" ? _nullishCoalesce(parent.node._id, () => ( "?")) : parent.type === "Orphaned" ? "<orphaned>" : "-";
10561
- let value;
10562
- if (node instanceof LiveRegister) {
10563
- value = stringifyOrLog(node.data);
10564
- } else if (node instanceof LiveList) {
10565
- value = "<LiveList>";
10566
- } else if (node instanceof LiveMap) {
10567
- value = "<LiveMap>";
10568
- } else if (node instanceof LiveFile) {
10569
- value = stringifyOrLog(node.data);
10570
- } else {
10571
- value = "<LiveObject>";
10572
- }
10573
- return { id: nn(node._id), parentId, key: _nullishCoalesce(node._parentKey, () => ( "")), value };
10574
- });
10575
- rows.sort((a, b) => {
10576
- if (a.parentId !== b.parentId) return a.parentId < b.parentId ? -1 : 1;
10577
- if (a.key !== b.key) return a.key < b.key ? -1 : 1;
10578
- return 0;
10579
- });
10580
- return rows.map(
10581
- (r) => ` ${r.id} parent=${r.parentId} key=${r.key || "\u2014"} ${r.value}`
10582
- ).join("\n");
10583
- }
10584
- function isJsonEq(a, b) {
10585
- if (a === b) {
10586
- return true;
10587
- }
10588
- if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
10589
- return false;
10590
- }
10591
- if (Array.isArray(a) || Array.isArray(b)) {
10592
- if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
10593
- return false;
10594
- }
10595
- for (let i = 0; i < a.length; i++) {
10596
- if (!isJsonEq(a[i], b[i])) {
10597
- return false;
10598
- }
10599
- }
10600
- return true;
10601
- }
10602
- const aKeys = Object.keys(a);
10603
- if (aKeys.length !== Object.keys(b).length) {
10604
- return false;
10605
- }
10606
- for (const key of aKeys) {
10607
- if (!isJsonEq(a[key], b[key])) {
10608
- return false;
10609
- }
10610
- }
10611
- return true;
10612
- }
10613
- function liveTextDataToReplaceOps(before2, after2) {
10614
- const ops = [];
10615
- const beforeLength = before2.reduce(
10616
- (length, [text]) => length + text.length,
10617
- 0
10618
- );
10619
- if (beforeLength > 0) {
10620
- ops.push({ type: "delete", index: 0, length: beforeLength });
10621
- }
10622
- let index = 0;
10623
- for (const [text, attributes] of after2) {
10624
- if (text.length === 0) {
10625
- continue;
10626
- }
10627
- ops.push({ type: "insert", index, text, attributes });
10628
- index += text.length;
10629
- }
10630
- return ops;
10631
- }
10632
- function diffNodeMap(prev, next, options) {
9347
+ function diffNodeMap(prev, next) {
10633
9348
  const ops = [];
10634
9349
  const idsToRecreate = /* @__PURE__ */ new Set();
10635
9350
  next.forEach((nextCrdt, id) => {
@@ -10721,16 +9436,6 @@ function diffNodeMap(prev, next, options) {
10721
9436
  parentKey: crdt.parentKey
10722
9437
  });
10723
9438
  break;
10724
- case CrdtType.TEXT:
10725
- ops.push({
10726
- type: OpCode.CREATE_TEXT,
10727
- id,
10728
- parentId: crdt.parentId,
10729
- parentKey: crdt.parentKey,
10730
- data: crdt.data,
10731
- version: crdt.version
10732
- });
10733
- break;
10734
9439
  }
10735
9440
  }
10736
9441
  next.forEach((crdt, id) => {
@@ -10757,17 +9462,6 @@ function diffNodeMap(prev, next, options) {
10757
9462
  }
10758
9463
  }
10759
9464
  }
10760
- if (_optionalChain([options, 'optionalAccess', _244 => _244.includeLiveTextUpdates]) === true && crdt.type === CrdtType.TEXT && currentCrdt.type === CrdtType.TEXT && !isJsonEq(crdt.data, currentCrdt.data)) {
10761
- ops.push({
10762
- type: OpCode.UPDATE_TEXT,
10763
- id,
10764
- // A restore is a new edit in the current timeline. The version from
10765
- // the historic snapshot describes its old timeline and must not move
10766
- // this node's current version backwards.
10767
- baseVersion: currentCrdt.version,
10768
- ops: liveTextDataToReplaceOps(currentCrdt.data, crdt.data)
10769
- });
10770
- }
10771
9465
  if (crdt.parentKey !== currentCrdt.parentKey) {
10772
9466
  ops.push({
10773
9467
  type: OpCode.SET_PARENT_KEY,
@@ -10808,36 +9502,19 @@ function mergeListStorageUpdates(first, second) {
10808
9502
  updates: updates.concat(second.updates)
10809
9503
  };
10810
9504
  }
10811
- function mergeTextStorageUpdates(first, second) {
10812
- return {
10813
- ...second,
10814
- updates: first.updates.concat(second.updates)
10815
- };
10816
- }
10817
- function mergeUpdateSources(first, second) {
10818
- if (first.origin === "remote" || second.origin === "remote") {
10819
- return REMOTE;
10820
- }
10821
- if (second.via !== "edit") return second;
10822
- if (first.via !== "edit") return first;
10823
- return LOCAL_EDIT;
10824
- }
10825
9505
  function mergeStorageUpdates(first, second) {
10826
9506
  if (first === void 0) {
10827
9507
  return second;
10828
9508
  }
10829
- const source = mergeUpdateSources(first.source, second.source);
10830
9509
  if (first.type === "LiveObject" && second.type === "LiveObject") {
10831
- return { ...mergeObjectStorageUpdates(first, second), source };
9510
+ return mergeObjectStorageUpdates(first, second);
10832
9511
  } else if (first.type === "LiveMap" && second.type === "LiveMap") {
10833
- return { ...mergeMapStorageUpdates(first, second), source };
9512
+ return mergeMapStorageUpdates(first, second);
10834
9513
  } else if (first.type === "LiveList" && second.type === "LiveList") {
10835
- return { ...mergeListStorageUpdates(first, second), source };
10836
- } else if (first.type === "LiveText" && second.type === "LiveText") {
10837
- return { ...mergeTextStorageUpdates(first, second), source };
9514
+ return mergeListStorageUpdates(first, second);
10838
9515
  } else {
10839
- return { ...second, source };
10840
9516
  }
9517
+ return second;
10841
9518
  }
10842
9519
 
10843
9520
  // src/devtools/bridge.ts
@@ -10853,7 +9530,7 @@ function sendToPanel(message, options) {
10853
9530
  ...message,
10854
9531
  source: "liveblocks-devtools-client"
10855
9532
  };
10856
- if (!(_optionalChain([options, 'optionalAccess', _245 => _245.force]) || _bridgeActive)) {
9533
+ if (!(_optionalChain([options, 'optionalAccess', _238 => _238.force]) || _bridgeActive)) {
10857
9534
  return;
10858
9535
  }
10859
9536
  window.postMessage(fullMsg, "*");
@@ -10861,7 +9538,7 @@ function sendToPanel(message, options) {
10861
9538
  var eventSource = makeEventSource();
10862
9539
  if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
10863
9540
  window.addEventListener("message", (event) => {
10864
- if (event.source === window && _optionalChain([event, 'access', _246 => _246.data, 'optionalAccess', _247 => _247.source]) === "liveblocks-devtools-panel") {
9541
+ if (event.source === window && _optionalChain([event, 'access', _239 => _239.data, 'optionalAccess', _240 => _240.source]) === "liveblocks-devtools-panel") {
10865
9542
  eventSource.notify(event.data);
10866
9543
  } else {
10867
9544
  }
@@ -11003,7 +9680,7 @@ function fullSync(room) {
11003
9680
  msg: "room::sync::full",
11004
9681
  roomId: room.id,
11005
9682
  status: room.getStatus(),
11006
- storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _248 => _248.toTreeNode, 'call', _249 => _249("root"), 'access', _250 => _250.payload]), () => ( null)),
9683
+ storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _241 => _241.toTreeNode, 'call', _242 => _242("root"), 'access', _243 => _243.payload]), () => ( null)),
11007
9684
  me,
11008
9685
  others
11009
9686
  });
@@ -11690,15 +10367,15 @@ function installBackgroundTabSpy() {
11690
10367
  const doc = typeof document !== "undefined" ? document : void 0;
11691
10368
  const inBackgroundSince = { current: null };
11692
10369
  function onVisibilityChange() {
11693
- if (_optionalChain([doc, 'optionalAccess', _251 => _251.visibilityState]) === "hidden") {
10370
+ if (_optionalChain([doc, 'optionalAccess', _244 => _244.visibilityState]) === "hidden") {
11694
10371
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
11695
10372
  } else {
11696
10373
  inBackgroundSince.current = null;
11697
10374
  }
11698
10375
  }
11699
- _optionalChain([doc, 'optionalAccess', _252 => _252.addEventListener, 'call', _253 => _253("visibilitychange", onVisibilityChange)]);
10376
+ _optionalChain([doc, 'optionalAccess', _245 => _245.addEventListener, 'call', _246 => _246("visibilitychange", onVisibilityChange)]);
11700
10377
  const unsub = () => {
11701
- _optionalChain([doc, 'optionalAccess', _254 => _254.removeEventListener, 'call', _255 => _255("visibilitychange", onVisibilityChange)]);
10378
+ _optionalChain([doc, 'optionalAccess', _247 => _247.removeEventListener, 'call', _248 => _248("visibilitychange", onVisibilityChange)]);
11702
10379
  };
11703
10380
  return [inBackgroundSince, unsub];
11704
10381
  }
@@ -11722,7 +10399,7 @@ function makeNodeMapBuffer() {
11722
10399
  function topLevelKeysOf(nodes) {
11723
10400
  const keys2 = /* @__PURE__ */ new Set();
11724
10401
  const root = nodes.get("root");
11725
- for (const key in _optionalChain([root, 'optionalAccess', _256 => _256.data])) {
10402
+ for (const key in _optionalChain([root, 'optionalAccess', _249 => _249.data])) {
11726
10403
  keys2.add(key);
11727
10404
  }
11728
10405
  for (const node of nodes.values()) {
@@ -11794,8 +10471,6 @@ function createRoom(options, config) {
11794
10471
  activeBatch: null,
11795
10472
  unacknowledgedOps
11796
10473
  };
11797
- let nextHistoryItemId = 0;
11798
- let historyDisabled = 0;
11799
10474
  const nodeMapBuffer = makeNodeMapBuffer();
11800
10475
  const stopwatch = config.enableDebugLogging ? makeStopWatch() : void 0;
11801
10476
  let lastTokenKey;
@@ -11880,7 +10555,7 @@ function createRoom(options, config) {
11880
10555
  }
11881
10556
  }
11882
10557
  });
11883
- function onDispatch(ops, reverse, storageUpdates, options2) {
10558
+ function onDispatch(ops, reverse, storageUpdates) {
11884
10559
  if (context.activeBatch) {
11885
10560
  for (const op of ops) {
11886
10561
  context.activeBatch.ops.push(op);
@@ -11895,24 +10570,19 @@ function createRoom(options, config) {
11895
10570
  );
11896
10571
  }
11897
10572
  context.activeBatch.reverseOps.pushLeft(reverse);
11898
- if (_optionalChain([options2, 'optionalAccess', _257 => _257.clearRedoStack])) {
11899
- context.activeBatch.clearRedoStack = true;
11900
- }
11901
10573
  } else {
11902
10574
  if (reverse.length > 0) {
11903
10575
  addToUndoStack(reverse);
11904
10576
  }
11905
- if (_nullishCoalesce(_optionalChain([options2, 'optionalAccess', _258 => _258.clearRedoStack]), () => ( ops.length > 0))) {
11906
- clearRedoStack();
11907
- }
11908
10577
  if (ops.length > 0) {
10578
+ context.redoStack.length = 0;
11909
10579
  dispatchOps(ops);
11910
10580
  }
11911
10581
  notify({ storageUpdates });
11912
10582
  }
11913
10583
  }
11914
10584
  function isStorageWritable() {
11915
- const permissionMatrix = _optionalChain([context, 'access', _259 => _259.dynamicSessionInfoSig, 'access', _260 => _260.get, 'call', _261 => _261(), 'optionalAccess', _262 => _262.permissionMatrix]);
10585
+ const permissionMatrix = _optionalChain([context, 'access', _250 => _250.dynamicSessionInfoSig, 'access', _251 => _251.get, 'call', _252 => _252(), 'optionalAccess', _253 => _253.permissionMatrix]);
11916
10586
  return permissionMatrix !== void 0 ? hasPermissionAccess(permissionMatrix, "storage", "write") : true;
11917
10587
  }
11918
10588
  const eventHub = {
@@ -11925,7 +10595,6 @@ function createRoom(options, config) {
11925
10595
  others: makeEventSource(),
11926
10596
  storageBatch: makeEventSource(),
11927
10597
  history: makeEventSource(),
11928
- privateHistory: makeEventSource(),
11929
10598
  storageDidLoad: makeEventSource(),
11930
10599
  storageStatus: makeEventSource(),
11931
10600
  ydoc: makeEventSource(),
@@ -12013,12 +10682,12 @@ function createRoom(options, config) {
12013
10682
  self,
12014
10683
  (me) => me !== null ? userToTreeNode("Me", me) : null
12015
10684
  );
12016
- function diffCurrentStorageAgainst(target, options2) {
10685
+ function diffCurrentStorageAgainst(target) {
12017
10686
  const current = /* @__PURE__ */ new Map();
12018
10687
  for (const [id, crdt] of context.pool.nodes) {
12019
10688
  current.set(id, crdt._serialize());
12020
10689
  }
12021
- return diffNodeMap(current, target, options2);
10690
+ return diffNodeMap(current, target);
12022
10691
  }
12023
10692
  function createOrUpdateRootFromMessage(nodes) {
12024
10693
  if (nodes.size === 0) {
@@ -12026,23 +10695,6 @@ function createRoom(options, config) {
12026
10695
  }
12027
10696
  if (context.root !== void 0) {
12028
10697
  const result = applyRemoteOps(diffCurrentStorageAgainst(nodes));
12029
- for (const [id, crdt] of nodes) {
12030
- if (crdt.type === CrdtType.TEXT) {
12031
- const node = context.pool.nodes.get(id);
12032
- if (node !== void 0 && isLiveText(node)) {
12033
- const update = node._resyncText(crdt.data, crdt.version, REMOTE);
12034
- if (update !== void 0) {
12035
- result.updates.storageUpdates.set(
12036
- id,
12037
- mergeStorageUpdates(
12038
- result.updates.storageUpdates.get(id),
12039
- update
12040
- )
12041
- );
12042
- }
12043
- }
12044
- }
12045
- }
12046
10698
  notify(result.updates);
12047
10699
  } else {
12048
10700
  context.root = LiveObject._fromItems(
@@ -12050,7 +10702,7 @@ function createRoom(options, config) {
12050
10702
  context.pool
12051
10703
  );
12052
10704
  }
12053
- const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _263 => _263.get, 'call', _264 => _264(), 'optionalAccess', _265 => _265.canWrite]), () => ( true));
10705
+ const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _254 => _254.get, 'call', _255 => _255(), 'optionalAccess', _256 => _256.canWrite]), () => ( true));
12054
10706
  const serverTopLevelKeys = topLevelKeysOf(nodes);
12055
10707
  const root = context.root;
12056
10708
  disableHistory(() => {
@@ -12067,23 +10719,12 @@ function createRoom(options, config) {
12067
10719
  }
12068
10720
  });
12069
10721
  }
12070
- function notifyPrivateHistory(event) {
12071
- if (historyDisabled > 0) return;
12072
- eventHub.privateHistory.notify(event);
12073
- }
12074
- function clearRedoStack() {
12075
- if (context.redoStack.length === 0) return;
12076
- const ids = context.redoStack.map((item) => item.id);
12077
- context.redoStack.length = 0;
12078
- notifyPrivateHistory({ action: "discard", ids });
12079
- }
12080
10722
  function reconcileStorageWithNodes(nodes) {
12081
10723
  if (context.root === void 0) {
12082
10724
  throw new Error("Cannot reconcile storage before it is loaded");
12083
10725
  }
12084
10726
  const ops = diffCurrentStorageAgainst(
12085
- new Map(nodes),
12086
- { includeLiveTextUpdates: true }
10727
+ new Map(nodes)
12087
10728
  );
12088
10729
  if (ops.length === 0) {
12089
10730
  return;
@@ -12102,14 +10743,9 @@ function createRoom(options, config) {
12102
10743
  }
12103
10744
  function _addToRealUndoStack(frames) {
12104
10745
  if (context.undoStack.length >= 50) {
12105
- const evicted = context.undoStack.shift();
12106
- if (evicted !== void 0) {
12107
- notifyPrivateHistory({ action: "discard", ids: [evicted.id] });
12108
- }
10746
+ context.undoStack.shift();
12109
10747
  }
12110
- const id = nextHistoryItemId++;
12111
- context.undoStack.push({ id, frames });
12112
- notifyPrivateHistory({ action: "push", id });
10748
+ context.undoStack.push(frames);
12113
10749
  onHistoryChange();
12114
10750
  }
12115
10751
  function addToUndoStack(frames) {
@@ -12133,10 +10769,7 @@ function createRoom(options, config) {
12133
10769
  eventHub.myPresence.notify(context.myPresence.get());
12134
10770
  }
12135
10771
  if (storageUpdates !== void 0 && storageUpdates.size > 0) {
12136
- const updates2 = Array.from(storageUpdates.values(), (update) => ({
12137
- ...update,
12138
- source: toUpdateSource(update.source)
12139
- }));
10772
+ const updates2 = Array.from(storageUpdates.values());
12140
10773
  eventHub.storageBatch.notify(updates2);
12141
10774
  }
12142
10775
  notifyStorageStatus();
@@ -12150,69 +10783,19 @@ function createRoom(options, config) {
12150
10783
  "Internal. Tried to get connection id but connection was never open"
12151
10784
  );
12152
10785
  }
12153
- const viaByOpId = /* @__PURE__ */ new Map();
12154
- function viaOfAckedOp(opId) {
12155
- const via = viaByOpId.get(opId);
12156
- if (via === void 0) {
12157
- return "edit";
12158
- }
12159
- viaByOpId.delete(opId);
12160
- return via;
12161
- }
12162
- function applyLocalOps(frames, localSource = LOCAL_EDIT) {
10786
+ function applyLocalOps(frames) {
12163
10787
  const [pframes, ops] = partition(
12164
10788
  frames,
12165
10789
  (f) => f.type === "presence"
12166
10790
  );
12167
- const restoredTextIds = /* @__PURE__ */ new Map();
12168
- for (const op of ops) {
12169
- if (op.type === OpCode.CREATE_TEXT && op.opId === void 0 && context.pool.nodes.get(op.id) === void 0 && !restoredTextIds.has(op.id)) {
12170
- restoredTextIds.set(op.id, context.pool.generateId());
12171
- }
12172
- }
12173
- const remappedOps = restoredTextIds.size === 0 ? ops : ops.map((op) => {
12174
- if (op.opId !== void 0) {
12175
- return op;
12176
- }
12177
- const id = restoredTextIds.get(op.id);
12178
- if (isCreateOp(op)) {
12179
- const parentId = restoredTextIds.get(op.parentId);
12180
- const deletedId = op.deletedId === void 0 ? void 0 : restoredTextIds.get(op.deletedId);
12181
- if (id === void 0 && parentId === void 0 && deletedId === void 0) {
12182
- return op;
12183
- }
12184
- if (op.type === OpCode.CREATE_TEXT && id !== void 0) {
12185
- return {
12186
- ...op,
12187
- id,
12188
- version: 0,
12189
- ...parentId === void 0 ? {} : { parentId },
12190
- ...deletedId === void 0 ? {} : { deletedId }
12191
- };
12192
- }
12193
- return {
12194
- ...op,
12195
- ...id === void 0 ? {} : { id },
12196
- ...parentId === void 0 ? {} : { parentId },
12197
- ...deletedId === void 0 ? {} : { deletedId }
12198
- };
12199
- }
12200
- return id === void 0 ? op : { ...op, id };
12201
- });
12202
- const opsWithOpIds = remappedOps.map(
10791
+ const opsWithOpIds = ops.map(
12203
10792
  (op) => op.opId === void 0 ? { ...op, opId: context.pool.generateOpId() } : op
12204
10793
  );
12205
- if (localSource.via !== "edit") {
12206
- for (const op of opsWithOpIds) {
12207
- viaByOpId.set(op.opId, localSource.via);
12208
- }
12209
- }
12210
10794
  const { reverse, updates } = applyOps(
12211
10795
  pframes,
12212
10796
  opsWithOpIds,
12213
10797
  /* isLocal */
12214
- true,
12215
- localSource
10798
+ true
12216
10799
  );
12217
10800
  return { opsToEmit: opsWithOpIds, reverse, updates };
12218
10801
  }
@@ -12224,7 +10807,7 @@ function createRoom(options, config) {
12224
10807
  false
12225
10808
  );
12226
10809
  }
12227
- function applyOps(pframes, ops, isLocal, localSource = LOCAL_EDIT) {
10810
+ function applyOps(pframes, ops, isLocal) {
12228
10811
  const output = {
12229
10812
  reverse: new Deque(),
12230
10813
  storageUpdates: /* @__PURE__ */ new Map(),
@@ -12253,16 +10836,12 @@ function createRoom(options, config) {
12253
10836
  for (const op of ops) {
12254
10837
  let source;
12255
10838
  if (isLocal) {
12256
- source = { ...localSource, optimistic: true };
10839
+ source = 0 /* LOCAL */;
12257
10840
  } else if (op.opId !== void 0) {
12258
10841
  context.unacknowledgedOps.delete(op.opId);
12259
- source = {
12260
- origin: "local",
12261
- via: viaOfAckedOp(op.opId),
12262
- optimistic: false
12263
- };
10842
+ source = 2 /* OURS */;
12264
10843
  } else {
12265
- source = REMOTE;
10844
+ source = 1 /* THEIRS */;
12266
10845
  }
12267
10846
  const applyOpResult = applyOp(op, source);
12268
10847
  if (applyOpResult.modified) {
@@ -12277,7 +10856,7 @@ function createRoom(options, config) {
12277
10856
  );
12278
10857
  output.reverse.pushLeft(applyOpResult.reverse);
12279
10858
  }
12280
- if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_TEXT || op.type === OpCode.CREATE_FILE) {
10859
+ if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_FILE) {
12281
10860
  createdNodeIds.add(op.id);
12282
10861
  }
12283
10862
  }
@@ -12297,13 +10876,12 @@ function createRoom(options, config) {
12297
10876
  switch (op.type) {
12298
10877
  case OpCode.DELETE_OBJECT_KEY:
12299
10878
  case OpCode.UPDATE_OBJECT:
12300
- case OpCode.UPDATE_TEXT:
12301
10879
  case OpCode.DELETE_CRDT: {
12302
10880
  const node = context.pool.nodes.get(op.id);
12303
10881
  if (node === void 0) {
12304
10882
  return { modified: false };
12305
10883
  }
12306
- return node._apply(op, source);
10884
+ return node._apply(op, source === 0 /* LOCAL */);
12307
10885
  }
12308
10886
  case OpCode.SET_PARENT_KEY: {
12309
10887
  const node = context.pool.nodes.get(op.id);
@@ -12322,7 +10900,6 @@ function createRoom(options, config) {
12322
10900
  case OpCode.CREATE_OBJECT:
12323
10901
  case OpCode.CREATE_LIST:
12324
10902
  case OpCode.CREATE_MAP:
12325
- case OpCode.CREATE_TEXT:
12326
10903
  case OpCode.CREATE_FILE:
12327
10904
  case OpCode.CREATE_REGISTER: {
12328
10905
  if (op.parentId === void 0) {
@@ -12358,7 +10935,7 @@ function createRoom(options, config) {
12358
10935
  }
12359
10936
  context.myPresence.patch(patch);
12360
10937
  if (context.activeBatch) {
12361
- if (_optionalChain([options2, 'optionalAccess', _266 => _266.addToHistory])) {
10938
+ if (_optionalChain([options2, 'optionalAccess', _257 => _257.addToHistory])) {
12362
10939
  context.activeBatch.reverseOps.pushLeft({
12363
10940
  type: "presence",
12364
10941
  data: oldValues
@@ -12367,7 +10944,7 @@ function createRoom(options, config) {
12367
10944
  context.activeBatch.updates.presence = true;
12368
10945
  } else {
12369
10946
  flushNowOrSoon();
12370
- if (_optionalChain([options2, 'optionalAccess', _267 => _267.addToHistory])) {
10947
+ if (_optionalChain([options2, 'optionalAccess', _258 => _258.addToHistory])) {
12371
10948
  addToUndoStack([{ type: "presence", data: oldValues }]);
12372
10949
  }
12373
10950
  notify({ presence: true });
@@ -12546,11 +11123,11 @@ function createRoom(options, config) {
12546
11123
  break;
12547
11124
  }
12548
11125
  case ServerMsgCode.STORAGE_CHUNK:
12549
- _optionalChain([stopwatch, 'optionalAccess', _268 => _268.lap, 'call', _269 => _269()]);
11126
+ _optionalChain([stopwatch, 'optionalAccess', _259 => _259.lap, 'call', _260 => _260()]);
12550
11127
  nodeMapBuffer.append(compactNodesToNodeStream(message.nodes));
12551
11128
  break;
12552
11129
  case ServerMsgCode.STORAGE_STREAM_END: {
12553
- const timing = _optionalChain([stopwatch, 'optionalAccess', _270 => _270.stop, 'call', _271 => _271()]);
11130
+ const timing = _optionalChain([stopwatch, 'optionalAccess', _261 => _261.stop, 'call', _262 => _262()]);
12554
11131
  if (timing) {
12555
11132
  const ms = (v) => `${v.toFixed(1)}ms`;
12556
11133
  const rest = timing.laps.slice(1);
@@ -12577,38 +11154,16 @@ function createRoom(options, config) {
12577
11154
  }
12578
11155
  break;
12579
11156
  }
12580
- // Receiving a RejectedOps message means the server refused some of
12581
- // our ops, so our optimistic local state is out of sync with the
12582
- // server. For LiveText ops this is a normal (if rare) situation
12583
- // e.g. a client that was offline long enough to fall outside the
12584
- // server's retained history window — and we can recover: drop the
12585
- // rejected pending state and re-fetch the authoritative storage
12586
- // snapshot. For other ops (e.g. permission rejections), rolling back
12587
- // particular Ops is hard/impossible, so we keep the old behavior of
12588
- // accepting the out-of-sync reality and surfacing an error.
11157
+ // Receiving a RejectedOps message in the client means that the server is no
11158
+ // longer in sync with the client. Trying to synchronize the client again by
11159
+ // rolling back particular Ops may be hard/impossible. It's fine to not try and
11160
+ // accept the out-of-sync reality and throw an error.
12589
11161
  case ServerMsgCode.REJECT_STORAGE_OP: {
12590
11162
  errorWithTitle(
12591
11163
  "Storage mutation rejection error",
12592
11164
  message.reason
12593
11165
  );
12594
- let needsStorageResync = false;
12595
- for (const opId of message.opIds) {
12596
- const rejectedOp = context.unacknowledgedOps.get(opId);
12597
- context.unacknowledgedOps.delete(opId);
12598
- context.buffer.storageOperations = context.buffer.storageOperations.filter((op) => op.opId !== opId);
12599
- viaByOpId.delete(opId);
12600
- if (rejectedOp !== void 0 && rejectedOp.type === OpCode.UPDATE_TEXT) {
12601
- const node = context.pool.nodes.get(rejectedOp.id);
12602
- if (node !== void 0 && isLiveText(node)) {
12603
- node._rejectPendingOp(opId);
12604
- needsStorageResync = true;
12605
- }
12606
- }
12607
- }
12608
- if (needsStorageResync) {
12609
- refreshStorage();
12610
- flushNowOrSoon();
12611
- } else if (process.env.NODE_ENV !== "production") {
11166
+ if (process.env.NODE_ENV !== "production") {
12612
11167
  throw new Error(
12613
11168
  `Storage mutations rejected by server: ${message.reason}`
12614
11169
  );
@@ -12707,11 +11262,11 @@ function createRoom(options, config) {
12707
11262
  } else if (pendingFeedsRequests.has(requestId)) {
12708
11263
  const pending = pendingFeedsRequests.get(requestId);
12709
11264
  pendingFeedsRequests.delete(requestId);
12710
- _optionalChain([pending, 'optionalAccess', _272 => _272.reject, 'call', _273 => _273(err)]);
11265
+ _optionalChain([pending, 'optionalAccess', _263 => _263.reject, 'call', _264 => _264(err)]);
12711
11266
  } else if (pendingFeedMessagesRequests.has(requestId)) {
12712
11267
  const pending = pendingFeedMessagesRequests.get(requestId);
12713
11268
  pendingFeedMessagesRequests.delete(requestId);
12714
- _optionalChain([pending, 'optionalAccess', _274 => _274.reject, 'call', _275 => _275(err)]);
11269
+ _optionalChain([pending, 'optionalAccess', _265 => _265.reject, 'call', _266 => _266(err)]);
12715
11270
  }
12716
11271
  eventHub.feeds.notify(message);
12717
11272
  break;
@@ -12865,10 +11420,10 @@ function createRoom(options, config) {
12865
11420
  timeoutId,
12866
11421
  kind,
12867
11422
  feedId,
12868
- messageId: _optionalChain([options2, 'optionalAccess', _276 => _276.messageId]),
12869
- expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _277 => _277.expectedClientMessageId])
11423
+ messageId: _optionalChain([options2, 'optionalAccess', _267 => _267.messageId]),
11424
+ expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _268 => _268.expectedClientMessageId])
12870
11425
  });
12871
- if (kind === "add-message" && _optionalChain([options2, 'optionalAccess', _278 => _278.expectedClientMessageId]) === void 0) {
11426
+ if (kind === "add-message" && _optionalChain([options2, 'optionalAccess', _269 => _269.expectedClientMessageId]) === void 0) {
12872
11427
  const q = _nullishCoalesce(pendingAddMessageFifoByFeed.get(feedId), () => ( []));
12873
11428
  q.push(requestId);
12874
11429
  pendingAddMessageFifoByFeed.set(feedId, q);
@@ -12919,10 +11474,10 @@ function createRoom(options, config) {
12919
11474
  }
12920
11475
  if (!matched) {
12921
11476
  const q = pendingAddMessageFifoByFeed.get(message.feedId);
12922
- const headId = _optionalChain([q, 'optionalAccess', _279 => _279[0]]);
11477
+ const headId = _optionalChain([q, 'optionalAccess', _270 => _270[0]]);
12923
11478
  if (headId !== void 0) {
12924
11479
  const pending = pendingFeedMutations.get(headId);
12925
- if (_optionalChain([pending, 'optionalAccess', _280 => _280.kind]) === "add-message" && pending.expectedClientMessageId === void 0) {
11480
+ if (_optionalChain([pending, 'optionalAccess', _271 => _271.kind]) === "add-message" && pending.expectedClientMessageId === void 0) {
12926
11481
  settleFeedMutation(headId, "ok");
12927
11482
  }
12928
11483
  }
@@ -12958,7 +11513,7 @@ function createRoom(options, config) {
12958
11513
  const unacknowledgedOps2 = [...context.unacknowledgedOps.values()];
12959
11514
  createOrUpdateRootFromMessage(nodes);
12960
11515
  applyAndSendOfflineOps(unacknowledgedOps2);
12961
- _optionalChain([_resolveStoragePromise, 'optionalCall', _281 => _281()]);
11516
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _272 => _272()]);
12962
11517
  notifyStorageStatus();
12963
11518
  eventHub.storageDidLoad.notify();
12964
11519
  }
@@ -12967,7 +11522,7 @@ function createRoom(options, config) {
12967
11522
  if (!messages.some((msg) => msg.type === ClientMsgCode.FETCH_STORAGE)) {
12968
11523
  messages.push({ type: ClientMsgCode.FETCH_STORAGE });
12969
11524
  nodeMapBuffer.take();
12970
- _optionalChain([stopwatch, 'optionalAccess', _282 => _282.start, 'call', _283 => _283()]);
11525
+ _optionalChain([stopwatch, 'optionalAccess', _273 => _273.start, 'call', _274 => _274()]);
12971
11526
  }
12972
11527
  }
12973
11528
  function startLoadingStorage() {
@@ -13021,10 +11576,10 @@ function createRoom(options, config) {
13021
11576
  const message = {
13022
11577
  type: ClientMsgCode.FETCH_FEEDS,
13023
11578
  requestId,
13024
- cursor: _optionalChain([options2, 'optionalAccess', _284 => _284.cursor]),
13025
- since: _optionalChain([options2, 'optionalAccess', _285 => _285.since]),
13026
- limit: _optionalChain([options2, 'optionalAccess', _286 => _286.limit]),
13027
- metadata: _optionalChain([options2, 'optionalAccess', _287 => _287.metadata])
11579
+ cursor: _optionalChain([options2, 'optionalAccess', _275 => _275.cursor]),
11580
+ since: _optionalChain([options2, 'optionalAccess', _276 => _276.since]),
11581
+ limit: _optionalChain([options2, 'optionalAccess', _277 => _277.limit]),
11582
+ metadata: _optionalChain([options2, 'optionalAccess', _278 => _278.metadata])
13028
11583
  };
13029
11584
  context.buffer.messages.push(message);
13030
11585
  flushNowOrSoon();
@@ -13044,9 +11599,9 @@ function createRoom(options, config) {
13044
11599
  type: ClientMsgCode.FETCH_FEED_MESSAGES,
13045
11600
  requestId,
13046
11601
  feedId,
13047
- cursor: _optionalChain([options2, 'optionalAccess', _288 => _288.cursor]),
13048
- since: _optionalChain([options2, 'optionalAccess', _289 => _289.since]),
13049
- limit: _optionalChain([options2, 'optionalAccess', _290 => _290.limit])
11602
+ cursor: _optionalChain([options2, 'optionalAccess', _279 => _279.cursor]),
11603
+ since: _optionalChain([options2, 'optionalAccess', _280 => _280.since]),
11604
+ limit: _optionalChain([options2, 'optionalAccess', _281 => _281.limit])
13050
11605
  };
13051
11606
  context.buffer.messages.push(message);
13052
11607
  flushNowOrSoon();
@@ -13065,8 +11620,8 @@ function createRoom(options, config) {
13065
11620
  type: ClientMsgCode.ADD_FEED,
13066
11621
  requestId,
13067
11622
  feedId,
13068
- metadata: _optionalChain([options2, 'optionalAccess', _291 => _291.metadata]),
13069
- createdAt: _optionalChain([options2, 'optionalAccess', _292 => _292.createdAt])
11623
+ metadata: _optionalChain([options2, 'optionalAccess', _282 => _282.metadata]),
11624
+ createdAt: _optionalChain([options2, 'optionalAccess', _283 => _283.createdAt])
13070
11625
  };
13071
11626
  context.buffer.messages.push(message);
13072
11627
  flushNowOrSoon();
@@ -13100,15 +11655,15 @@ function createRoom(options, config) {
13100
11655
  function addFeedMessage(feedId, data, options2) {
13101
11656
  const requestId = nanoid();
13102
11657
  const promise = registerFeedMutation(requestId, "add-message", feedId, {
13103
- expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _293 => _293.id])
11658
+ expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _284 => _284.id])
13104
11659
  });
13105
11660
  const message = {
13106
11661
  type: ClientMsgCode.ADD_FEED_MESSAGE,
13107
11662
  requestId,
13108
11663
  feedId,
13109
11664
  data,
13110
- id: _optionalChain([options2, 'optionalAccess', _294 => _294.id]),
13111
- createdAt: _optionalChain([options2, 'optionalAccess', _295 => _295.createdAt])
11665
+ id: _optionalChain([options2, 'optionalAccess', _285 => _285.id]),
11666
+ createdAt: _optionalChain([options2, 'optionalAccess', _286 => _286.createdAt])
13112
11667
  };
13113
11668
  context.buffer.messages.push(message);
13114
11669
  flushNowOrSoon();
@@ -13125,7 +11680,7 @@ function createRoom(options, config) {
13125
11680
  feedId,
13126
11681
  messageId,
13127
11682
  data,
13128
- updatedAt: _optionalChain([options2, 'optionalAccess', _296 => _296.updatedAt])
11683
+ updatedAt: _optionalChain([options2, 'optionalAccess', _287 => _287.updatedAt])
13129
11684
  };
13130
11685
  context.buffer.messages.push(message);
13131
11686
  flushNowOrSoon();
@@ -13150,15 +11705,14 @@ function createRoom(options, config) {
13150
11705
  if (context.activeBatch) {
13151
11706
  throw new Error("undo is not allowed during a batch");
13152
11707
  }
13153
- const item = context.undoStack.pop();
13154
- if (item === void 0) {
11708
+ const frames = context.undoStack.pop();
11709
+ if (frames === void 0) {
13155
11710
  return;
13156
11711
  }
13157
11712
  context.pausedHistory = null;
13158
- const result = applyLocalOps(item.frames, LOCAL_UNDO);
13159
- context.redoStack.push({ id: item.id, frames: result.reverse });
13160
- notifyPrivateHistory({ action: "undo", id: item.id });
11713
+ const result = applyLocalOps(frames);
13161
11714
  notify(result.updates);
11715
+ context.redoStack.push(result.reverse);
13162
11716
  onHistoryChange();
13163
11717
  for (const op of result.opsToEmit) {
13164
11718
  context.buffer.storageOperations.push(op);
@@ -13169,15 +11723,14 @@ function createRoom(options, config) {
13169
11723
  if (context.activeBatch) {
13170
11724
  throw new Error("redo is not allowed during a batch");
13171
11725
  }
13172
- const item = context.redoStack.pop();
13173
- if (item === void 0) {
11726
+ const frames = context.redoStack.pop();
11727
+ if (frames === void 0) {
13174
11728
  return;
13175
11729
  }
13176
11730
  context.pausedHistory = null;
13177
- const result = applyLocalOps(item.frames, LOCAL_REDO);
13178
- context.undoStack.push({ id: item.id, frames: result.reverse });
13179
- notifyPrivateHistory({ action: "redo", id: item.id });
11731
+ const result = applyLocalOps(frames);
13180
11732
  notify(result.updates);
11733
+ context.undoStack.push(result.reverse);
13181
11734
  onHistoryChange();
13182
11735
  for (const op of result.opsToEmit) {
13183
11736
  context.buffer.storageOperations.push(op);
@@ -13187,8 +11740,6 @@ function createRoom(options, config) {
13187
11740
  function clear() {
13188
11741
  context.undoStack.length = 0;
13189
11742
  context.redoStack.length = 0;
13190
- notifyPrivateHistory({ action: "clear" });
13191
- onHistoryChange();
13192
11743
  }
13193
11744
  function batch2(callback) {
13194
11745
  if (context.activeBatch) {
@@ -13216,8 +11767,8 @@ function createRoom(options, config) {
13216
11767
  if (currentBatch.scheduleHistoryResume) {
13217
11768
  commitPausedHistoryToUndoStack();
13218
11769
  }
13219
- if (currentBatch.ops.length > 0 || currentBatch.clearRedoStack) {
13220
- clearRedoStack();
11770
+ if (currentBatch.ops.length > 0) {
11771
+ context.redoStack.length = 0;
13221
11772
  }
13222
11773
  if (currentBatch.ops.length > 0) {
13223
11774
  dispatchOps(currentBatch.ops);
@@ -13246,6 +11797,7 @@ function createRoom(options, config) {
13246
11797
  }
13247
11798
  commitPausedHistoryToUndoStack();
13248
11799
  }
11800
+ let historyDisabled = 0;
13249
11801
  function disableHistory(fn) {
13250
11802
  const origUndo = context.undoStack;
13251
11803
  const origRedo = context.redoStack;
@@ -13335,8 +11887,8 @@ function createRoom(options, config) {
13335
11887
  async function getThreads(options2) {
13336
11888
  return httpClient.getThreads({
13337
11889
  roomId,
13338
- query: _optionalChain([options2, 'optionalAccess', _297 => _297.query]),
13339
- cursor: _optionalChain([options2, 'optionalAccess', _298 => _298.cursor])
11890
+ query: _optionalChain([options2, 'optionalAccess', _288 => _288.query]),
11891
+ cursor: _optionalChain([options2, 'optionalAccess', _289 => _289.cursor])
13340
11892
  });
13341
11893
  }
13342
11894
  async function getThread(threadId) {
@@ -13469,7 +12021,7 @@ function createRoom(options, config) {
13469
12021
  function getSubscriptionSettings(options2) {
13470
12022
  return httpClient.getSubscriptionSettings({
13471
12023
  roomId,
13472
- signal: _optionalChain([options2, 'optionalAccess', _299 => _299.signal])
12024
+ signal: _optionalChain([options2, 'optionalAccess', _290 => _290.signal])
13473
12025
  });
13474
12026
  }
13475
12027
  function updateSubscriptionSettings(settings) {
@@ -13491,45 +12043,30 @@ function createRoom(options, config) {
13491
12043
  {
13492
12044
  [kInternal]: {
13493
12045
  get presenceBuffer() {
13494
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _300 => _300.buffer, 'access', _301 => _301.presenceUpdates, 'optionalAccess', _302 => _302.data]), () => ( null)));
12046
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _291 => _291.buffer, 'access', _292 => _292.presenceUpdates, 'optionalAccess', _293 => _293.data]), () => ( null)));
13495
12047
  },
13496
12048
  // prettier-ignore
13497
12049
  get undoStack() {
13498
- return structuredClone(
13499
- context.undoStack.map((item) => ({
13500
- id: item.id,
13501
- frames: item.frames
13502
- }))
13503
- );
13504
- },
13505
- // prettier-ignore
13506
- get redoStack() {
13507
- return structuredClone(
13508
- context.redoStack.map((item) => ({
13509
- id: item.id,
13510
- frames: item.frames
13511
- }))
13512
- );
12050
+ return deepClone(context.undoStack);
13513
12051
  },
13514
12052
  // prettier-ignore
13515
12053
  get nodeCount() {
13516
12054
  return context.pool.nodes.size;
13517
12055
  },
13518
12056
  // prettier-ignore
13519
- history: eventHub.privateHistory.observable,
13520
12057
  getYjsProvider() {
13521
12058
  return context.yjsProvider;
13522
12059
  },
13523
12060
  setYjsProvider(newProvider) {
13524
- _optionalChain([context, 'access', _303 => _303.yjsProvider, 'optionalAccess', _304 => _304.off, 'call', _305 => _305("status", yjsStatusDidChange)]);
12061
+ _optionalChain([context, 'access', _294 => _294.yjsProvider, 'optionalAccess', _295 => _295.off, 'call', _296 => _296("status", yjsStatusDidChange)]);
13525
12062
  context.yjsProvider = newProvider;
13526
- _optionalChain([newProvider, 'optionalAccess', _306 => _306.on, 'call', _307 => _307("status", yjsStatusDidChange)]);
12063
+ _optionalChain([newProvider, 'optionalAccess', _297 => _297.on, 'call', _298 => _298("status", yjsStatusDidChange)]);
13527
12064
  context.yjsProviderDidChange.notify();
13528
12065
  },
13529
12066
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
13530
12067
  // send metadata when using a text editor
13531
12068
  reportTextEditor,
13532
- getPermissionMatrix: () => _optionalChain([context, 'access', _308 => _308.dynamicSessionInfoSig, 'access', _309 => _309.get, 'call', _310 => _310(), 'optionalAccess', _311 => _311.permissionMatrix]),
12069
+ getPermissionMatrix: () => _optionalChain([context, 'access', _299 => _299.dynamicSessionInfoSig, 'access', _300 => _300.get, 'call', _301 => _301(), 'optionalAccess', _302 => _302.permissionMatrix]),
13533
12070
  // create a text mention when using a text editor
13534
12071
  createTextMention,
13535
12072
  // delete a text mention when using a text editor
@@ -13592,7 +12129,7 @@ ${dumpPool(
13592
12129
  source.dispose();
13593
12130
  }
13594
12131
  eventHub.roomWillDestroy.notify();
13595
- _optionalChain([context, 'access', _312 => _312.yjsProvider, 'optionalAccess', _313 => _313.off, 'call', _314 => _314("status", yjsStatusDidChange)]);
12132
+ _optionalChain([context, 'access', _303 => _303.yjsProvider, 'optionalAccess', _304 => _304.off, 'call', _305 => _305("status", yjsStatusDidChange)]);
13596
12133
  syncSourceForStorage.destroy();
13597
12134
  syncSourceForYjs.destroy();
13598
12135
  uninstallBgTabSpy();
@@ -13756,7 +12293,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
13756
12293
  }
13757
12294
  if (isLiveNode(first)) {
13758
12295
  const node = first;
13759
- if (_optionalChain([options, 'optionalAccess', _315 => _315.isDeep])) {
12296
+ if (_optionalChain([options, 'optionalAccess', _306 => _306.isDeep])) {
13760
12297
  const storageCallback = second;
13761
12298
  return subscribeToLiveStructureDeeply(node, storageCallback);
13762
12299
  } else {
@@ -13846,8 +12383,8 @@ function createClient(options) {
13846
12383
  const authManager = createAuthManager(options, (token) => {
13847
12384
  currentUserId.set(() => token.uid);
13848
12385
  });
13849
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _316 => _316.polyfills, 'optionalAccess', _317 => _317.fetch]) || /* istanbul ignore next */
13850
- _optionalChain([globalThis, 'access', _318 => _318.fetch, 'optionalAccess', _319 => _319.bind, 'call', _320 => _320(globalThis)]);
12386
+ const fetchPolyfill = _optionalChain([clientOptions, 'access', _307 => _307.polyfills, 'optionalAccess', _308 => _308.fetch]) || /* istanbul ignore next */
12387
+ _optionalChain([globalThis, 'access', _309 => _309.fetch, 'optionalAccess', _310 => _310.bind, 'call', _311 => _311(globalThis)]);
13851
12388
  const httpClient = createApiClient({
13852
12389
  baseUrl,
13853
12390
  fetchPolyfill,
@@ -13864,7 +12401,7 @@ function createClient(options) {
13864
12401
  delegates: {
13865
12402
  createSocket: makeCreateSocketDelegateForAi(
13866
12403
  baseUrl,
13867
- _optionalChain([clientOptions, 'access', _321 => _321.polyfills, 'optionalAccess', _322 => _322.WebSocket])
12404
+ _optionalChain([clientOptions, 'access', _312 => _312.polyfills, 'optionalAccess', _313 => _313.WebSocket])
13868
12405
  ),
13869
12406
  authenticate: async () => {
13870
12407
  const resp = await authManager.getAuthValue({
@@ -13935,7 +12472,7 @@ function createClient(options) {
13935
12472
  createSocket: makeCreateSocketDelegateForRoom(
13936
12473
  roomId,
13937
12474
  baseUrl,
13938
- _optionalChain([clientOptions, 'access', _323 => _323.polyfills, 'optionalAccess', _324 => _324.WebSocket])
12475
+ _optionalChain([clientOptions, 'access', _314 => _314.polyfills, 'optionalAccess', _315 => _315.WebSocket])
13939
12476
  ),
13940
12477
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
13941
12478
  })),
@@ -13957,7 +12494,7 @@ function createClient(options) {
13957
12494
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
13958
12495
  if (shouldConnect) {
13959
12496
  if (typeof atob === "undefined") {
13960
- if (_optionalChain([clientOptions, 'access', _325 => _325.polyfills, 'optionalAccess', _326 => _326.atob]) === void 0) {
12497
+ if (_optionalChain([clientOptions, 'access', _316 => _316.polyfills, 'optionalAccess', _317 => _317.atob]) === void 0) {
13961
12498
  throw new Error(
13962
12499
  "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"
13963
12500
  );
@@ -13969,7 +12506,7 @@ function createClient(options) {
13969
12506
  return leaseRoom(newRoomDetails);
13970
12507
  }
13971
12508
  function getRoom(roomId) {
13972
- const room = _optionalChain([roomsById, 'access', _327 => _327.get, 'call', _328 => _328(roomId), 'optionalAccess', _329 => _329.room]);
12509
+ const room = _optionalChain([roomsById, 'access', _318 => _318.get, 'call', _319 => _319(roomId), 'optionalAccess', _320 => _320.room]);
13973
12510
  return room ? room : null;
13974
12511
  }
13975
12512
  function logout() {
@@ -13985,7 +12522,7 @@ function createClient(options) {
13985
12522
  const batchedResolveUsers = new Batch(
13986
12523
  async (batchedUserIds) => {
13987
12524
  const userIds = batchedUserIds.flat();
13988
- const users = await _optionalChain([resolveUsers, 'optionalCall', _330 => _330({ userIds })]);
12525
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _321 => _321({ userIds })]);
13989
12526
  warnOnceIf(
13990
12527
  !resolveUsers,
13991
12528
  "Set the resolveUsers option in createClient to specify user info."
@@ -14002,7 +12539,7 @@ function createClient(options) {
14002
12539
  const batchedResolveRoomsInfo = new Batch(
14003
12540
  async (batchedRoomIds) => {
14004
12541
  const roomIds = batchedRoomIds.flat();
14005
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _331 => _331({ roomIds })]);
12542
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _322 => _322({ roomIds })]);
14006
12543
  warnOnceIf(
14007
12544
  !resolveRoomsInfo,
14008
12545
  "Set the resolveRoomsInfo option in createClient to specify room info."
@@ -14019,7 +12556,7 @@ function createClient(options) {
14019
12556
  const batchedResolveGroupsInfo = new Batch(
14020
12557
  async (batchedGroupIds) => {
14021
12558
  const groupIds = batchedGroupIds.flat();
14022
- const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _332 => _332({ groupIds })]);
12559
+ const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _323 => _323({ groupIds })]);
14023
12560
  warnOnceIf(
14024
12561
  !resolveGroupsInfo,
14025
12562
  "Set the resolveGroupsInfo option in createClient to specify group info."
@@ -14078,7 +12615,7 @@ function createClient(options) {
14078
12615
  }
14079
12616
  };
14080
12617
  const win = typeof window !== "undefined" ? window : void 0;
14081
- _optionalChain([win, 'optionalAccess', _333 => _333.addEventListener, 'call', _334 => _334("beforeunload", maybePreventClose)]);
12618
+ _optionalChain([win, 'optionalAccess', _324 => _324.addEventListener, 'call', _325 => _325("beforeunload", maybePreventClose)]);
14082
12619
  }
14083
12620
  async function getNotificationSettings(options2) {
14084
12621
  const plainSettings = await httpClient.getNotificationSettings(options2);
@@ -14206,7 +12743,7 @@ var commentBodyElementsTypes = {
14206
12743
  mention: "inline"
14207
12744
  };
14208
12745
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
14209
- if (!body || !_optionalChain([body, 'optionalAccess', _335 => _335.content])) {
12746
+ if (!body || !_optionalChain([body, 'optionalAccess', _326 => _326.content])) {
14210
12747
  return;
14211
12748
  }
14212
12749
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -14216,13 +12753,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
14216
12753
  for (const block of body.content) {
14217
12754
  if (type === "all" || type === "block") {
14218
12755
  if (guard(block)) {
14219
- _optionalChain([visitor, 'optionalCall', _336 => _336(block)]);
12756
+ _optionalChain([visitor, 'optionalCall', _327 => _327(block)]);
14220
12757
  }
14221
12758
  }
14222
12759
  if (type === "all" || type === "inline") {
14223
12760
  for (const inline of block.children) {
14224
12761
  if (guard(inline)) {
14225
- _optionalChain([visitor, 'optionalCall', _337 => _337(inline)]);
12762
+ _optionalChain([visitor, 'optionalCall', _328 => _328(inline)]);
14226
12763
  }
14227
12764
  }
14228
12765
  }
@@ -14392,7 +12929,7 @@ var stringifyCommentBodyPlainElements = {
14392
12929
  text: ({ element }) => element.text,
14393
12930
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
14394
12931
  mention: ({ element, user, group }) => {
14395
- return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _338 => _338.name]), () => ( _optionalChain([group, 'optionalAccess', _339 => _339.name]))), () => ( element.id))}`;
12932
+ return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _329 => _329.name]), () => ( _optionalChain([group, 'optionalAccess', _330 => _330.name]))), () => ( element.id))}`;
14396
12933
  }
14397
12934
  };
14398
12935
  var stringifyCommentBodyHtmlElements = {
@@ -14422,7 +12959,7 @@ var stringifyCommentBodyHtmlElements = {
14422
12959
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
14423
12960
  },
14424
12961
  mention: ({ element, user, group }) => {
14425
- return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _340 => _340.name]) ? html`${_optionalChain([user, 'optionalAccess', _341 => _341.name])}` : _optionalChain([group, 'optionalAccess', _342 => _342.name]) ? html`${_optionalChain([group, 'optionalAccess', _343 => _343.name])}` : element.id}</span>`;
12962
+ return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _331 => _331.name]) ? html`${_optionalChain([user, 'optionalAccess', _332 => _332.name])}` : _optionalChain([group, 'optionalAccess', _333 => _333.name]) ? html`${_optionalChain([group, 'optionalAccess', _334 => _334.name])}` : element.id}</span>`;
14426
12963
  }
14427
12964
  };
14428
12965
  var stringifyCommentBodyMarkdownElements = {
@@ -14452,20 +12989,20 @@ var stringifyCommentBodyMarkdownElements = {
14452
12989
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
14453
12990
  },
14454
12991
  mention: ({ element, user, group }) => {
14455
- return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _344 => _344.name]), () => ( _optionalChain([group, 'optionalAccess', _345 => _345.name]))), () => ( element.id))}`;
12992
+ return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _335 => _335.name]), () => ( _optionalChain([group, 'optionalAccess', _336 => _336.name]))), () => ( element.id))}`;
14456
12993
  }
14457
12994
  };
14458
12995
  async function stringifyCommentBody(body, options) {
14459
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _346 => _346.format]), () => ( "plain"));
14460
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _347 => _347.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
12996
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _337 => _337.format]), () => ( "plain"));
12997
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _338 => _338.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
14461
12998
  const elements = {
14462
12999
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
14463
- ..._optionalChain([options, 'optionalAccess', _348 => _348.elements])
13000
+ ..._optionalChain([options, 'optionalAccess', _339 => _339.elements])
14464
13001
  };
14465
13002
  const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
14466
13003
  body,
14467
- _optionalChain([options, 'optionalAccess', _349 => _349.resolveUsers]),
14468
- _optionalChain([options, 'optionalAccess', _350 => _350.resolveGroupsInfo])
13004
+ _optionalChain([options, 'optionalAccess', _340 => _340.resolveUsers]),
13005
+ _optionalChain([options, 'optionalAccess', _341 => _341.resolveGroupsInfo])
14469
13006
  );
14470
13007
  const blocks = body.content.flatMap((block, blockIndex) => {
14471
13008
  switch (block.type) {
@@ -14547,12 +13084,6 @@ function toPlainLson(lson) {
14547
13084
  liveblocksType: "LiveList",
14548
13085
  data: [...lson].map((item) => toPlainLson(item))
14549
13086
  };
14550
- } else if (lson instanceof LiveText) {
14551
- return {
14552
- liveblocksType: "LiveText",
14553
- data: lson.toJSON(),
14554
- version: lson.version
14555
- };
14556
13087
  } else if (lson instanceof LiveFile) {
14557
13088
  return {
14558
13089
  liveblocksType: "LiveFile",
@@ -14611,9 +13142,9 @@ function makePoller(callback, intervalMs, options) {
14611
13142
  const startTime = performance.now();
14612
13143
  const doc = typeof document !== "undefined" ? document : void 0;
14613
13144
  const win = typeof window !== "undefined" ? window : void 0;
14614
- const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _351 => _351.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
13145
+ const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _342 => _342.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
14615
13146
  const context = {
14616
- inForeground: _optionalChain([doc, 'optionalAccess', _352 => _352.visibilityState]) !== "hidden",
13147
+ inForeground: _optionalChain([doc, 'optionalAccess', _343 => _343.visibilityState]) !== "hidden",
14617
13148
  lastSuccessfulPollAt: startTime,
14618
13149
  count: 0,
14619
13150
  backoff: 0
@@ -14694,11 +13225,11 @@ function makePoller(callback, intervalMs, options) {
14694
13225
  pollNowIfStale();
14695
13226
  }
14696
13227
  function onVisibilityChange() {
14697
- setInForeground(_optionalChain([doc, 'optionalAccess', _353 => _353.visibilityState]) !== "hidden");
13228
+ setInForeground(_optionalChain([doc, 'optionalAccess', _344 => _344.visibilityState]) !== "hidden");
14698
13229
  }
14699
- _optionalChain([doc, 'optionalAccess', _354 => _354.addEventListener, 'call', _355 => _355("visibilitychange", onVisibilityChange)]);
14700
- _optionalChain([win, 'optionalAccess', _356 => _356.addEventListener, 'call', _357 => _357("online", onVisibilityChange)]);
14701
- _optionalChain([win, 'optionalAccess', _358 => _358.addEventListener, 'call', _359 => _359("focus", pollNowIfStale)]);
13230
+ _optionalChain([doc, 'optionalAccess', _345 => _345.addEventListener, 'call', _346 => _346("visibilitychange", onVisibilityChange)]);
13231
+ _optionalChain([win, 'optionalAccess', _347 => _347.addEventListener, 'call', _348 => _348("online", onVisibilityChange)]);
13232
+ _optionalChain([win, 'optionalAccess', _349 => _349.addEventListener, 'call', _350 => _350("focus", pollNowIfStale)]);
14702
13233
  fsm.start();
14703
13234
  return {
14704
13235
  inc,
@@ -14847,9 +13378,5 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
14847
13378
 
14848
13379
 
14849
13380
 
14850
-
14851
-
14852
-
14853
-
14854
- exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.Deque = Deque; exports.DerivedSignal = DerivedSignal; exports.FeedRequestErrorCode = FeedRequestErrorCode; exports.HttpError = HttpError; exports.LiveFile = LiveFile; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveText = LiveText; exports.LiveblocksError = LiveblocksError; exports.MENTION_CHARACTER = MENTION_CHARACTER; exports.MutableSignal = MutableSignal; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.applyLiveTextOperations = applyLiveTextOperations; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.checkBounds = checkBounds; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactNodesToNodeStream = compactNodesToNodeStream; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToGroupData = convertToGroupData; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToSubscriptionData = convertToSubscriptionData; exports.convertToThreadData = convertToThreadData; exports.convertToUserSubscriptionData = convertToUserSubscriptionData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createManagedPool = createManagedPool; exports.createNotificationSettings = createNotificationSettings; exports.createStorageFileId = createStorageFileId; exports.createThreadId = createThreadId; exports.deepLiveify = deepLiveify; exports.defineAiTool = defineAiTool; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.entries = entries; exports.errorIf = errorIf; exports.findLastIndex = findLastIndex; exports.freeze = freeze; exports.generateUrl = generateUrl; exports.getLiveFileId = getLiveFileId; exports.getMentionsFromCommentBody = getMentionsFromCommentBody; exports.getSubscriptionKey = getSubscriptionKey; exports.hasPermissionAccess = hasPermissionAccess; exports.html = html; exports.htmlSafe = htmlSafe; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isFileStorageNode = isFileStorageNode; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isListStorageNode = isListStorageNode; exports.isLiveNode = isLiveNode; exports.isMapStorageNode = isMapStorageNode; exports.isNotificationChannelEnabled = isNotificationChannelEnabled; exports.isNumberOperator = isNumberOperator; exports.isObjectStorageNode = isObjectStorageNode; exports.isPlainObject = isPlainObject; exports.isRegisterStorageNode = isRegisterStorageNode; exports.isRootStorageNode = isRootStorageNode; exports.isStartsWithOperator = isStartsWithOperator; exports.isTextStorageNode = isTextStorageNode; exports.isUrl = isUrl; exports.kInternal = kInternal; exports.keys = keys; exports.makeAbortController = makeAbortController; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.mergeRoomPermissionScopes = mergeRoomPermissionScopes; exports.nanoid = nanoid; exports.nn = nn; exports.nodeStreamToCompactNodes = nodeStreamToCompactNodes; exports.normalizeRoomAccesses = normalizeRoomAccesses; exports.normalizeRoomPermissions = normalizeRoomPermissions; exports.normalizeUpdateRoomAccesses = normalizeUpdateRoomAccesses; exports.objectToQuery = objectToQuery; exports.patchNotificationSettings = patchNotificationSettings; exports.permissionMatrixFromScopes = permissionMatrixFromScopes; exports.raise = raise; exports.resolveMentionsInCommentBody = resolveMentionsInCommentBody; exports.sanitizeUrl = sanitizeUrl; exports.shallow = shallow; exports.shallow2 = shallow2; exports.stableStringify = stableStringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.transformTextOperations = transformTextOperations; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.validatePermissionsSet = validatePermissionsSet; exports.wait = wait; exports.warnOnce = warnOnce; exports.warnOnceIf = warnOnceIf; exports.withTimeout = withTimeout;
13381
+ exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.Deque = Deque; exports.DerivedSignal = DerivedSignal; exports.FeedRequestErrorCode = FeedRequestErrorCode; exports.HttpError = HttpError; exports.LiveFile = LiveFile; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveblocksError = LiveblocksError; exports.MENTION_CHARACTER = MENTION_CHARACTER; exports.MutableSignal = MutableSignal; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.checkBounds = checkBounds; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactNodesToNodeStream = compactNodesToNodeStream; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToGroupData = convertToGroupData; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToSubscriptionData = convertToSubscriptionData; exports.convertToThreadData = convertToThreadData; exports.convertToUserSubscriptionData = convertToUserSubscriptionData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createManagedPool = createManagedPool; exports.createNotificationSettings = createNotificationSettings; exports.createStorageFileId = createStorageFileId; exports.createThreadId = createThreadId; exports.deepLiveify = deepLiveify; exports.defineAiTool = defineAiTool; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.entries = entries; exports.errorIf = errorIf; exports.findLastIndex = findLastIndex; exports.freeze = freeze; exports.generateUrl = generateUrl; exports.getLiveFileId = getLiveFileId; exports.getMentionsFromCommentBody = getMentionsFromCommentBody; exports.getSubscriptionKey = getSubscriptionKey; exports.hasPermissionAccess = hasPermissionAccess; exports.html = html; exports.htmlSafe = htmlSafe; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isFileStorageNode = isFileStorageNode; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isListStorageNode = isListStorageNode; exports.isLiveNode = isLiveNode; exports.isMapStorageNode = isMapStorageNode; exports.isNotificationChannelEnabled = isNotificationChannelEnabled; exports.isNumberOperator = isNumberOperator; exports.isObjectStorageNode = isObjectStorageNode; exports.isPlainObject = isPlainObject; exports.isRegisterStorageNode = isRegisterStorageNode; exports.isRootStorageNode = isRootStorageNode; exports.isStartsWithOperator = isStartsWithOperator; exports.isUrl = isUrl; exports.kInternal = kInternal; exports.keys = keys; exports.makeAbortController = makeAbortController; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.mergeRoomPermissionScopes = mergeRoomPermissionScopes; exports.nanoid = nanoid; exports.nn = nn; exports.nodeStreamToCompactNodes = nodeStreamToCompactNodes; exports.normalizeRoomAccesses = normalizeRoomAccesses; exports.normalizeRoomPermissions = normalizeRoomPermissions; exports.normalizeUpdateRoomAccesses = normalizeUpdateRoomAccesses; exports.objectToQuery = objectToQuery; exports.patchNotificationSettings = patchNotificationSettings; exports.permissionMatrixFromScopes = permissionMatrixFromScopes; exports.raise = raise; exports.resolveMentionsInCommentBody = resolveMentionsInCommentBody; exports.sanitizeUrl = sanitizeUrl; exports.shallow = shallow; exports.shallow2 = shallow2; exports.stableStringify = stableStringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.validatePermissionsSet = validatePermissionsSet; exports.wait = wait; exports.warnOnce = warnOnce; exports.warnOnceIf = warnOnceIf; exports.withTimeout = withTimeout;
14855
13382
  //# sourceMappingURL=index.cjs.map