@liveblocks/core 3.23.1-exp3 → 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-exp3";
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,1380 +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 normalizeLiveTextOperations(data, operations) {
9742
- let shadow = dataToSegments(data);
9743
- const normalized = [];
9744
- for (const operation of operations) {
9745
- const text = shadow.map((segment) => segment.text).join("");
9746
- let normalizedOperation;
9747
- if (operation.type === "insert") {
9748
- normalizedOperation = {
9749
- ...operation,
9750
- index: clipIndexToCodePointBoundary(text, operation.index)
9751
- };
9752
- } else {
9753
- const range = clipRangeToCodePointBoundaries(
9754
- text,
9755
- operation.index,
9756
- operation.length
9757
- );
9758
- normalizedOperation = {
9759
- ...operation,
9760
- index: range.index,
9761
- length: range.length
9762
- };
9763
- }
9764
- normalized.push(normalizedOperation);
9765
- shadow = applyTextOperationsToSegments(shadow, [normalizedOperation]);
9766
- }
9767
- return normalized;
9768
- }
9769
- function invertTextOperations(segments, ops) {
9770
- let shadow = [...segments];
9771
- const reverse = [];
9772
- for (const op of ops) {
9773
- if (op.type === "insert") {
9774
- shadow = applyInsert(shadow, op.index, op.text, op.attributes);
9775
- reverse.unshift({
9776
- type: "delete",
9777
- index: op.index,
9778
- length: op.text.length
9779
- });
9780
- } else if (op.type === "delete") {
9781
- const deletedSegments = extractDeletedSegments(
9782
- shadow,
9783
- op.index,
9784
- op.length
9785
- );
9786
- shadow = applyDelete(shadow, op.index, op.length).segments;
9787
- const inserts = [];
9788
- let insertIndex = op.index;
9789
- for (const segment of deletedSegments) {
9790
- inserts.push({
9791
- type: "insert",
9792
- index: insertIndex,
9793
- text: segment.text,
9794
- attributes: segment.attributes
9795
- });
9796
- insertIndex += segment.text.length;
9797
- }
9798
- for (let index = inserts.length - 1; index >= 0; index--) {
9799
- reverse.unshift(inserts[index]);
9800
- }
9801
- } else {
9802
- const inverse = formatReverseOperations(
9803
- shadow,
9804
- op.index,
9805
- op.length,
9806
- op.attributes
9807
- );
9808
- shadow = applyFormat(shadow, op.index, op.length, op.attributes);
9809
- reverse.unshift(...inverse.reverse());
9810
- }
9811
- }
9812
- return reverse;
9813
- }
9814
-
9815
- // src/crdts/LiveText.ts
9816
- var ACCEPTED_OPS_HISTORY_LIMIT = 1e3;
9817
- var LiveText = class _LiveText extends AbstractCrdt {
9818
- /** The local document: #confirmed ⊕ #inFlightOps ⊕ #queuedOps. */
9819
- #segments;
9820
- /** The server-confirmed document (only authoritative ops applied). */
9821
- #confirmed;
9822
- #version;
9823
- /** The op currently awaiting server acknowledgement (at most one). */
9824
- #inFlightOpId;
9825
- /** Its ops, continuously re-expressed against current server state. */
9826
- #inFlightOps = [];
9827
- /** Local edits made while an op is in flight; sent after the ack. */
9828
- #queuedOps = [];
9829
- #acceptedOps = [];
9830
- /**
9831
- * Creates a new LiveText document.
9832
- *
9833
- * @param textOrData Initial plain text, or an array of `[text]` /
9834
- * `[text, attributes]` segments. Defaults to an empty document.
9835
- *
9836
- * @example
9837
- * new LiveText();
9838
- * new LiveText("Hello world");
9839
- * new LiveText([["Hello ", { bold: true }], ["world"]]);
9840
- */
9841
- constructor(textOrData = "", version = 0) {
9842
- super();
9843
- this.#segments = typeof textOrData === "string" ? textOrData.length === 0 ? [] : [{ text: textOrData }] : dataToSegments(textOrData);
9844
- this.#confirmed = [...this.#segments];
9845
- this.#version = version;
9846
- Object.assign(this[kInternal], {
9847
- encodeIndex: (localIndex) => this.#encodeIndex(localIndex),
9848
- decodeIndex: (index, fromVersion) => this.#decodeIndex(index, fromVersion)
9849
- });
9850
- }
9851
- get version() {
9852
- return this.#version;
9853
- }
9854
- get length() {
9855
- return textLength(this.#segments);
9856
- }
9857
- /** @internal */
9858
- static _deserialize([id, item], _parentToChildren, pool) {
9859
- const text = new _LiveText(item.data, item.version);
9860
- text._attach(id, pool);
9861
- return text;
9862
- }
9863
- /** @internal */
9864
- _toOps(parentId, parentKey) {
9865
- if (this._id === void 0) {
9866
- throw new Error("Cannot serialize LiveText if it is not attached");
9867
- }
9868
- return [
9869
- {
9870
- type: OpCode.CREATE_TEXT,
9871
- id: this._id,
9872
- parentId,
9873
- parentKey,
9874
- data: this.toJSON(),
9875
- version: this.#version
9876
- }
9877
- ];
9878
- }
9879
- /** @internal */
9880
- _serialize() {
9881
- if (this.parent.type !== "HasParent") {
9882
- throw new Error("Cannot serialize LiveText if parent is missing");
9883
- }
9884
- return {
9885
- type: CrdtType.TEXT,
9886
- parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
9887
- parentKey: this.parent.key,
9888
- data: this.toJSON(),
9889
- version: this.#version
9890
- };
9891
- }
9892
- /** @internal */
9893
- _attachChild(_op) {
9894
- throw new Error("LiveText cannot contain child nodes");
9895
- }
9896
- /** @internal */
9897
- _detachChild(_crdt) {
9898
- throw new Error("LiveText cannot contain child nodes");
9899
- }
9900
- /** @internal */
9901
- _apply(op, source) {
9902
- if (op.type !== OpCode.UPDATE_TEXT) {
9903
- return super._apply(op, source);
9904
- }
9905
- if (source.origin === "local" && source.optimistic) {
9906
- return this.#applyLocal(op, toUpdateSource(source));
9907
- }
9908
- if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
9909
- return this.#applyAck(op, toUpdateSource(source));
9910
- }
9911
- if (op.opId !== void 0 && this.#acceptedOps.some((entry) => entry.opId === op.opId)) {
9912
- this.#version = Math.max(this.#version, _nullishCoalesce(op.version, () => ( op.baseVersion + 1)));
9913
- return { modified: false };
9914
- }
9915
- return this.#applyRemote(op, toUpdateSource(source));
9916
- }
9917
- /**
9918
- * Inserts text at the given index.
9919
- *
9920
- * @param index Character index at which to insert. Values outside the
9921
- * document range are clipped.
9922
- * @param text Text to insert.
9923
- * @param attributes Optional inline attributes for the inserted text.
9924
- *
9925
- * @example
9926
- * const text = new LiveText("Hello");
9927
- * text.insert(5, " world");
9928
- * text.insert(0, "Say: ", { italic: true });
9929
- */
9930
- insert(index, text, attributes) {
9931
- const clippedIndex = clipIndexToCodePointBoundary(this.toString(), index);
9932
- this.#dispatch([{ type: "insert", index: clippedIndex, text, attributes }]);
9933
- }
9934
- /**
9935
- * Deletes `length` characters starting at `index`.
9936
- *
9937
- * @example
9938
- * const text = new LiveText("Hello world");
9939
- * text.delete(5, 6); // "Hello"
9940
- */
9941
- delete(index, length) {
9942
- const clipped = clipRangeToCodePointBoundaries(
9943
- this.toString(),
9944
- index,
9945
- length
9946
- );
9947
- if (clipped.length === 0) {
9948
- return;
9949
- }
9950
- this.#dispatch([
9951
- { type: "delete", index: clipped.index, length: clipped.length }
9952
- ]);
9953
- }
9954
- /**
9955
- * Replaces a range of text with new text.
9956
- *
9957
- * @example
9958
- * const text = new LiveText("Hello world");
9959
- * text.replace(0, 5, "Hi"); // "Hi world"
9960
- */
9961
- replace(index, length, text, attributes) {
9962
- const clipped = clipRangeToCodePointBoundaries(
9963
- this.toString(),
9964
- index,
9965
- length
9966
- );
9967
- const ops = [];
9968
- if (clipped.length > 0) {
9969
- ops.push({
9970
- type: "delete",
9971
- index: clipped.index,
9972
- length: clipped.length
9973
- });
9974
- }
9975
- if (text.length > 0) {
9976
- ops.push({ type: "insert", index: clipped.index, text, attributes });
9977
- }
9978
- this.#dispatch(ops);
9979
- }
9980
- /**
9981
- * Encode a local-document index (an offset into this LiveText's current
9982
- * #segments, which CodeMirror or any consumer mirrors as its document)
9983
- * into server-confirmed coordinates suitable for broadcasting to peers via
9984
- * presence or any other side channel.
9985
- *
9986
- * The returned index is in this LiveText's current #confirmed coordinates
9987
- * — that is, with this client's local pending ops inverse-mapped out.
9988
- * Pair it with the current {@link LiveText.version} when sending so the
9989
- * receiver can call {@link PrivateLiveTextApi.decodeIndex} to land the
9990
- * position in their own local document coordinates regardless of their
9991
- * private pending ops.
9992
- *
9993
- * Index ambiguity at boundaries is resolved by an inverse-of-forward
9994
- * convention: a position at or before a local insertion is reported as
9995
- * the position right before the insertion in #confirmed; a position past
9996
- * the insertion shifts left by the insertion's length. Positions inside
9997
- * an own-pending insertion collapse to the insertion point.
9998
- */
9999
- #encodeIndex(localIndex) {
10000
- let mapped = Math.max(0, Math.min(localIndex, this.length));
10001
- mapped = inverseMapTextIndexThroughOperations(mapped, this.#queuedOps);
10002
- mapped = inverseMapTextIndexThroughOperations(mapped, this.#inFlightOps);
10003
- return mapped;
10004
- }
10005
- /**
10006
- * Decode an `(index, fromVersion)` pair produced by
10007
- * {@link PrivateLiveTextApi.encodeIndex} — typically on a peer — into an
10008
- * offset in this LiveText's current local document (an index suitable for
10009
- * placing a CodeMirror marker, an annotation anchor, or anything else that
10010
- * lives over #segments).
10011
- *
10012
- * Composes the accepted ops applied since `fromVersion` (drawn from
10013
- * #acceptedOps in locally-applied form) with this client's own local
10014
- * pending ops, in that order. The result is in current #segments
10015
- * coordinates.
10016
- *
10017
- * Returns `null` when the position cannot be decoded against the current
10018
- * state:
10019
- * - `fromVersion` is greater than this LiveText's current version: the
10020
- * peer is ahead of us. The caller should park the message and retry
10021
- * after more accepted ops arrive.
10022
- * - `fromVersion` falls outside the retained accepted-ops history. This
10023
- * only happens after very long-lived disconnections; the caller can
10024
- * fall back to using the raw index and letting subsequent local
10025
- * transactions map it (with bounded drift).
10026
- */
10027
- #decodeIndex(index, fromVersion) {
10028
- if (fromVersion > this.#version) {
10029
- return null;
10030
- }
10031
- if (fromVersion < this.#version) {
10032
- const oldest = _optionalChain([this, 'access', _238 => _238.#acceptedOps, 'access', _239 => _239[0], 'optionalAccess', _240 => _240.version]);
10033
- if (oldest === void 0 || oldest > fromVersion + 1) {
10034
- return null;
10035
- }
10036
- }
10037
- let mapped = index;
10038
- for (const entry of this.#acceptedOps) {
10039
- if (entry.version <= fromVersion) continue;
10040
- if (entry.version > this.#version) break;
10041
- if (entry.ops.length === 0) continue;
10042
- mapped = mapTextIndexThroughOperations(mapped, entry.ops);
10043
- }
10044
- mapped = mapTextIndexThroughOperations(mapped, this.#inFlightOps);
10045
- mapped = mapTextIndexThroughOperations(mapped, this.#queuedOps);
10046
- return Math.max(0, Math.min(mapped, this.length));
10047
- }
10048
- /**
10049
- * Applies or removes inline attributes on a range of text.
10050
- *
10051
- * Set an attribute to `null` to remove it from the range.
10052
- *
10053
- * @example
10054
- * const text = new LiveText("Hello world");
10055
- * text.format(0, 5, { bold: true });
10056
- * text.format(0, 5, { bold: null });
10057
- */
10058
- format(index, length, attributes) {
10059
- const clipped = clipRangeToCodePointBoundaries(
10060
- this.toString(),
10061
- index,
10062
- length
10063
- );
10064
- if (clipped.length === 0) {
10065
- return;
10066
- }
10067
- this.#dispatch([
10068
- {
10069
- type: "format",
10070
- index: clipped.index,
10071
- length: clipped.length,
10072
- attributes
10073
- }
10074
- ]);
10075
- }
10076
- /** Local edits made through the public API. */
10077
- #dispatch(ops) {
10078
- if (ops.length === 0) {
10079
- return;
10080
- }
10081
- _optionalChain([this, 'access', _241 => _241._pool, 'optionalAccess', _242 => _242.assertStorageIsWritable, 'call', _243 => _243()]);
10082
- const attached = this._pool !== void 0 && this._id !== void 0;
10083
- const reverse = attached ? this.#invertOperations(ops) : [];
10084
- const changes = this.#applyOperationsLocally(ops);
10085
- if (!attached) {
10086
- return;
10087
- }
10088
- const pool = nn(this._pool);
10089
- const id = nn(this._id);
10090
- const updates = /* @__PURE__ */ new Map([
10091
- [
10092
- id,
10093
- {
10094
- type: "LiveText",
10095
- node: this,
10096
- version: this.#version,
10097
- updates: changes,
10098
- source: LOCAL_EDIT
10099
- }
10100
- ]
10101
- ]);
10102
- if (this.#inFlightOpId === void 0) {
10103
- const opId = pool.generateOpId();
10104
- this.#inFlightOpId = opId;
10105
- this.#inFlightOps = [...ops];
10106
- pool.dispatch(
10107
- [
10108
- {
10109
- type: OpCode.UPDATE_TEXT,
10110
- id,
10111
- opId,
10112
- baseVersion: this.#version,
10113
- ops: [...ops]
10114
- }
10115
- ],
10116
- reverse,
10117
- updates
10118
- );
10119
- } else {
10120
- this.#queuedOps.push(...ops);
10121
- pool.dispatch([], reverse, updates, { clearRedoStack: true });
10122
- }
10123
- }
10124
- /**
10125
- * A local replay of an existing wire op: an undo/redo frame, or an
10126
- * unacknowledged op re-sent after a reconnect.
10127
- */
10128
- #applyLocal(op, source) {
10129
- const mutableOp = op;
10130
- if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
10131
- this.#inFlightOps = [...this.#inFlightOps, ...this.#queuedOps];
10132
- this.#queuedOps = [];
10133
- mutableOp.baseVersion = this.#version;
10134
- mutableOp.ops = [...this.#inFlightOps];
10135
- return { modified: false };
10136
- }
10137
- let ops = op.ops;
10138
- for (const entry of this.#acceptedOps) {
10139
- if (entry.version > op.baseVersion && entry.ops.length > 0) {
10140
- ops = transformTextOperations(ops, entry.ops, "after");
10141
- }
10142
- }
10143
- const reverse = this.#invertOperations(ops);
10144
- const changes = this.#applyOperationsLocally(ops);
10145
- if (this.#inFlightOpId === void 0 && ops.length > 0) {
10146
- this.#inFlightOpId = nn(op.opId, "Local ops must have an opId");
10147
- this.#inFlightOps = [...ops];
10148
- mutableOp.baseVersion = this.#version;
10149
- mutableOp.ops = [...ops];
10150
- } else {
10151
- this.#queuedOps.push(...ops);
10152
- mutableOp.baseVersion = this.#version;
10153
- mutableOp.ops = [];
10154
- }
10155
- if (changes.length === 0) {
10156
- return { modified: false };
10157
- }
10158
- return {
10159
- reverse,
10160
- modified: {
10161
- type: "LiveText",
10162
- node: this,
10163
- version: this.#version,
10164
- updates: changes,
10165
- source
10166
- }
10167
- };
10168
- }
10169
- /** Server acknowledgement of our in-flight op. */
10170
- #applyAck(op, source) {
10171
- const ackedVersion = _nullishCoalesce(op.version, () => ( Math.max(this.#version, op.baseVersion + 1)));
10172
- const predicted = this.#inFlightOps;
10173
- const opId = this.#inFlightOpId;
10174
- this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
10175
- this.#inFlightOpId = void 0;
10176
- this.#inFlightOps = [];
10177
- let appliedOps = [];
10178
- let result = { modified: false };
10179
- if (!textOperationsEqual(op.ops, predicted)) {
10180
- error2(
10181
- "LiveText: acknowledgement did not match the local prediction; resynchronizing"
10182
- );
10183
- const rebuilt = this.#rebuildLocalFromConfirmed();
10184
- appliedOps = rebuilt.appliedOps;
10185
- if (rebuilt.changes.length > 0) {
10186
- result = {
10187
- reverse: [],
10188
- modified: {
10189
- type: "LiveText",
10190
- node: this,
10191
- version: ackedVersion,
10192
- updates: rebuilt.changes,
10193
- source
10194
- }
10195
- };
10196
- }
10197
- }
10198
- this.#version = Math.max(this.#version, ackedVersion);
10199
- this.#recordAccepted(ackedVersion, appliedOps, opId);
10200
- this.#flushQueued();
10201
- return result;
10202
- }
10203
- /** An accepted op from another client (or a server-fabricated fix op). */
10204
- #applyRemote(op, source) {
10205
- const version = _nullishCoalesce(op.version, () => ( this.#version + 1));
10206
- this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
10207
- const [overInFlight, inFlight] = transformTextOperationsX(
10208
- op.ops,
10209
- this.#inFlightOps,
10210
- "before"
10211
- );
10212
- const [applied, queued] = transformTextOperationsX(
10213
- overInFlight,
10214
- this.#queuedOps,
10215
- "before"
10216
- );
10217
- this.#inFlightOps = inFlight;
10218
- this.#queuedOps = queued;
10219
- this.#recordAccepted(version, applied, op.opId);
10220
- if (applied.length === 0) {
10221
- this.#version = Math.max(this.#version, version);
10222
- return { modified: false };
10223
- }
10224
- const reverse = this.#invertOperations(applied);
10225
- const changes = this.#applyOperationsLocally(applied);
10226
- this.#version = Math.max(this.#version, version);
10227
- return {
10228
- reverse,
10229
- modified: {
10230
- type: "LiveText",
10231
- node: this,
10232
- version: this.#version,
10233
- updates: changes,
10234
- source
10235
- }
10236
- };
10237
- }
10238
- /** Send the queued ops as the next in-flight op (after an ack). */
10239
- #flushQueued() {
10240
- if (this.#queuedOps.length === 0 || this._pool === void 0 || this._id === void 0) {
10241
- return;
10242
- }
10243
- const opId = this._pool.generateOpId();
10244
- this.#inFlightOpId = opId;
10245
- this.#inFlightOps = this.#queuedOps;
10246
- this.#queuedOps = [];
10247
- this._pool.dispatch(
10248
- [
10249
- {
10250
- type: OpCode.UPDATE_TEXT,
10251
- id: this._id,
10252
- opId,
10253
- baseVersion: this.#version,
10254
- ops: [...this.#inFlightOps]
10255
- }
10256
- ],
10257
- [],
10258
- /* @__PURE__ */ new Map(),
10259
- // The local content was already applied (and made undoable) when the
10260
- // edits happened; this is purely an outbound flush.
10261
- { clearRedoStack: false }
10262
- );
10263
- }
10264
- /**
10265
- * Rebuild the local document as confirmed ⊕ queued ops, returning the
10266
- * coarse delta that was applied. Only used by defensive recovery paths.
10267
- */
10268
- #rebuildLocalFromConfirmed() {
10269
- const before2 = this.#segments;
10270
- const after2 = applyTextOperationsToSegments(this.#confirmed, [
10271
- ...this.#inFlightOps,
10272
- ...this.#queuedOps
10273
- ]);
10274
- if (stableStringify(segmentsToData(before2)) === stableStringify(segmentsToData(after2))) {
10275
- this.#segments = after2;
10276
- return { appliedOps: [], changes: [] };
10277
- }
10278
- const beforeText = before2.map((segment) => segment.text).join("");
10279
- this.#segments = after2;
10280
- this.invalidate();
10281
- const appliedOps = [];
10282
- const changes = [];
10283
- if (beforeText.length > 0) {
10284
- appliedOps.push({ type: "delete", index: 0, length: beforeText.length });
10285
- changes.push({
10286
- type: "delete",
10287
- index: 0,
10288
- length: beforeText.length,
10289
- deletedText: beforeText
10290
- });
10291
- }
10292
- let index = 0;
10293
- for (const segment of after2) {
10294
- appliedOps.push({
10295
- type: "insert",
10296
- index,
10297
- text: segment.text,
10298
- attributes: segment.attributes
10299
- });
10300
- changes.push({
10301
- type: "insert",
10302
- index,
10303
- text: segment.text,
10304
- attributes: segment.attributes
10305
- });
10306
- index += segment.text.length;
10307
- }
10308
- return { appliedOps, changes };
10309
- }
10310
- /**
10311
- * Reconcile this node against an authoritative storage snapshot (e.g.
10312
- * after a reconnect). The confirmed state and version are replaced by the
10313
- * snapshot's; pending (in-flight + queued) ops are preserved on top and
10314
- * will be re-sent by the offline-ops replay.
10315
- *
10316
- * @internal
10317
- */
10318
- _resyncText(data, version, source) {
10319
- this.#confirmed = dataToSegments(data);
10320
- this.#version = version;
10321
- this.#acceptedOps = [];
10322
- const rebuilt = this.#rebuildLocalFromConfirmed();
10323
- if (rebuilt.changes.length === 0) {
10324
- return void 0;
10325
- }
10326
- return {
10327
- type: "LiveText",
10328
- node: this,
10329
- version: this.#version,
10330
- updates: rebuilt.changes,
10331
- source
10332
- };
10333
- }
10334
- /**
10335
- * Called when the server rejected one of our ops. Drops all pending state
10336
- * for this node (edits queued behind a rejected op cannot be trusted
10337
- * either); the room follows up with a storage resync.
10338
- *
10339
- * @internal
10340
- */
10341
- _rejectPendingOp(opId) {
10342
- if (opId !== this.#inFlightOpId) {
10343
- return;
10344
- }
10345
- this.#inFlightOpId = void 0;
10346
- this.#inFlightOps = [];
10347
- this.#queuedOps = [];
10348
- }
10349
- #recordAccepted(version, ops, opId) {
10350
- if (this.#acceptedOps.some((entry) => entry.version === version)) {
10351
- return;
10352
- }
10353
- this.#acceptedOps.push({ version, opId, ops: [...ops] });
10354
- this.#acceptedOps.sort((left, right) => left.version - right.version);
10355
- if (this.#acceptedOps.length > ACCEPTED_OPS_HISTORY_LIMIT) {
10356
- this.#acceptedOps.splice(
10357
- 0,
10358
- this.#acceptedOps.length - ACCEPTED_OPS_HISTORY_LIMIT
10359
- );
10360
- }
10361
- }
10362
- #applyOperationsLocally(ops) {
10363
- const changes = [];
10364
- for (const op of ops) {
10365
- if (op.type === "insert") {
10366
- this.#segments = applyInsert(
10367
- this.#segments,
10368
- op.index,
10369
- op.text,
10370
- op.attributes
10371
- );
10372
- changes.push({
10373
- type: "insert",
10374
- index: op.index,
10375
- text: op.text,
10376
- attributes: op.attributes
10377
- });
10378
- } else if (op.type === "delete") {
10379
- const result = applyDelete(this.#segments, op.index, op.length);
10380
- this.#segments = result.segments;
10381
- changes.push({
10382
- type: "delete",
10383
- index: op.index,
10384
- length: op.length,
10385
- deletedText: result.deletedText
10386
- });
10387
- } else {
10388
- this.#segments = applyFormat(
10389
- this.#segments,
10390
- op.index,
10391
- op.length,
10392
- op.attributes
10393
- );
10394
- changes.push({
10395
- type: "format",
10396
- index: op.index,
10397
- length: op.length,
10398
- attributes: op.attributes
10399
- });
10400
- }
10401
- }
10402
- this.invalidate();
10403
- return changes;
10404
- }
10405
- #invertOperations(ops) {
10406
- return [
10407
- {
10408
- type: OpCode.UPDATE_TEXT,
10409
- id: nn(this._id),
10410
- baseVersion: this.#version,
10411
- ops: invertTextOperations(this.#segments, ops)
10412
- }
10413
- ];
10414
- }
10415
- /** Returns the plain text content without attributes. Equivalent to joining the text from each segment in {@link LiveText.toJSON}. */
10416
- toString() {
10417
- return this.#segments.map((segment) => segment.text).join("");
10418
- }
10419
- /**
10420
- * Returns a JSON-compatible snapshot of the document as a {@link LiveTextData}
10421
- * array.
10422
- *
10423
- * @example
10424
- * new LiveText([["Hello ", { bold: true }], ["world"]]).toJSON();
10425
- * // [["Hello ", { bold: true }], ["world"]]
10426
- */
10427
- toJSON() {
10428
- return super.toJSON();
10429
- }
10430
- /** @internal */
10431
- _toJSON() {
10432
- return segmentsToData(this.#segments);
10433
- }
10434
- /** @internal */
10435
- toTreeNode(key) {
10436
- return super.toTreeNode(key);
10437
- }
10438
- /** @internal */
10439
- _toTreeNode(key) {
10440
- const nodeId = _nullishCoalesce(this._id, () => ( nanoid()));
10441
- const payload = this.toJSON().map(
10442
- (segment, index) => ({
10443
- type: "Json",
10444
- id: `${nodeId}:${index}`,
10445
- key: String(index),
10446
- payload: segment
10447
- })
10448
- );
10449
- payload.push({
10450
- type: "Json",
10451
- id: `${nodeId}:version`,
10452
- key: "version",
10453
- payload: this.version
10454
- });
10455
- return {
10456
- type: "LiveText",
10457
- id: nodeId,
10458
- key,
10459
- payload
10460
- };
10461
- }
10462
- clone() {
10463
- return new _LiveText(this.toJSON(), this.#version);
10464
- }
10465
- };
10466
-
10467
- // src/crdts/liveblocks-helpers.ts
10468
- function creationOpToLiveNode(op) {
10469
- return lsonToLiveNode(creationOpToLson(op));
10470
- }
10471
- function creationOpToLson(op) {
10472
- switch (op.type) {
10473
- case OpCode.CREATE_FILE:
10474
- return new LiveFile(op.data);
10475
- case OpCode.CREATE_REGISTER:
10476
- return op.data;
10477
- case OpCode.CREATE_OBJECT:
10478
- return new LiveObject(op.data);
10479
- case OpCode.CREATE_MAP:
10480
- return new LiveMap();
10481
- case OpCode.CREATE_LIST:
10482
- return new LiveList([]);
10483
- case OpCode.CREATE_TEXT:
10484
- return new LiveText(op.data, op.version);
10485
- default:
10486
- return assertNever(op, "Unknown creation Op");
10487
- }
10488
- }
10489
- function isSameNodeOrChildOf(node, parent) {
10490
- if (node === parent) {
10491
- return true;
10492
- }
10493
- if (node.parent.type === "HasParent") {
10494
- return isSameNodeOrChildOf(node.parent.node, parent);
10495
- }
10496
- return false;
10497
- }
10498
- function liveObjectFromNodeStream(nodes) {
10499
- const pool = createManagedPool({
10500
- getCurrentConnectionId: () => {
10501
- throw new Error(
10502
- "Cannot mutate a historic storage version: it is a read-only snapshot"
10503
- );
10504
- }
10505
- });
10506
- return LiveObject._fromItems(nodes, pool);
10507
- }
10508
- function deserialize(node, parentToChildren, pool) {
10509
- if (isObjectStorageNode(node)) {
10510
- return LiveObject._deserialize(node, parentToChildren, pool);
10511
- } else if (isListStorageNode(node)) {
10512
- return LiveList._deserialize(node, parentToChildren, pool);
10513
- } else if (isMapStorageNode(node)) {
10514
- return LiveMap._deserialize(node, parentToChildren, pool);
10515
- } else if (isRegisterStorageNode(node)) {
10516
- return LiveRegister._deserialize(node, parentToChildren, pool);
10517
- } else if (isTextStorageNode(node)) {
10518
- return LiveText._deserialize(node, parentToChildren, pool);
10519
- } else if (isFileStorageNode(node)) {
10520
- return LiveFile._deserialize(node, parentToChildren, pool);
10521
- } else {
10522
- throw new Error("Unexpected CRDT type");
10523
- }
10524
- }
10525
- function deserializeToLson(node, parentToChildren, pool) {
10526
- if (isObjectStorageNode(node)) {
10527
- return LiveObject._deserialize(node, parentToChildren, pool);
10528
- } else if (isListStorageNode(node)) {
10529
- return LiveList._deserialize(node, parentToChildren, pool);
10530
- } else if (isMapStorageNode(node)) {
10531
- return LiveMap._deserialize(node, parentToChildren, pool);
10532
- } else if (isRegisterStorageNode(node)) {
10533
- return node[1].data;
10534
- } else if (isTextStorageNode(node)) {
10535
- return LiveText._deserialize(node, parentToChildren, pool);
10536
- } else if (isFileStorageNode(node)) {
10537
- return LiveFile._deserialize(node, parentToChildren, pool);
10538
- } else {
10539
- throw new Error("Unexpected CRDT type");
10540
- }
10541
- }
10542
- function isLiveStructure(value) {
10543
- return isLiveList(value) || isLiveMap(value) || isLiveObject(value) || isLiveText(value) || isLiveFile(value);
10544
- }
10545
- function isLiveNode(value) {
10546
- return isLiveStructure(value) || isLiveRegister(value);
10547
- }
10548
- function isLiveList(value) {
10549
- return value instanceof LiveList;
10550
- }
10551
- function isLiveMap(value) {
10552
- return value instanceof LiveMap;
10553
- }
10554
- function isLiveObject(value) {
10555
- return value instanceof LiveObject;
10556
- }
10557
- function isLiveText(value) {
10558
- return value instanceof LiveText;
10559
- }
10560
- function isLiveFile(value) {
10561
- return value instanceof LiveFile;
10562
- }
10563
- function isLiveRegister(value) {
10564
- return value instanceof LiveRegister;
10565
- }
10566
- function cloneLson(value) {
10567
- return value === void 0 ? void 0 : isLiveStructure(value) ? value.clone() : deepClone(value);
10568
- }
10569
- function liveNodeToLson(obj) {
10570
- if (obj instanceof LiveRegister) {
10571
- return obj.data;
10572
- } else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject || obj instanceof LiveText || obj instanceof LiveFile) {
10573
- return obj;
10574
- } else {
10575
- return assertNever(obj, "Unknown AbstractCrdt");
10576
- }
10577
- }
10578
- function lsonToLiveNode(value) {
10579
- if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList || value instanceof LiveText || value instanceof LiveFile) {
10580
- return value;
10581
- } else {
10582
- return new LiveRegister(value);
10583
- }
10584
- }
10585
- function dumpPool(pool) {
10586
- const rows = Array.from(pool.nodes.values(), (node) => {
10587
- const parent = node.parent;
10588
- const parentId = parent.type === "HasParent" ? _nullishCoalesce(parent.node._id, () => ( "?")) : parent.type === "Orphaned" ? "<orphaned>" : "-";
10589
- let value;
10590
- if (node instanceof LiveRegister) {
10591
- value = stringifyOrLog(node.data);
10592
- } else if (node instanceof LiveList) {
10593
- value = "<LiveList>";
10594
- } else if (node instanceof LiveMap) {
10595
- value = "<LiveMap>";
10596
- } else if (node instanceof LiveFile) {
10597
- value = stringifyOrLog(node.data);
10598
- } else {
10599
- value = "<LiveObject>";
10600
- }
10601
- return { id: nn(node._id), parentId, key: _nullishCoalesce(node._parentKey, () => ( "")), value };
10602
- });
10603
- rows.sort((a, b) => {
10604
- if (a.parentId !== b.parentId) return a.parentId < b.parentId ? -1 : 1;
10605
- if (a.key !== b.key) return a.key < b.key ? -1 : 1;
10606
- return 0;
10607
- });
10608
- return rows.map(
10609
- (r) => ` ${r.id} parent=${r.parentId} key=${r.key || "\u2014"} ${r.value}`
10610
- ).join("\n");
10611
- }
10612
- function isJsonEq(a, b) {
10613
- if (a === b) {
10614
- return true;
10615
- }
10616
- if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
10617
- return false;
10618
- }
10619
- if (Array.isArray(a) || Array.isArray(b)) {
10620
- if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
10621
- return false;
10622
- }
10623
- for (let i = 0; i < a.length; i++) {
10624
- if (!isJsonEq(a[i], b[i])) {
10625
- return false;
10626
- }
10627
- }
10628
- return true;
10629
- }
10630
- const aKeys = Object.keys(a);
10631
- if (aKeys.length !== Object.keys(b).length) {
10632
- return false;
10633
- }
10634
- for (const key of aKeys) {
10635
- if (!isJsonEq(a[key], b[key])) {
10636
- return false;
10637
- }
10638
- }
10639
- return true;
10640
- }
10641
- function liveTextDataToReplaceOps(before2, after2) {
10642
- const ops = [];
10643
- const beforeLength = before2.reduce(
10644
- (length, [text]) => length + text.length,
10645
- 0
10646
- );
10647
- if (beforeLength > 0) {
10648
- ops.push({ type: "delete", index: 0, length: beforeLength });
10649
- }
10650
- let index = 0;
10651
- for (const [text, attributes] of after2) {
10652
- if (text.length === 0) {
10653
- continue;
10654
- }
10655
- ops.push({ type: "insert", index, text, attributes });
10656
- index += text.length;
10657
- }
10658
- return ops;
10659
- }
10660
- function diffNodeMap(prev, next, options) {
9347
+ function diffNodeMap(prev, next) {
10661
9348
  const ops = [];
10662
9349
  const idsToRecreate = /* @__PURE__ */ new Set();
10663
9350
  next.forEach((nextCrdt, id) => {
@@ -10749,16 +9436,6 @@ function diffNodeMap(prev, next, options) {
10749
9436
  parentKey: crdt.parentKey
10750
9437
  });
10751
9438
  break;
10752
- case CrdtType.TEXT:
10753
- ops.push({
10754
- type: OpCode.CREATE_TEXT,
10755
- id,
10756
- parentId: crdt.parentId,
10757
- parentKey: crdt.parentKey,
10758
- data: crdt.data,
10759
- version: crdt.version
10760
- });
10761
- break;
10762
9439
  }
10763
9440
  }
10764
9441
  next.forEach((crdt, id) => {
@@ -10785,17 +9462,6 @@ function diffNodeMap(prev, next, options) {
10785
9462
  }
10786
9463
  }
10787
9464
  }
10788
- if (_optionalChain([options, 'optionalAccess', _244 => _244.includeLiveTextUpdates]) === true && crdt.type === CrdtType.TEXT && currentCrdt.type === CrdtType.TEXT && !isJsonEq(crdt.data, currentCrdt.data)) {
10789
- ops.push({
10790
- type: OpCode.UPDATE_TEXT,
10791
- id,
10792
- // A restore is a new edit in the current timeline. The version from
10793
- // the historic snapshot describes its old timeline and must not move
10794
- // this node's current version backwards.
10795
- baseVersion: currentCrdt.version,
10796
- ops: liveTextDataToReplaceOps(currentCrdt.data, crdt.data)
10797
- });
10798
- }
10799
9465
  if (crdt.parentKey !== currentCrdt.parentKey) {
10800
9466
  ops.push({
10801
9467
  type: OpCode.SET_PARENT_KEY,
@@ -10836,36 +9502,19 @@ function mergeListStorageUpdates(first, second) {
10836
9502
  updates: updates.concat(second.updates)
10837
9503
  };
10838
9504
  }
10839
- function mergeTextStorageUpdates(first, second) {
10840
- return {
10841
- ...second,
10842
- updates: first.updates.concat(second.updates)
10843
- };
10844
- }
10845
- function mergeUpdateSources(first, second) {
10846
- if (first.origin === "remote" || second.origin === "remote") {
10847
- return REMOTE;
10848
- }
10849
- if (second.via !== "edit") return second;
10850
- if (first.via !== "edit") return first;
10851
- return LOCAL_EDIT;
10852
- }
10853
9505
  function mergeStorageUpdates(first, second) {
10854
9506
  if (first === void 0) {
10855
9507
  return second;
10856
9508
  }
10857
- const source = mergeUpdateSources(first.source, second.source);
10858
9509
  if (first.type === "LiveObject" && second.type === "LiveObject") {
10859
- return { ...mergeObjectStorageUpdates(first, second), source };
9510
+ return mergeObjectStorageUpdates(first, second);
10860
9511
  } else if (first.type === "LiveMap" && second.type === "LiveMap") {
10861
- return { ...mergeMapStorageUpdates(first, second), source };
9512
+ return mergeMapStorageUpdates(first, second);
10862
9513
  } else if (first.type === "LiveList" && second.type === "LiveList") {
10863
- return { ...mergeListStorageUpdates(first, second), source };
10864
- } else if (first.type === "LiveText" && second.type === "LiveText") {
10865
- return { ...mergeTextStorageUpdates(first, second), source };
9514
+ return mergeListStorageUpdates(first, second);
10866
9515
  } else {
10867
- return { ...second, source };
10868
9516
  }
9517
+ return second;
10869
9518
  }
10870
9519
 
10871
9520
  // src/devtools/bridge.ts
@@ -10881,7 +9530,7 @@ function sendToPanel(message, options) {
10881
9530
  ...message,
10882
9531
  source: "liveblocks-devtools-client"
10883
9532
  };
10884
- if (!(_optionalChain([options, 'optionalAccess', _245 => _245.force]) || _bridgeActive)) {
9533
+ if (!(_optionalChain([options, 'optionalAccess', _238 => _238.force]) || _bridgeActive)) {
10885
9534
  return;
10886
9535
  }
10887
9536
  window.postMessage(fullMsg, "*");
@@ -10889,7 +9538,7 @@ function sendToPanel(message, options) {
10889
9538
  var eventSource = makeEventSource();
10890
9539
  if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
10891
9540
  window.addEventListener("message", (event) => {
10892
- 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") {
10893
9542
  eventSource.notify(event.data);
10894
9543
  } else {
10895
9544
  }
@@ -11031,7 +9680,7 @@ function fullSync(room) {
11031
9680
  msg: "room::sync::full",
11032
9681
  roomId: room.id,
11033
9682
  status: room.getStatus(),
11034
- 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)),
11035
9684
  me,
11036
9685
  others
11037
9686
  });
@@ -11718,15 +10367,15 @@ function installBackgroundTabSpy() {
11718
10367
  const doc = typeof document !== "undefined" ? document : void 0;
11719
10368
  const inBackgroundSince = { current: null };
11720
10369
  function onVisibilityChange() {
11721
- if (_optionalChain([doc, 'optionalAccess', _251 => _251.visibilityState]) === "hidden") {
10370
+ if (_optionalChain([doc, 'optionalAccess', _244 => _244.visibilityState]) === "hidden") {
11722
10371
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
11723
10372
  } else {
11724
10373
  inBackgroundSince.current = null;
11725
10374
  }
11726
10375
  }
11727
- _optionalChain([doc, 'optionalAccess', _252 => _252.addEventListener, 'call', _253 => _253("visibilitychange", onVisibilityChange)]);
10376
+ _optionalChain([doc, 'optionalAccess', _245 => _245.addEventListener, 'call', _246 => _246("visibilitychange", onVisibilityChange)]);
11728
10377
  const unsub = () => {
11729
- _optionalChain([doc, 'optionalAccess', _254 => _254.removeEventListener, 'call', _255 => _255("visibilitychange", onVisibilityChange)]);
10378
+ _optionalChain([doc, 'optionalAccess', _247 => _247.removeEventListener, 'call', _248 => _248("visibilitychange", onVisibilityChange)]);
11730
10379
  };
11731
10380
  return [inBackgroundSince, unsub];
11732
10381
  }
@@ -11750,7 +10399,7 @@ function makeNodeMapBuffer() {
11750
10399
  function topLevelKeysOf(nodes) {
11751
10400
  const keys2 = /* @__PURE__ */ new Set();
11752
10401
  const root = nodes.get("root");
11753
- for (const key in _optionalChain([root, 'optionalAccess', _256 => _256.data])) {
10402
+ for (const key in _optionalChain([root, 'optionalAccess', _249 => _249.data])) {
11754
10403
  keys2.add(key);
11755
10404
  }
11756
10405
  for (const node of nodes.values()) {
@@ -11822,8 +10471,6 @@ function createRoom(options, config) {
11822
10471
  activeBatch: null,
11823
10472
  unacknowledgedOps
11824
10473
  };
11825
- let nextHistoryItemId = 0;
11826
- let historyDisabled = 0;
11827
10474
  const nodeMapBuffer = makeNodeMapBuffer();
11828
10475
  const stopwatch = config.enableDebugLogging ? makeStopWatch() : void 0;
11829
10476
  let lastTokenKey;
@@ -11908,7 +10555,7 @@ function createRoom(options, config) {
11908
10555
  }
11909
10556
  }
11910
10557
  });
11911
- function onDispatch(ops, reverse, storageUpdates, options2) {
10558
+ function onDispatch(ops, reverse, storageUpdates) {
11912
10559
  if (context.activeBatch) {
11913
10560
  for (const op of ops) {
11914
10561
  context.activeBatch.ops.push(op);
@@ -11923,24 +10570,19 @@ function createRoom(options, config) {
11923
10570
  );
11924
10571
  }
11925
10572
  context.activeBatch.reverseOps.pushLeft(reverse);
11926
- if (_optionalChain([options2, 'optionalAccess', _257 => _257.clearRedoStack])) {
11927
- context.activeBatch.clearRedoStack = true;
11928
- }
11929
10573
  } else {
11930
10574
  if (reverse.length > 0) {
11931
10575
  addToUndoStack(reverse);
11932
10576
  }
11933
- if (_nullishCoalesce(_optionalChain([options2, 'optionalAccess', _258 => _258.clearRedoStack]), () => ( ops.length > 0))) {
11934
- clearRedoStack();
11935
- }
11936
10577
  if (ops.length > 0) {
10578
+ context.redoStack.length = 0;
11937
10579
  dispatchOps(ops);
11938
10580
  }
11939
10581
  notify({ storageUpdates });
11940
10582
  }
11941
10583
  }
11942
10584
  function isStorageWritable() {
11943
- 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]);
11944
10586
  return permissionMatrix !== void 0 ? hasPermissionAccess(permissionMatrix, "storage", "write") : true;
11945
10587
  }
11946
10588
  const eventHub = {
@@ -11953,7 +10595,6 @@ function createRoom(options, config) {
11953
10595
  others: makeEventSource(),
11954
10596
  storageBatch: makeEventSource(),
11955
10597
  history: makeEventSource(),
11956
- privateHistory: makeEventSource(),
11957
10598
  storageDidLoad: makeEventSource(),
11958
10599
  storageStatus: makeEventSource(),
11959
10600
  ydoc: makeEventSource(),
@@ -12041,12 +10682,12 @@ function createRoom(options, config) {
12041
10682
  self,
12042
10683
  (me) => me !== null ? userToTreeNode("Me", me) : null
12043
10684
  );
12044
- function diffCurrentStorageAgainst(target, options2) {
10685
+ function diffCurrentStorageAgainst(target) {
12045
10686
  const current = /* @__PURE__ */ new Map();
12046
10687
  for (const [id, crdt] of context.pool.nodes) {
12047
10688
  current.set(id, crdt._serialize());
12048
10689
  }
12049
- return diffNodeMap(current, target, options2);
10690
+ return diffNodeMap(current, target);
12050
10691
  }
12051
10692
  function createOrUpdateRootFromMessage(nodes) {
12052
10693
  if (nodes.size === 0) {
@@ -12054,23 +10695,6 @@ function createRoom(options, config) {
12054
10695
  }
12055
10696
  if (context.root !== void 0) {
12056
10697
  const result = applyRemoteOps(diffCurrentStorageAgainst(nodes));
12057
- for (const [id, crdt] of nodes) {
12058
- if (crdt.type === CrdtType.TEXT) {
12059
- const node = context.pool.nodes.get(id);
12060
- if (node !== void 0 && isLiveText(node)) {
12061
- const update = node._resyncText(crdt.data, crdt.version, REMOTE);
12062
- if (update !== void 0) {
12063
- result.updates.storageUpdates.set(
12064
- id,
12065
- mergeStorageUpdates(
12066
- result.updates.storageUpdates.get(id),
12067
- update
12068
- )
12069
- );
12070
- }
12071
- }
12072
- }
12073
- }
12074
10698
  notify(result.updates);
12075
10699
  } else {
12076
10700
  context.root = LiveObject._fromItems(
@@ -12078,7 +10702,7 @@ function createRoom(options, config) {
12078
10702
  context.pool
12079
10703
  );
12080
10704
  }
12081
- 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));
12082
10706
  const serverTopLevelKeys = topLevelKeysOf(nodes);
12083
10707
  const root = context.root;
12084
10708
  disableHistory(() => {
@@ -12095,23 +10719,12 @@ function createRoom(options, config) {
12095
10719
  }
12096
10720
  });
12097
10721
  }
12098
- function notifyPrivateHistory(event) {
12099
- if (historyDisabled > 0) return;
12100
- eventHub.privateHistory.notify(event);
12101
- }
12102
- function clearRedoStack() {
12103
- if (context.redoStack.length === 0) return;
12104
- const ids = context.redoStack.map((item) => item.id);
12105
- context.redoStack.length = 0;
12106
- notifyPrivateHistory({ action: "discard", ids });
12107
- }
12108
10722
  function reconcileStorageWithNodes(nodes) {
12109
10723
  if (context.root === void 0) {
12110
10724
  throw new Error("Cannot reconcile storage before it is loaded");
12111
10725
  }
12112
10726
  const ops = diffCurrentStorageAgainst(
12113
- new Map(nodes),
12114
- { includeLiveTextUpdates: true }
10727
+ new Map(nodes)
12115
10728
  );
12116
10729
  if (ops.length === 0) {
12117
10730
  return;
@@ -12130,14 +10743,9 @@ function createRoom(options, config) {
12130
10743
  }
12131
10744
  function _addToRealUndoStack(frames) {
12132
10745
  if (context.undoStack.length >= 50) {
12133
- const evicted = context.undoStack.shift();
12134
- if (evicted !== void 0) {
12135
- notifyPrivateHistory({ action: "discard", ids: [evicted.id] });
12136
- }
10746
+ context.undoStack.shift();
12137
10747
  }
12138
- const id = nextHistoryItemId++;
12139
- context.undoStack.push({ id, frames });
12140
- notifyPrivateHistory({ action: "push", id });
10748
+ context.undoStack.push(frames);
12141
10749
  onHistoryChange();
12142
10750
  }
12143
10751
  function addToUndoStack(frames) {
@@ -12161,10 +10769,7 @@ function createRoom(options, config) {
12161
10769
  eventHub.myPresence.notify(context.myPresence.get());
12162
10770
  }
12163
10771
  if (storageUpdates !== void 0 && storageUpdates.size > 0) {
12164
- const updates2 = Array.from(storageUpdates.values(), (update) => ({
12165
- ...update,
12166
- source: toUpdateSource(update.source)
12167
- }));
10772
+ const updates2 = Array.from(storageUpdates.values());
12168
10773
  eventHub.storageBatch.notify(updates2);
12169
10774
  }
12170
10775
  notifyStorageStatus();
@@ -12178,69 +10783,19 @@ function createRoom(options, config) {
12178
10783
  "Internal. Tried to get connection id but connection was never open"
12179
10784
  );
12180
10785
  }
12181
- const viaByOpId = /* @__PURE__ */ new Map();
12182
- function viaOfAckedOp(opId) {
12183
- const via = viaByOpId.get(opId);
12184
- if (via === void 0) {
12185
- return "edit";
12186
- }
12187
- viaByOpId.delete(opId);
12188
- return via;
12189
- }
12190
- function applyLocalOps(frames, localSource = LOCAL_EDIT) {
10786
+ function applyLocalOps(frames) {
12191
10787
  const [pframes, ops] = partition(
12192
10788
  frames,
12193
10789
  (f) => f.type === "presence"
12194
10790
  );
12195
- const restoredTextIds = /* @__PURE__ */ new Map();
12196
- for (const op of ops) {
12197
- if (op.type === OpCode.CREATE_TEXT && op.opId === void 0 && context.pool.nodes.get(op.id) === void 0 && !restoredTextIds.has(op.id)) {
12198
- restoredTextIds.set(op.id, context.pool.generateId());
12199
- }
12200
- }
12201
- const remappedOps = restoredTextIds.size === 0 ? ops : ops.map((op) => {
12202
- if (op.opId !== void 0) {
12203
- return op;
12204
- }
12205
- const id = restoredTextIds.get(op.id);
12206
- if (isCreateOp(op)) {
12207
- const parentId = restoredTextIds.get(op.parentId);
12208
- const deletedId = op.deletedId === void 0 ? void 0 : restoredTextIds.get(op.deletedId);
12209
- if (id === void 0 && parentId === void 0 && deletedId === void 0) {
12210
- return op;
12211
- }
12212
- if (op.type === OpCode.CREATE_TEXT && id !== void 0) {
12213
- return {
12214
- ...op,
12215
- id,
12216
- version: 0,
12217
- ...parentId === void 0 ? {} : { parentId },
12218
- ...deletedId === void 0 ? {} : { deletedId }
12219
- };
12220
- }
12221
- return {
12222
- ...op,
12223
- ...id === void 0 ? {} : { id },
12224
- ...parentId === void 0 ? {} : { parentId },
12225
- ...deletedId === void 0 ? {} : { deletedId }
12226
- };
12227
- }
12228
- return id === void 0 ? op : { ...op, id };
12229
- });
12230
- const opsWithOpIds = remappedOps.map(
10791
+ const opsWithOpIds = ops.map(
12231
10792
  (op) => op.opId === void 0 ? { ...op, opId: context.pool.generateOpId() } : op
12232
10793
  );
12233
- if (localSource.via !== "edit") {
12234
- for (const op of opsWithOpIds) {
12235
- viaByOpId.set(op.opId, localSource.via);
12236
- }
12237
- }
12238
10794
  const { reverse, updates } = applyOps(
12239
10795
  pframes,
12240
10796
  opsWithOpIds,
12241
10797
  /* isLocal */
12242
- true,
12243
- localSource
10798
+ true
12244
10799
  );
12245
10800
  return { opsToEmit: opsWithOpIds, reverse, updates };
12246
10801
  }
@@ -12252,7 +10807,7 @@ function createRoom(options, config) {
12252
10807
  false
12253
10808
  );
12254
10809
  }
12255
- function applyOps(pframes, ops, isLocal, localSource = LOCAL_EDIT) {
10810
+ function applyOps(pframes, ops, isLocal) {
12256
10811
  const output = {
12257
10812
  reverse: new Deque(),
12258
10813
  storageUpdates: /* @__PURE__ */ new Map(),
@@ -12281,16 +10836,12 @@ function createRoom(options, config) {
12281
10836
  for (const op of ops) {
12282
10837
  let source;
12283
10838
  if (isLocal) {
12284
- source = { ...localSource, optimistic: true };
10839
+ source = 0 /* LOCAL */;
12285
10840
  } else if (op.opId !== void 0) {
12286
10841
  context.unacknowledgedOps.delete(op.opId);
12287
- source = {
12288
- origin: "local",
12289
- via: viaOfAckedOp(op.opId),
12290
- optimistic: false
12291
- };
10842
+ source = 2 /* OURS */;
12292
10843
  } else {
12293
- source = REMOTE;
10844
+ source = 1 /* THEIRS */;
12294
10845
  }
12295
10846
  const applyOpResult = applyOp(op, source);
12296
10847
  if (applyOpResult.modified) {
@@ -12305,7 +10856,7 @@ function createRoom(options, config) {
12305
10856
  );
12306
10857
  output.reverse.pushLeft(applyOpResult.reverse);
12307
10858
  }
12308
- 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) {
12309
10860
  createdNodeIds.add(op.id);
12310
10861
  }
12311
10862
  }
@@ -12325,13 +10876,12 @@ function createRoom(options, config) {
12325
10876
  switch (op.type) {
12326
10877
  case OpCode.DELETE_OBJECT_KEY:
12327
10878
  case OpCode.UPDATE_OBJECT:
12328
- case OpCode.UPDATE_TEXT:
12329
10879
  case OpCode.DELETE_CRDT: {
12330
10880
  const node = context.pool.nodes.get(op.id);
12331
10881
  if (node === void 0) {
12332
10882
  return { modified: false };
12333
10883
  }
12334
- return node._apply(op, source);
10884
+ return node._apply(op, source === 0 /* LOCAL */);
12335
10885
  }
12336
10886
  case OpCode.SET_PARENT_KEY: {
12337
10887
  const node = context.pool.nodes.get(op.id);
@@ -12350,7 +10900,6 @@ function createRoom(options, config) {
12350
10900
  case OpCode.CREATE_OBJECT:
12351
10901
  case OpCode.CREATE_LIST:
12352
10902
  case OpCode.CREATE_MAP:
12353
- case OpCode.CREATE_TEXT:
12354
10903
  case OpCode.CREATE_FILE:
12355
10904
  case OpCode.CREATE_REGISTER: {
12356
10905
  if (op.parentId === void 0) {
@@ -12386,7 +10935,7 @@ function createRoom(options, config) {
12386
10935
  }
12387
10936
  context.myPresence.patch(patch);
12388
10937
  if (context.activeBatch) {
12389
- if (_optionalChain([options2, 'optionalAccess', _266 => _266.addToHistory])) {
10938
+ if (_optionalChain([options2, 'optionalAccess', _257 => _257.addToHistory])) {
12390
10939
  context.activeBatch.reverseOps.pushLeft({
12391
10940
  type: "presence",
12392
10941
  data: oldValues
@@ -12395,7 +10944,7 @@ function createRoom(options, config) {
12395
10944
  context.activeBatch.updates.presence = true;
12396
10945
  } else {
12397
10946
  flushNowOrSoon();
12398
- if (_optionalChain([options2, 'optionalAccess', _267 => _267.addToHistory])) {
10947
+ if (_optionalChain([options2, 'optionalAccess', _258 => _258.addToHistory])) {
12399
10948
  addToUndoStack([{ type: "presence", data: oldValues }]);
12400
10949
  }
12401
10950
  notify({ presence: true });
@@ -12574,11 +11123,11 @@ function createRoom(options, config) {
12574
11123
  break;
12575
11124
  }
12576
11125
  case ServerMsgCode.STORAGE_CHUNK:
12577
- _optionalChain([stopwatch, 'optionalAccess', _268 => _268.lap, 'call', _269 => _269()]);
11126
+ _optionalChain([stopwatch, 'optionalAccess', _259 => _259.lap, 'call', _260 => _260()]);
12578
11127
  nodeMapBuffer.append(compactNodesToNodeStream(message.nodes));
12579
11128
  break;
12580
11129
  case ServerMsgCode.STORAGE_STREAM_END: {
12581
- const timing = _optionalChain([stopwatch, 'optionalAccess', _270 => _270.stop, 'call', _271 => _271()]);
11130
+ const timing = _optionalChain([stopwatch, 'optionalAccess', _261 => _261.stop, 'call', _262 => _262()]);
12582
11131
  if (timing) {
12583
11132
  const ms = (v) => `${v.toFixed(1)}ms`;
12584
11133
  const rest = timing.laps.slice(1);
@@ -12605,38 +11154,16 @@ function createRoom(options, config) {
12605
11154
  }
12606
11155
  break;
12607
11156
  }
12608
- // Receiving a RejectedOps message means the server refused some of
12609
- // our ops, so our optimistic local state is out of sync with the
12610
- // server. For LiveText ops this is a normal (if rare) situation
12611
- // e.g. a client that was offline long enough to fall outside the
12612
- // server's retained history window — and we can recover: drop the
12613
- // rejected pending state and re-fetch the authoritative storage
12614
- // snapshot. For other ops (e.g. permission rejections), rolling back
12615
- // particular Ops is hard/impossible, so we keep the old behavior of
12616
- // 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.
12617
11161
  case ServerMsgCode.REJECT_STORAGE_OP: {
12618
11162
  errorWithTitle(
12619
11163
  "Storage mutation rejection error",
12620
11164
  message.reason
12621
11165
  );
12622
- let needsStorageResync = false;
12623
- for (const opId of message.opIds) {
12624
- const rejectedOp = context.unacknowledgedOps.get(opId);
12625
- context.unacknowledgedOps.delete(opId);
12626
- context.buffer.storageOperations = context.buffer.storageOperations.filter((op) => op.opId !== opId);
12627
- viaByOpId.delete(opId);
12628
- if (rejectedOp !== void 0 && rejectedOp.type === OpCode.UPDATE_TEXT) {
12629
- const node = context.pool.nodes.get(rejectedOp.id);
12630
- if (node !== void 0 && isLiveText(node)) {
12631
- node._rejectPendingOp(opId);
12632
- needsStorageResync = true;
12633
- }
12634
- }
12635
- }
12636
- if (needsStorageResync) {
12637
- refreshStorage();
12638
- flushNowOrSoon();
12639
- } else if (process.env.NODE_ENV !== "production") {
11166
+ if (process.env.NODE_ENV !== "production") {
12640
11167
  throw new Error(
12641
11168
  `Storage mutations rejected by server: ${message.reason}`
12642
11169
  );
@@ -12735,11 +11262,11 @@ function createRoom(options, config) {
12735
11262
  } else if (pendingFeedsRequests.has(requestId)) {
12736
11263
  const pending = pendingFeedsRequests.get(requestId);
12737
11264
  pendingFeedsRequests.delete(requestId);
12738
- _optionalChain([pending, 'optionalAccess', _272 => _272.reject, 'call', _273 => _273(err)]);
11265
+ _optionalChain([pending, 'optionalAccess', _263 => _263.reject, 'call', _264 => _264(err)]);
12739
11266
  } else if (pendingFeedMessagesRequests.has(requestId)) {
12740
11267
  const pending = pendingFeedMessagesRequests.get(requestId);
12741
11268
  pendingFeedMessagesRequests.delete(requestId);
12742
- _optionalChain([pending, 'optionalAccess', _274 => _274.reject, 'call', _275 => _275(err)]);
11269
+ _optionalChain([pending, 'optionalAccess', _265 => _265.reject, 'call', _266 => _266(err)]);
12743
11270
  }
12744
11271
  eventHub.feeds.notify(message);
12745
11272
  break;
@@ -12893,10 +11420,10 @@ function createRoom(options, config) {
12893
11420
  timeoutId,
12894
11421
  kind,
12895
11422
  feedId,
12896
- messageId: _optionalChain([options2, 'optionalAccess', _276 => _276.messageId]),
12897
- expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _277 => _277.expectedClientMessageId])
11423
+ messageId: _optionalChain([options2, 'optionalAccess', _267 => _267.messageId]),
11424
+ expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _268 => _268.expectedClientMessageId])
12898
11425
  });
12899
- 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) {
12900
11427
  const q = _nullishCoalesce(pendingAddMessageFifoByFeed.get(feedId), () => ( []));
12901
11428
  q.push(requestId);
12902
11429
  pendingAddMessageFifoByFeed.set(feedId, q);
@@ -12947,10 +11474,10 @@ function createRoom(options, config) {
12947
11474
  }
12948
11475
  if (!matched) {
12949
11476
  const q = pendingAddMessageFifoByFeed.get(message.feedId);
12950
- const headId = _optionalChain([q, 'optionalAccess', _279 => _279[0]]);
11477
+ const headId = _optionalChain([q, 'optionalAccess', _270 => _270[0]]);
12951
11478
  if (headId !== void 0) {
12952
11479
  const pending = pendingFeedMutations.get(headId);
12953
- 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) {
12954
11481
  settleFeedMutation(headId, "ok");
12955
11482
  }
12956
11483
  }
@@ -12986,7 +11513,7 @@ function createRoom(options, config) {
12986
11513
  const unacknowledgedOps2 = [...context.unacknowledgedOps.values()];
12987
11514
  createOrUpdateRootFromMessage(nodes);
12988
11515
  applyAndSendOfflineOps(unacknowledgedOps2);
12989
- _optionalChain([_resolveStoragePromise, 'optionalCall', _281 => _281()]);
11516
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _272 => _272()]);
12990
11517
  notifyStorageStatus();
12991
11518
  eventHub.storageDidLoad.notify();
12992
11519
  }
@@ -12995,7 +11522,7 @@ function createRoom(options, config) {
12995
11522
  if (!messages.some((msg) => msg.type === ClientMsgCode.FETCH_STORAGE)) {
12996
11523
  messages.push({ type: ClientMsgCode.FETCH_STORAGE });
12997
11524
  nodeMapBuffer.take();
12998
- _optionalChain([stopwatch, 'optionalAccess', _282 => _282.start, 'call', _283 => _283()]);
11525
+ _optionalChain([stopwatch, 'optionalAccess', _273 => _273.start, 'call', _274 => _274()]);
12999
11526
  }
13000
11527
  }
13001
11528
  function startLoadingStorage() {
@@ -13049,10 +11576,10 @@ function createRoom(options, config) {
13049
11576
  const message = {
13050
11577
  type: ClientMsgCode.FETCH_FEEDS,
13051
11578
  requestId,
13052
- cursor: _optionalChain([options2, 'optionalAccess', _284 => _284.cursor]),
13053
- since: _optionalChain([options2, 'optionalAccess', _285 => _285.since]),
13054
- limit: _optionalChain([options2, 'optionalAccess', _286 => _286.limit]),
13055
- 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])
13056
11583
  };
13057
11584
  context.buffer.messages.push(message);
13058
11585
  flushNowOrSoon();
@@ -13072,9 +11599,9 @@ function createRoom(options, config) {
13072
11599
  type: ClientMsgCode.FETCH_FEED_MESSAGES,
13073
11600
  requestId,
13074
11601
  feedId,
13075
- cursor: _optionalChain([options2, 'optionalAccess', _288 => _288.cursor]),
13076
- since: _optionalChain([options2, 'optionalAccess', _289 => _289.since]),
13077
- 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])
13078
11605
  };
13079
11606
  context.buffer.messages.push(message);
13080
11607
  flushNowOrSoon();
@@ -13093,8 +11620,8 @@ function createRoom(options, config) {
13093
11620
  type: ClientMsgCode.ADD_FEED,
13094
11621
  requestId,
13095
11622
  feedId,
13096
- metadata: _optionalChain([options2, 'optionalAccess', _291 => _291.metadata]),
13097
- createdAt: _optionalChain([options2, 'optionalAccess', _292 => _292.createdAt])
11623
+ metadata: _optionalChain([options2, 'optionalAccess', _282 => _282.metadata]),
11624
+ createdAt: _optionalChain([options2, 'optionalAccess', _283 => _283.createdAt])
13098
11625
  };
13099
11626
  context.buffer.messages.push(message);
13100
11627
  flushNowOrSoon();
@@ -13128,15 +11655,15 @@ function createRoom(options, config) {
13128
11655
  function addFeedMessage(feedId, data, options2) {
13129
11656
  const requestId = nanoid();
13130
11657
  const promise = registerFeedMutation(requestId, "add-message", feedId, {
13131
- expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _293 => _293.id])
11658
+ expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _284 => _284.id])
13132
11659
  });
13133
11660
  const message = {
13134
11661
  type: ClientMsgCode.ADD_FEED_MESSAGE,
13135
11662
  requestId,
13136
11663
  feedId,
13137
11664
  data,
13138
- id: _optionalChain([options2, 'optionalAccess', _294 => _294.id]),
13139
- createdAt: _optionalChain([options2, 'optionalAccess', _295 => _295.createdAt])
11665
+ id: _optionalChain([options2, 'optionalAccess', _285 => _285.id]),
11666
+ createdAt: _optionalChain([options2, 'optionalAccess', _286 => _286.createdAt])
13140
11667
  };
13141
11668
  context.buffer.messages.push(message);
13142
11669
  flushNowOrSoon();
@@ -13153,7 +11680,7 @@ function createRoom(options, config) {
13153
11680
  feedId,
13154
11681
  messageId,
13155
11682
  data,
13156
- updatedAt: _optionalChain([options2, 'optionalAccess', _296 => _296.updatedAt])
11683
+ updatedAt: _optionalChain([options2, 'optionalAccess', _287 => _287.updatedAt])
13157
11684
  };
13158
11685
  context.buffer.messages.push(message);
13159
11686
  flushNowOrSoon();
@@ -13178,15 +11705,14 @@ function createRoom(options, config) {
13178
11705
  if (context.activeBatch) {
13179
11706
  throw new Error("undo is not allowed during a batch");
13180
11707
  }
13181
- const item = context.undoStack.pop();
13182
- if (item === void 0) {
11708
+ const frames = context.undoStack.pop();
11709
+ if (frames === void 0) {
13183
11710
  return;
13184
11711
  }
13185
11712
  context.pausedHistory = null;
13186
- const result = applyLocalOps(item.frames, LOCAL_UNDO);
13187
- context.redoStack.push({ id: item.id, frames: result.reverse });
13188
- notifyPrivateHistory({ action: "undo", id: item.id });
11713
+ const result = applyLocalOps(frames);
13189
11714
  notify(result.updates);
11715
+ context.redoStack.push(result.reverse);
13190
11716
  onHistoryChange();
13191
11717
  for (const op of result.opsToEmit) {
13192
11718
  context.buffer.storageOperations.push(op);
@@ -13197,15 +11723,14 @@ function createRoom(options, config) {
13197
11723
  if (context.activeBatch) {
13198
11724
  throw new Error("redo is not allowed during a batch");
13199
11725
  }
13200
- const item = context.redoStack.pop();
13201
- if (item === void 0) {
11726
+ const frames = context.redoStack.pop();
11727
+ if (frames === void 0) {
13202
11728
  return;
13203
11729
  }
13204
11730
  context.pausedHistory = null;
13205
- const result = applyLocalOps(item.frames, LOCAL_REDO);
13206
- context.undoStack.push({ id: item.id, frames: result.reverse });
13207
- notifyPrivateHistory({ action: "redo", id: item.id });
11731
+ const result = applyLocalOps(frames);
13208
11732
  notify(result.updates);
11733
+ context.undoStack.push(result.reverse);
13209
11734
  onHistoryChange();
13210
11735
  for (const op of result.opsToEmit) {
13211
11736
  context.buffer.storageOperations.push(op);
@@ -13215,8 +11740,6 @@ function createRoom(options, config) {
13215
11740
  function clear() {
13216
11741
  context.undoStack.length = 0;
13217
11742
  context.redoStack.length = 0;
13218
- notifyPrivateHistory({ action: "clear" });
13219
- onHistoryChange();
13220
11743
  }
13221
11744
  function batch2(callback) {
13222
11745
  if (context.activeBatch) {
@@ -13244,8 +11767,8 @@ function createRoom(options, config) {
13244
11767
  if (currentBatch.scheduleHistoryResume) {
13245
11768
  commitPausedHistoryToUndoStack();
13246
11769
  }
13247
- if (currentBatch.ops.length > 0 || currentBatch.clearRedoStack) {
13248
- clearRedoStack();
11770
+ if (currentBatch.ops.length > 0) {
11771
+ context.redoStack.length = 0;
13249
11772
  }
13250
11773
  if (currentBatch.ops.length > 0) {
13251
11774
  dispatchOps(currentBatch.ops);
@@ -13274,6 +11797,7 @@ function createRoom(options, config) {
13274
11797
  }
13275
11798
  commitPausedHistoryToUndoStack();
13276
11799
  }
11800
+ let historyDisabled = 0;
13277
11801
  function disableHistory(fn) {
13278
11802
  const origUndo = context.undoStack;
13279
11803
  const origRedo = context.redoStack;
@@ -13363,8 +11887,8 @@ function createRoom(options, config) {
13363
11887
  async function getThreads(options2) {
13364
11888
  return httpClient.getThreads({
13365
11889
  roomId,
13366
- query: _optionalChain([options2, 'optionalAccess', _297 => _297.query]),
13367
- cursor: _optionalChain([options2, 'optionalAccess', _298 => _298.cursor])
11890
+ query: _optionalChain([options2, 'optionalAccess', _288 => _288.query]),
11891
+ cursor: _optionalChain([options2, 'optionalAccess', _289 => _289.cursor])
13368
11892
  });
13369
11893
  }
13370
11894
  async function getThread(threadId) {
@@ -13497,7 +12021,7 @@ function createRoom(options, config) {
13497
12021
  function getSubscriptionSettings(options2) {
13498
12022
  return httpClient.getSubscriptionSettings({
13499
12023
  roomId,
13500
- signal: _optionalChain([options2, 'optionalAccess', _299 => _299.signal])
12024
+ signal: _optionalChain([options2, 'optionalAccess', _290 => _290.signal])
13501
12025
  });
13502
12026
  }
13503
12027
  function updateSubscriptionSettings(settings) {
@@ -13519,45 +12043,30 @@ function createRoom(options, config) {
13519
12043
  {
13520
12044
  [kInternal]: {
13521
12045
  get presenceBuffer() {
13522
- 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)));
13523
12047
  },
13524
12048
  // prettier-ignore
13525
12049
  get undoStack() {
13526
- return structuredClone(
13527
- context.undoStack.map((item) => ({
13528
- id: item.id,
13529
- frames: item.frames
13530
- }))
13531
- );
13532
- },
13533
- // prettier-ignore
13534
- get redoStack() {
13535
- return structuredClone(
13536
- context.redoStack.map((item) => ({
13537
- id: item.id,
13538
- frames: item.frames
13539
- }))
13540
- );
12050
+ return deepClone(context.undoStack);
13541
12051
  },
13542
12052
  // prettier-ignore
13543
12053
  get nodeCount() {
13544
12054
  return context.pool.nodes.size;
13545
12055
  },
13546
12056
  // prettier-ignore
13547
- history: eventHub.privateHistory.observable,
13548
12057
  getYjsProvider() {
13549
12058
  return context.yjsProvider;
13550
12059
  },
13551
12060
  setYjsProvider(newProvider) {
13552
- _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)]);
13553
12062
  context.yjsProvider = newProvider;
13554
- _optionalChain([newProvider, 'optionalAccess', _306 => _306.on, 'call', _307 => _307("status", yjsStatusDidChange)]);
12063
+ _optionalChain([newProvider, 'optionalAccess', _297 => _297.on, 'call', _298 => _298("status", yjsStatusDidChange)]);
13555
12064
  context.yjsProviderDidChange.notify();
13556
12065
  },
13557
12066
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
13558
12067
  // send metadata when using a text editor
13559
12068
  reportTextEditor,
13560
- 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]),
13561
12070
  // create a text mention when using a text editor
13562
12071
  createTextMention,
13563
12072
  // delete a text mention when using a text editor
@@ -13620,7 +12129,7 @@ ${dumpPool(
13620
12129
  source.dispose();
13621
12130
  }
13622
12131
  eventHub.roomWillDestroy.notify();
13623
- _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)]);
13624
12133
  syncSourceForStorage.destroy();
13625
12134
  syncSourceForYjs.destroy();
13626
12135
  uninstallBgTabSpy();
@@ -13784,7 +12293,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
13784
12293
  }
13785
12294
  if (isLiveNode(first)) {
13786
12295
  const node = first;
13787
- if (_optionalChain([options, 'optionalAccess', _315 => _315.isDeep])) {
12296
+ if (_optionalChain([options, 'optionalAccess', _306 => _306.isDeep])) {
13788
12297
  const storageCallback = second;
13789
12298
  return subscribeToLiveStructureDeeply(node, storageCallback);
13790
12299
  } else {
@@ -13874,8 +12383,8 @@ function createClient(options) {
13874
12383
  const authManager = createAuthManager(options, (token) => {
13875
12384
  currentUserId.set(() => token.uid);
13876
12385
  });
13877
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _316 => _316.polyfills, 'optionalAccess', _317 => _317.fetch]) || /* istanbul ignore next */
13878
- _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)]);
13879
12388
  const httpClient = createApiClient({
13880
12389
  baseUrl,
13881
12390
  fetchPolyfill,
@@ -13892,7 +12401,7 @@ function createClient(options) {
13892
12401
  delegates: {
13893
12402
  createSocket: makeCreateSocketDelegateForAi(
13894
12403
  baseUrl,
13895
- _optionalChain([clientOptions, 'access', _321 => _321.polyfills, 'optionalAccess', _322 => _322.WebSocket])
12404
+ _optionalChain([clientOptions, 'access', _312 => _312.polyfills, 'optionalAccess', _313 => _313.WebSocket])
13896
12405
  ),
13897
12406
  authenticate: async () => {
13898
12407
  const resp = await authManager.getAuthValue({
@@ -13963,7 +12472,7 @@ function createClient(options) {
13963
12472
  createSocket: makeCreateSocketDelegateForRoom(
13964
12473
  roomId,
13965
12474
  baseUrl,
13966
- _optionalChain([clientOptions, 'access', _323 => _323.polyfills, 'optionalAccess', _324 => _324.WebSocket])
12475
+ _optionalChain([clientOptions, 'access', _314 => _314.polyfills, 'optionalAccess', _315 => _315.WebSocket])
13967
12476
  ),
13968
12477
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
13969
12478
  })),
@@ -13985,7 +12494,7 @@ function createClient(options) {
13985
12494
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
13986
12495
  if (shouldConnect) {
13987
12496
  if (typeof atob === "undefined") {
13988
- 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) {
13989
12498
  throw new Error(
13990
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"
13991
12500
  );
@@ -13997,7 +12506,7 @@ function createClient(options) {
13997
12506
  return leaseRoom(newRoomDetails);
13998
12507
  }
13999
12508
  function getRoom(roomId) {
14000
- 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]);
14001
12510
  return room ? room : null;
14002
12511
  }
14003
12512
  function logout() {
@@ -14013,7 +12522,7 @@ function createClient(options) {
14013
12522
  const batchedResolveUsers = new Batch(
14014
12523
  async (batchedUserIds) => {
14015
12524
  const userIds = batchedUserIds.flat();
14016
- const users = await _optionalChain([resolveUsers, 'optionalCall', _330 => _330({ userIds })]);
12525
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _321 => _321({ userIds })]);
14017
12526
  warnOnceIf(
14018
12527
  !resolveUsers,
14019
12528
  "Set the resolveUsers option in createClient to specify user info."
@@ -14030,7 +12539,7 @@ function createClient(options) {
14030
12539
  const batchedResolveRoomsInfo = new Batch(
14031
12540
  async (batchedRoomIds) => {
14032
12541
  const roomIds = batchedRoomIds.flat();
14033
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _331 => _331({ roomIds })]);
12542
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _322 => _322({ roomIds })]);
14034
12543
  warnOnceIf(
14035
12544
  !resolveRoomsInfo,
14036
12545
  "Set the resolveRoomsInfo option in createClient to specify room info."
@@ -14047,7 +12556,7 @@ function createClient(options) {
14047
12556
  const batchedResolveGroupsInfo = new Batch(
14048
12557
  async (batchedGroupIds) => {
14049
12558
  const groupIds = batchedGroupIds.flat();
14050
- const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _332 => _332({ groupIds })]);
12559
+ const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _323 => _323({ groupIds })]);
14051
12560
  warnOnceIf(
14052
12561
  !resolveGroupsInfo,
14053
12562
  "Set the resolveGroupsInfo option in createClient to specify group info."
@@ -14106,7 +12615,7 @@ function createClient(options) {
14106
12615
  }
14107
12616
  };
14108
12617
  const win = typeof window !== "undefined" ? window : void 0;
14109
- _optionalChain([win, 'optionalAccess', _333 => _333.addEventListener, 'call', _334 => _334("beforeunload", maybePreventClose)]);
12618
+ _optionalChain([win, 'optionalAccess', _324 => _324.addEventListener, 'call', _325 => _325("beforeunload", maybePreventClose)]);
14110
12619
  }
14111
12620
  async function getNotificationSettings(options2) {
14112
12621
  const plainSettings = await httpClient.getNotificationSettings(options2);
@@ -14234,7 +12743,7 @@ var commentBodyElementsTypes = {
14234
12743
  mention: "inline"
14235
12744
  };
14236
12745
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
14237
- if (!body || !_optionalChain([body, 'optionalAccess', _335 => _335.content])) {
12746
+ if (!body || !_optionalChain([body, 'optionalAccess', _326 => _326.content])) {
14238
12747
  return;
14239
12748
  }
14240
12749
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -14244,13 +12753,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
14244
12753
  for (const block of body.content) {
14245
12754
  if (type === "all" || type === "block") {
14246
12755
  if (guard(block)) {
14247
- _optionalChain([visitor, 'optionalCall', _336 => _336(block)]);
12756
+ _optionalChain([visitor, 'optionalCall', _327 => _327(block)]);
14248
12757
  }
14249
12758
  }
14250
12759
  if (type === "all" || type === "inline") {
14251
12760
  for (const inline of block.children) {
14252
12761
  if (guard(inline)) {
14253
- _optionalChain([visitor, 'optionalCall', _337 => _337(inline)]);
12762
+ _optionalChain([visitor, 'optionalCall', _328 => _328(inline)]);
14254
12763
  }
14255
12764
  }
14256
12765
  }
@@ -14420,7 +12929,7 @@ var stringifyCommentBodyPlainElements = {
14420
12929
  text: ({ element }) => element.text,
14421
12930
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
14422
12931
  mention: ({ element, user, group }) => {
14423
- 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))}`;
14424
12933
  }
14425
12934
  };
14426
12935
  var stringifyCommentBodyHtmlElements = {
@@ -14450,7 +12959,7 @@ var stringifyCommentBodyHtmlElements = {
14450
12959
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
14451
12960
  },
14452
12961
  mention: ({ element, user, group }) => {
14453
- 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>`;
14454
12963
  }
14455
12964
  };
14456
12965
  var stringifyCommentBodyMarkdownElements = {
@@ -14480,20 +12989,20 @@ var stringifyCommentBodyMarkdownElements = {
14480
12989
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
14481
12990
  },
14482
12991
  mention: ({ element, user, group }) => {
14483
- 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))}`;
14484
12993
  }
14485
12994
  };
14486
12995
  async function stringifyCommentBody(body, options) {
14487
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _346 => _346.format]), () => ( "plain"));
14488
- 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")));
14489
12998
  const elements = {
14490
12999
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
14491
- ..._optionalChain([options, 'optionalAccess', _348 => _348.elements])
13000
+ ..._optionalChain([options, 'optionalAccess', _339 => _339.elements])
14492
13001
  };
14493
13002
  const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
14494
13003
  body,
14495
- _optionalChain([options, 'optionalAccess', _349 => _349.resolveUsers]),
14496
- _optionalChain([options, 'optionalAccess', _350 => _350.resolveGroupsInfo])
13004
+ _optionalChain([options, 'optionalAccess', _340 => _340.resolveUsers]),
13005
+ _optionalChain([options, 'optionalAccess', _341 => _341.resolveGroupsInfo])
14497
13006
  );
14498
13007
  const blocks = body.content.flatMap((block, blockIndex) => {
14499
13008
  switch (block.type) {
@@ -14575,12 +13084,6 @@ function toPlainLson(lson) {
14575
13084
  liveblocksType: "LiveList",
14576
13085
  data: [...lson].map((item) => toPlainLson(item))
14577
13086
  };
14578
- } else if (lson instanceof LiveText) {
14579
- return {
14580
- liveblocksType: "LiveText",
14581
- data: lson.toJSON(),
14582
- version: lson.version
14583
- };
14584
13087
  } else if (lson instanceof LiveFile) {
14585
13088
  return {
14586
13089
  liveblocksType: "LiveFile",
@@ -14639,9 +13142,9 @@ function makePoller(callback, intervalMs, options) {
14639
13142
  const startTime = performance.now();
14640
13143
  const doc = typeof document !== "undefined" ? document : void 0;
14641
13144
  const win = typeof window !== "undefined" ? window : void 0;
14642
- 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));
14643
13146
  const context = {
14644
- inForeground: _optionalChain([doc, 'optionalAccess', _352 => _352.visibilityState]) !== "hidden",
13147
+ inForeground: _optionalChain([doc, 'optionalAccess', _343 => _343.visibilityState]) !== "hidden",
14645
13148
  lastSuccessfulPollAt: startTime,
14646
13149
  count: 0,
14647
13150
  backoff: 0
@@ -14722,11 +13225,11 @@ function makePoller(callback, intervalMs, options) {
14722
13225
  pollNowIfStale();
14723
13226
  }
14724
13227
  function onVisibilityChange() {
14725
- setInForeground(_optionalChain([doc, 'optionalAccess', _353 => _353.visibilityState]) !== "hidden");
13228
+ setInForeground(_optionalChain([doc, 'optionalAccess', _344 => _344.visibilityState]) !== "hidden");
14726
13229
  }
14727
- _optionalChain([doc, 'optionalAccess', _354 => _354.addEventListener, 'call', _355 => _355("visibilitychange", onVisibilityChange)]);
14728
- _optionalChain([win, 'optionalAccess', _356 => _356.addEventListener, 'call', _357 => _357("online", onVisibilityChange)]);
14729
- _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)]);
14730
13233
  fsm.start();
14731
13234
  return {
14732
13235
  inc,
@@ -14875,10 +13378,5 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
14875
13378
 
14876
13379
 
14877
13380
 
14878
-
14879
-
14880
-
14881
-
14882
-
14883
- 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.normalizeLiveTextOperations = normalizeLiveTextOperations; 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;
14884
13382
  //# sourceMappingURL=index.cjs.map