@liveblocks/core 3.23.1 → 3.24.0
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 +1889 -363
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +620 -273
- package/dist/index.d.ts +620 -273
- package/dist/index.js +1817 -291
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
9
|
+
var PKG_VERSION = "3.24.0";
|
|
10
10
|
var PKG_FORMAT = "cjs";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -988,14 +988,15 @@ var OpCode = Object.freeze({
|
|
|
988
988
|
DELETE_OBJECT_KEY: 6,
|
|
989
989
|
CREATE_MAP: 7,
|
|
990
990
|
CREATE_REGISTER: 8,
|
|
991
|
-
|
|
991
|
+
CREATE_TEXT: 9,
|
|
992
|
+
UPDATE_TEXT: 10,
|
|
992
993
|
CREATE_FILE: 11
|
|
993
994
|
});
|
|
994
995
|
function isIgnoredOp(op) {
|
|
995
996
|
return op.type === OpCode.DELETE_CRDT && op.id === "ACK";
|
|
996
997
|
}
|
|
997
998
|
function isCreateOp(op) {
|
|
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;
|
|
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;
|
|
999
1000
|
}
|
|
1000
1001
|
|
|
1001
1002
|
// src/protocol/StorageNode.ts
|
|
@@ -1004,7 +1005,7 @@ var CrdtType = Object.freeze({
|
|
|
1004
1005
|
LIST: 1,
|
|
1005
1006
|
MAP: 2,
|
|
1006
1007
|
REGISTER: 3,
|
|
1007
|
-
|
|
1008
|
+
TEXT: 4,
|
|
1008
1009
|
FILE: 5
|
|
1009
1010
|
});
|
|
1010
1011
|
function isRootStorageNode(node) {
|
|
@@ -1022,6 +1023,9 @@ function isMapStorageNode(node) {
|
|
|
1022
1023
|
function isRegisterStorageNode(node) {
|
|
1023
1024
|
return node[1].type === CrdtType.REGISTER;
|
|
1024
1025
|
}
|
|
1026
|
+
function isTextStorageNode(node) {
|
|
1027
|
+
return node[1].type === CrdtType.TEXT;
|
|
1028
|
+
}
|
|
1025
1029
|
function isFileStorageNode(node) {
|
|
1026
1030
|
return node[1].type === CrdtType.FILE;
|
|
1027
1031
|
}
|
|
@@ -1047,6 +1051,9 @@ function* compactNodesToNodeStream(compactNodes) {
|
|
|
1047
1051
|
case CrdtType.REGISTER:
|
|
1048
1052
|
yield [cnode[0], { type: CrdtType.REGISTER, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
|
|
1049
1053
|
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;
|
|
1050
1057
|
case CrdtType.FILE:
|
|
1051
1058
|
yield [cnode[0], { type: CrdtType.FILE, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
|
|
1052
1059
|
break;
|
|
@@ -1078,6 +1085,17 @@ function* nodeStreamToCompactNodes(nodes) {
|
|
|
1078
1085
|
const id = node[0];
|
|
1079
1086
|
const crdt = node[1];
|
|
1080
1087
|
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
|
+
];
|
|
1081
1099
|
} else if (isFileStorageNode(node)) {
|
|
1082
1100
|
const id = node[0];
|
|
1083
1101
|
const crdt = node[1];
|
|
@@ -1087,6 +1105,42 @@ function* nodeStreamToCompactNodes(nodes) {
|
|
|
1087
1105
|
}
|
|
1088
1106
|
}
|
|
1089
1107
|
|
|
1108
|
+
// src/internal.ts
|
|
1109
|
+
var kInternal = /* @__PURE__ */ Symbol();
|
|
1110
|
+
|
|
1111
|
+
// src/lib/fancy-console.ts
|
|
1112
|
+
var fancy_console_exports = {};
|
|
1113
|
+
__export(fancy_console_exports, {
|
|
1114
|
+
error: () => error2,
|
|
1115
|
+
errorWithTitle: () => errorWithTitle,
|
|
1116
|
+
warn: () => warn,
|
|
1117
|
+
warnWithTitle: () => warnWithTitle
|
|
1118
|
+
});
|
|
1119
|
+
var badge = "background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;";
|
|
1120
|
+
var bold = "font-weight:600";
|
|
1121
|
+
function wrap(method) {
|
|
1122
|
+
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
1123
|
+
/* istanbul ignore next */
|
|
1124
|
+
(message, ...args) => console[method]("%cLiveblocks", badge, message, ...args)
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
var warn = wrap("warn");
|
|
1128
|
+
var error2 = wrap("error");
|
|
1129
|
+
function wrapWithTitle(method) {
|
|
1130
|
+
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
1131
|
+
/* istanbul ignore next */
|
|
1132
|
+
(title, message, ...args) => console[method](
|
|
1133
|
+
`%cLiveblocks%c ${title}`,
|
|
1134
|
+
badge,
|
|
1135
|
+
bold,
|
|
1136
|
+
message,
|
|
1137
|
+
...args
|
|
1138
|
+
)
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
var warnWithTitle = wrapWithTitle("warn");
|
|
1142
|
+
var errorWithTitle = wrapWithTitle("error");
|
|
1143
|
+
|
|
1090
1144
|
// src/lib/position.ts
|
|
1091
1145
|
var MIN_CODE = 32;
|
|
1092
1146
|
var MAX_CODE = 126;
|
|
@@ -1266,6 +1320,18 @@ function asPos(str) {
|
|
|
1266
1320
|
return isPos(str) ? str : convertToPos(str);
|
|
1267
1321
|
}
|
|
1268
1322
|
|
|
1323
|
+
// src/crdts/StorageUpdates.ts
|
|
1324
|
+
var REMOTE = freeze({ origin: "remote" });
|
|
1325
|
+
var LOCAL_EDIT = freeze({ origin: "local", via: "edit" });
|
|
1326
|
+
var LOCAL_UNDO = freeze({ origin: "local", via: "undo" });
|
|
1327
|
+
var LOCAL_REDO = freeze({ origin: "local", via: "redo" });
|
|
1328
|
+
function toUpdateSource(source) {
|
|
1329
|
+
return source.origin === "remote" ? source : (
|
|
1330
|
+
// Removes `optimistic` field, which is not public
|
|
1331
|
+
{ origin: "local", via: source.via }
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1269
1335
|
// src/crdts/UnacknowledgedOps.ts
|
|
1270
1336
|
var UnacknowledgedOps = class {
|
|
1271
1337
|
// opId -> op
|
|
@@ -1284,6 +1350,10 @@ ${parentKey}`;
|
|
|
1284
1350
|
get size() {
|
|
1285
1351
|
return this.#byOpId.size;
|
|
1286
1352
|
}
|
|
1353
|
+
/** The still-unacknowledged op with the given opId, if any. */
|
|
1354
|
+
get(opId) {
|
|
1355
|
+
return this.#byOpId.get(opId);
|
|
1356
|
+
}
|
|
1287
1357
|
/**
|
|
1288
1358
|
* Mark the given Op as still unacknowledged.
|
|
1289
1359
|
*/
|
|
@@ -1366,6 +1436,8 @@ ${parentKey}`;
|
|
|
1366
1436
|
};
|
|
1367
1437
|
|
|
1368
1438
|
// src/crdts/AbstractCrdt.ts
|
|
1439
|
+
var warnedOrphanedNodes = /* @__PURE__ */ new WeakSet();
|
|
1440
|
+
var ORPHANED_NODE_WARNING = "Cannot sync changes made to this Live structure because it is no longer part of Storage. Retrieve the current value from its parent before mutating it.";
|
|
1369
1441
|
function createManagedPool(options) {
|
|
1370
1442
|
const {
|
|
1371
1443
|
getCurrentConnectionId,
|
|
@@ -1383,8 +1455,8 @@ function createManagedPool(options) {
|
|
|
1383
1455
|
deleteNode: (id) => void nodes.delete(id),
|
|
1384
1456
|
generateId: () => `${getCurrentConnectionId()}:${clock++}`,
|
|
1385
1457
|
generateOpId: () => `${getCurrentConnectionId()}:${opClock++}`,
|
|
1386
|
-
dispatch(ops, reverse, storageUpdates) {
|
|
1387
|
-
_optionalChain([onDispatch, 'optionalCall', _23 => _23(ops, reverse, storageUpdates)]);
|
|
1458
|
+
dispatch(ops, reverse, storageUpdates, options2) {
|
|
1459
|
+
_optionalChain([onDispatch, 'optionalCall', _23 => _23(ops, reverse, storageUpdates, options2)]);
|
|
1388
1460
|
},
|
|
1389
1461
|
assertStorageIsWritable: () => {
|
|
1390
1462
|
if (!isStorageWritable()) {
|
|
@@ -1407,10 +1479,17 @@ function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
|
1407
1479
|
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
1408
1480
|
}
|
|
1409
1481
|
var AbstractCrdt = class {
|
|
1410
|
-
// ^^^^^^^^^^^^ TODO: Make this an interface
|
|
1411
1482
|
#pool;
|
|
1412
1483
|
#id;
|
|
1413
1484
|
#parent = NoParent;
|
|
1485
|
+
constructor() {
|
|
1486
|
+
Object.defineProperty(this, kInternal, {
|
|
1487
|
+
value: {
|
|
1488
|
+
getId: () => this.#id
|
|
1489
|
+
},
|
|
1490
|
+
enumerable: false
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1414
1493
|
/** @internal */
|
|
1415
1494
|
_getParentKeyOrThrow() {
|
|
1416
1495
|
switch (this.parent.type) {
|
|
@@ -1450,6 +1529,17 @@ var AbstractCrdt = class {
|
|
|
1450
1529
|
return this.#parent;
|
|
1451
1530
|
}
|
|
1452
1531
|
/** @internal */
|
|
1532
|
+
_warnIfOrphaned() {
|
|
1533
|
+
const node = crdtAsLiveNode(this);
|
|
1534
|
+
if (this.parent.type === "Orphaned" && !warnedOrphanedNodes.has(node)) {
|
|
1535
|
+
warnedOrphanedNodes.add(node);
|
|
1536
|
+
warn(ORPHANED_NODE_WARNING, {
|
|
1537
|
+
type: node.constructor.name,
|
|
1538
|
+
formerParentKey: this.parent.oldKey
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
/** @internal */
|
|
1453
1543
|
get _parentKey() {
|
|
1454
1544
|
switch (this.parent.type) {
|
|
1455
1545
|
case "HasParent":
|
|
@@ -1463,11 +1553,14 @@ var AbstractCrdt = class {
|
|
|
1463
1553
|
}
|
|
1464
1554
|
}
|
|
1465
1555
|
/** @internal */
|
|
1466
|
-
_apply(op,
|
|
1556
|
+
_apply(op, source) {
|
|
1467
1557
|
switch (op.type) {
|
|
1468
1558
|
case OpCode.DELETE_CRDT: {
|
|
1469
1559
|
if (this.parent.type === "HasParent") {
|
|
1470
|
-
return this.parent.node._detachChild(
|
|
1560
|
+
return this.parent.node._detachChild(
|
|
1561
|
+
crdtAsLiveNode(this),
|
|
1562
|
+
toUpdateSource(source)
|
|
1563
|
+
);
|
|
1471
1564
|
}
|
|
1472
1565
|
return { modified: false };
|
|
1473
1566
|
}
|
|
@@ -1657,8 +1750,8 @@ var LiveFile = class _LiveFile extends AbstractCrdt {
|
|
|
1657
1750
|
throw new Error("A LiveFile node cannot have children");
|
|
1658
1751
|
}
|
|
1659
1752
|
/** @internal */
|
|
1660
|
-
_apply(op,
|
|
1661
|
-
return super._apply(op,
|
|
1753
|
+
_apply(op, source) {
|
|
1754
|
+
return super._apply(op, source);
|
|
1662
1755
|
}
|
|
1663
1756
|
/** @internal */
|
|
1664
1757
|
_toTreeNode(key) {
|
|
@@ -1678,39 +1771,6 @@ var LiveFile = class _LiveFile extends AbstractCrdt {
|
|
|
1678
1771
|
}
|
|
1679
1772
|
};
|
|
1680
1773
|
|
|
1681
|
-
// src/lib/fancy-console.ts
|
|
1682
|
-
var fancy_console_exports = {};
|
|
1683
|
-
__export(fancy_console_exports, {
|
|
1684
|
-
error: () => error2,
|
|
1685
|
-
errorWithTitle: () => errorWithTitle,
|
|
1686
|
-
warn: () => warn,
|
|
1687
|
-
warnWithTitle: () => warnWithTitle
|
|
1688
|
-
});
|
|
1689
|
-
var badge = "background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;";
|
|
1690
|
-
var bold = "font-weight:600";
|
|
1691
|
-
function wrap(method) {
|
|
1692
|
-
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
1693
|
-
/* istanbul ignore next */
|
|
1694
|
-
(message, ...args) => console[method]("%cLiveblocks", badge, message, ...args)
|
|
1695
|
-
);
|
|
1696
|
-
}
|
|
1697
|
-
var warn = wrap("warn");
|
|
1698
|
-
var error2 = wrap("error");
|
|
1699
|
-
function wrapWithTitle(method) {
|
|
1700
|
-
return typeof window === "undefined" || process.env.NODE_ENV === "test" ? console[method] : (
|
|
1701
|
-
/* istanbul ignore next */
|
|
1702
|
-
(title, message, ...args) => console[method](
|
|
1703
|
-
`%cLiveblocks%c ${title}`,
|
|
1704
|
-
badge,
|
|
1705
|
-
bold,
|
|
1706
|
-
message,
|
|
1707
|
-
...args
|
|
1708
|
-
)
|
|
1709
|
-
);
|
|
1710
|
-
}
|
|
1711
|
-
var warnWithTitle = wrapWithTitle("warn");
|
|
1712
|
-
var errorWithTitle = wrapWithTitle("error");
|
|
1713
|
-
|
|
1714
1774
|
// src/lib/guards.ts
|
|
1715
1775
|
function isDefined(value) {
|
|
1716
1776
|
return value !== null && value !== void 0;
|
|
@@ -4877,9 +4937,6 @@ var ManagedSocket = class {
|
|
|
4877
4937
|
}
|
|
4878
4938
|
};
|
|
4879
4939
|
|
|
4880
|
-
// src/internal.ts
|
|
4881
|
-
var kInternal = /* @__PURE__ */ Symbol();
|
|
4882
|
-
|
|
4883
4940
|
// src/lib/IncrementalJsonParser.ts
|
|
4884
4941
|
var EMPTY_OBJECT = Object.freeze({});
|
|
4885
4942
|
var NULL_KEYWORD_CHARS = Array.from(new Set("null"));
|
|
@@ -6881,8 +6938,8 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
|
6881
6938
|
throw new Error("Method not implemented.");
|
|
6882
6939
|
}
|
|
6883
6940
|
/** @internal */
|
|
6884
|
-
_apply(op,
|
|
6885
|
-
return super._apply(op,
|
|
6941
|
+
_apply(op, source) {
|
|
6942
|
+
return super._apply(op, source);
|
|
6886
6943
|
}
|
|
6887
6944
|
/** @internal */
|
|
6888
6945
|
_toTreeNode(key) {
|
|
@@ -7043,7 +7100,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7043
7100
|
item._detach();
|
|
7044
7101
|
}
|
|
7045
7102
|
}
|
|
7046
|
-
#
|
|
7103
|
+
#applyRemoteSet(op) {
|
|
7047
7104
|
if (this._pool === void 0) {
|
|
7048
7105
|
throw new Error("Can't attach child if managed pool is not present");
|
|
7049
7106
|
}
|
|
@@ -7061,9 +7118,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7061
7118
|
itemWithSamePosition._detach();
|
|
7062
7119
|
this.#items.add(child);
|
|
7063
7120
|
return {
|
|
7064
|
-
modified: makeUpdate(
|
|
7065
|
-
|
|
7066
|
-
|
|
7121
|
+
modified: makeUpdate(
|
|
7122
|
+
this,
|
|
7123
|
+
[setDelta(indexOfItemWithSamePosition, child)],
|
|
7124
|
+
REMOTE
|
|
7125
|
+
),
|
|
7067
7126
|
reverse: []
|
|
7068
7127
|
};
|
|
7069
7128
|
} else {
|
|
@@ -7074,20 +7133,22 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7074
7133
|
setDelta(indexOfItemWithSamePosition, child)
|
|
7075
7134
|
];
|
|
7076
7135
|
const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
|
|
7077
|
-
op.deletedId
|
|
7136
|
+
op.deletedId,
|
|
7137
|
+
REMOTE
|
|
7078
7138
|
);
|
|
7079
7139
|
if (deleteDelta2) {
|
|
7080
7140
|
delta.push(deleteDelta2);
|
|
7081
7141
|
}
|
|
7082
7142
|
return {
|
|
7083
|
-
modified: makeUpdate(this, delta),
|
|
7143
|
+
modified: makeUpdate(this, delta, REMOTE),
|
|
7084
7144
|
reverse: []
|
|
7085
7145
|
};
|
|
7086
7146
|
}
|
|
7087
7147
|
} else {
|
|
7088
7148
|
const updates = [];
|
|
7089
7149
|
const deleteDelta2 = this.#detachItemAssociatedToSetOperation(
|
|
7090
|
-
op.deletedId
|
|
7150
|
+
op.deletedId,
|
|
7151
|
+
REMOTE
|
|
7091
7152
|
);
|
|
7092
7153
|
if (deleteDelta2) {
|
|
7093
7154
|
updates.push(deleteDelta2);
|
|
@@ -7096,29 +7157,32 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7096
7157
|
updates.push(insertDelta(this._indexOfPosition(key), child));
|
|
7097
7158
|
return {
|
|
7098
7159
|
reverse: [],
|
|
7099
|
-
modified: makeUpdate(this, updates)
|
|
7160
|
+
modified: makeUpdate(this, updates, REMOTE)
|
|
7100
7161
|
};
|
|
7101
7162
|
}
|
|
7102
7163
|
}
|
|
7103
|
-
#applySetAck(op) {
|
|
7164
|
+
#applySetAck(op, source) {
|
|
7104
7165
|
if (this._pool === void 0) {
|
|
7105
7166
|
throw new Error("Can't attach child if managed pool is not present");
|
|
7106
7167
|
}
|
|
7107
7168
|
const delta = [];
|
|
7108
|
-
const deletedDelta = this.#detachItemAssociatedToSetOperation(
|
|
7169
|
+
const deletedDelta = this.#detachItemAssociatedToSetOperation(
|
|
7170
|
+
op.deletedId,
|
|
7171
|
+
source
|
|
7172
|
+
);
|
|
7109
7173
|
if (deletedDelta) {
|
|
7110
7174
|
delta.push(deletedDelta);
|
|
7111
7175
|
}
|
|
7112
7176
|
const unacknowledgedOpId = this.#unacknowledgedSetOpIdAt(op.parentKey);
|
|
7113
7177
|
if (unacknowledgedOpId !== void 0 && unacknowledgedOpId !== op.opId) {
|
|
7114
|
-
return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
|
|
7178
|
+
return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta, source), reverse: [] };
|
|
7115
7179
|
}
|
|
7116
7180
|
const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey);
|
|
7117
7181
|
const existingItem = this.#items.find((item) => item._id === op.id);
|
|
7118
7182
|
if (existingItem !== void 0) {
|
|
7119
7183
|
if (existingItem._parentKey === op.parentKey) {
|
|
7120
7184
|
return {
|
|
7121
|
-
modified: delta.length > 0 ? makeUpdate(this, delta) : false,
|
|
7185
|
+
modified: delta.length > 0 ? makeUpdate(this, delta, source) : false,
|
|
7122
7186
|
reverse: []
|
|
7123
7187
|
};
|
|
7124
7188
|
}
|
|
@@ -7136,7 +7200,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7136
7200
|
delta.push(moveDelta(prevIndex, newIndex, existingItem));
|
|
7137
7201
|
}
|
|
7138
7202
|
return {
|
|
7139
|
-
modified: delta.length > 0 ? makeUpdate(this, delta) : false,
|
|
7203
|
+
modified: delta.length > 0 ? makeUpdate(this, delta, source) : false,
|
|
7140
7204
|
reverse: []
|
|
7141
7205
|
};
|
|
7142
7206
|
} else {
|
|
@@ -7146,11 +7210,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7146
7210
|
this.#implicitlyDeletedItems.delete(orphan);
|
|
7147
7211
|
const recreatedItemIndex = this.#insert(orphan);
|
|
7148
7212
|
return {
|
|
7149
|
-
modified: makeUpdate(
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7213
|
+
modified: makeUpdate(
|
|
7214
|
+
this,
|
|
7215
|
+
[
|
|
7216
|
+
// If there is an item at this position, update is a set, else it's an insert
|
|
7217
|
+
indexOfItemWithSamePosition === -1 ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan),
|
|
7218
|
+
...delta
|
|
7219
|
+
],
|
|
7220
|
+
source
|
|
7221
|
+
),
|
|
7154
7222
|
reverse: []
|
|
7155
7223
|
};
|
|
7156
7224
|
} else {
|
|
@@ -7165,11 +7233,15 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7165
7233
|
op.parentKey
|
|
7166
7234
|
);
|
|
7167
7235
|
return {
|
|
7168
|
-
modified: makeUpdate(
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7236
|
+
modified: makeUpdate(
|
|
7237
|
+
this,
|
|
7238
|
+
[
|
|
7239
|
+
// If there is an item at this position, update is a set, else it's an insert
|
|
7240
|
+
indexOfItemWithSamePosition === -1 ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem),
|
|
7241
|
+
...delta
|
|
7242
|
+
],
|
|
7243
|
+
source
|
|
7244
|
+
),
|
|
7173
7245
|
reverse: []
|
|
7174
7246
|
};
|
|
7175
7247
|
}
|
|
@@ -7178,7 +7250,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7178
7250
|
/**
|
|
7179
7251
|
* Returns the update delta of the deletion or null
|
|
7180
7252
|
*/
|
|
7181
|
-
#detachItemAssociatedToSetOperation(deletedId) {
|
|
7253
|
+
#detachItemAssociatedToSetOperation(deletedId, source) {
|
|
7182
7254
|
if (deletedId === void 0 || this._pool === void 0) {
|
|
7183
7255
|
return null;
|
|
7184
7256
|
}
|
|
@@ -7186,7 +7258,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7186
7258
|
if (deletedItem === void 0) {
|
|
7187
7259
|
return null;
|
|
7188
7260
|
}
|
|
7189
|
-
const result = this._detachChild(deletedItem);
|
|
7261
|
+
const result = this._detachChild(deletedItem, source);
|
|
7190
7262
|
if (result.modified === false) {
|
|
7191
7263
|
return null;
|
|
7192
7264
|
}
|
|
@@ -7204,10 +7276,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7204
7276
|
const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
|
|
7205
7277
|
const bumpDeltas = this.#bumpUnackedPushesAbove(key);
|
|
7206
7278
|
return {
|
|
7207
|
-
modified: makeUpdate(
|
|
7208
|
-
|
|
7209
|
-
...bumpDeltas
|
|
7210
|
-
|
|
7279
|
+
modified: makeUpdate(
|
|
7280
|
+
this,
|
|
7281
|
+
[insertDelta(newIndex, newItem), ...bumpDeltas],
|
|
7282
|
+
REMOTE
|
|
7283
|
+
),
|
|
7211
7284
|
reverse: []
|
|
7212
7285
|
};
|
|
7213
7286
|
}
|
|
@@ -7288,7 +7361,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7288
7361
|
}
|
|
7289
7362
|
return deltas;
|
|
7290
7363
|
}
|
|
7291
|
-
#applyInsertAck(op) {
|
|
7364
|
+
#applyInsertAck(op, source) {
|
|
7292
7365
|
const existingItem = this.#items.find((item) => item._id === op.id);
|
|
7293
7366
|
const key = asPos(op.parentKey);
|
|
7294
7367
|
const itemIndexAtPosition = this._indexOfPosition(key);
|
|
@@ -7310,9 +7383,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7310
7383
|
return { modified: false };
|
|
7311
7384
|
}
|
|
7312
7385
|
return {
|
|
7313
|
-
modified: makeUpdate(
|
|
7314
|
-
|
|
7315
|
-
|
|
7386
|
+
modified: makeUpdate(
|
|
7387
|
+
this,
|
|
7388
|
+
[moveDelta(oldPositionIndex, newIndex, existingItem)],
|
|
7389
|
+
source
|
|
7390
|
+
),
|
|
7316
7391
|
reverse: []
|
|
7317
7392
|
};
|
|
7318
7393
|
}
|
|
@@ -7324,7 +7399,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7324
7399
|
this.#insert(orphan);
|
|
7325
7400
|
const newIndex = this._indexOfPosition(key);
|
|
7326
7401
|
return {
|
|
7327
|
-
modified: makeUpdate(this, [insertDelta(newIndex, orphan)]),
|
|
7402
|
+
modified: makeUpdate(this, [insertDelta(newIndex, orphan)], source),
|
|
7328
7403
|
reverse: []
|
|
7329
7404
|
};
|
|
7330
7405
|
} else {
|
|
@@ -7333,13 +7408,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7333
7408
|
}
|
|
7334
7409
|
const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
|
|
7335
7410
|
return {
|
|
7336
|
-
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
7411
|
+
modified: makeUpdate(this, [insertDelta(newIndex, newItem)], source),
|
|
7337
7412
|
reverse: []
|
|
7338
7413
|
};
|
|
7339
7414
|
}
|
|
7340
7415
|
}
|
|
7341
7416
|
}
|
|
7342
|
-
#
|
|
7417
|
+
#applyLocalInsert(op, source) {
|
|
7343
7418
|
const { id, parentKey: key } = op;
|
|
7344
7419
|
const child = creationOpToLiveNode(op);
|
|
7345
7420
|
if (_optionalChain([this, 'access', _151 => _151._pool, 'optionalAccess', _152 => _152.getNode, 'call', _153 => _153(id)]) !== void 0) {
|
|
@@ -7358,11 +7433,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7358
7433
|
this.#insert(child);
|
|
7359
7434
|
const newIndex = this._indexOfPosition(newKey);
|
|
7360
7435
|
return {
|
|
7361
|
-
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
7436
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)], source),
|
|
7362
7437
|
reverse: [{ type: OpCode.DELETE_CRDT, id }]
|
|
7363
7438
|
};
|
|
7364
7439
|
}
|
|
7365
|
-
#
|
|
7440
|
+
#applyLocalSet(op, source) {
|
|
7366
7441
|
const { id, parentKey: key } = op;
|
|
7367
7442
|
const child = creationOpToLiveNode(op);
|
|
7368
7443
|
if (_optionalChain([this, 'access', _162 => _162._pool, 'optionalAccess', _163 => _163.getNode, 'call', _164 => _164(id)]) !== void 0) {
|
|
@@ -7384,46 +7459,48 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7384
7459
|
);
|
|
7385
7460
|
const delta = [setDelta(indexOfItemWithSameKey, child)];
|
|
7386
7461
|
const deletedDelta = this.#detachItemAssociatedToSetOperation(
|
|
7387
|
-
op.deletedId
|
|
7462
|
+
op.deletedId,
|
|
7463
|
+
source
|
|
7388
7464
|
);
|
|
7389
7465
|
if (deletedDelta) {
|
|
7390
7466
|
delta.push(deletedDelta);
|
|
7391
7467
|
}
|
|
7392
7468
|
return {
|
|
7393
|
-
modified: makeUpdate(this, delta),
|
|
7469
|
+
modified: makeUpdate(this, delta, source),
|
|
7394
7470
|
reverse
|
|
7395
7471
|
};
|
|
7396
7472
|
} else {
|
|
7397
7473
|
this.#insert(child);
|
|
7398
|
-
this.#detachItemAssociatedToSetOperation(op.deletedId);
|
|
7474
|
+
this.#detachItemAssociatedToSetOperation(op.deletedId, source);
|
|
7399
7475
|
const newIndex = this._indexOfPosition(newKey);
|
|
7400
7476
|
return {
|
|
7401
7477
|
reverse: [{ type: OpCode.DELETE_CRDT, id }],
|
|
7402
|
-
modified: makeUpdate(this, [insertDelta(newIndex, child)])
|
|
7478
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)], source)
|
|
7403
7479
|
};
|
|
7404
7480
|
}
|
|
7405
7481
|
}
|
|
7406
7482
|
/** @internal */
|
|
7407
|
-
_attachChild(op,
|
|
7483
|
+
_attachChild(op, opSource) {
|
|
7484
|
+
const source = toUpdateSource(opSource);
|
|
7408
7485
|
if (this._pool === void 0) {
|
|
7409
7486
|
throw new Error("Can't attach child if managed pool is not present");
|
|
7410
7487
|
}
|
|
7411
7488
|
let result;
|
|
7412
7489
|
if (op.intent === "set") {
|
|
7413
|
-
if (
|
|
7414
|
-
result = this.#
|
|
7415
|
-
} else if (
|
|
7416
|
-
result = this.#applySetAck(op);
|
|
7490
|
+
if (opSource.origin === "remote") {
|
|
7491
|
+
result = this.#applyRemoteSet(op);
|
|
7492
|
+
} else if (!opSource.optimistic) {
|
|
7493
|
+
result = this.#applySetAck(op, source);
|
|
7417
7494
|
} else {
|
|
7418
|
-
result = this.#
|
|
7495
|
+
result = this.#applyLocalSet(op, source);
|
|
7419
7496
|
}
|
|
7420
7497
|
} else {
|
|
7421
|
-
if (
|
|
7498
|
+
if (opSource.origin === "remote") {
|
|
7422
7499
|
result = this.#applyRemoteInsert(op);
|
|
7423
|
-
} else if (
|
|
7424
|
-
result = this.#applyInsertAck(op);
|
|
7500
|
+
} else if (!opSource.optimistic) {
|
|
7501
|
+
result = this.#applyInsertAck(op, source);
|
|
7425
7502
|
} else {
|
|
7426
|
-
result = this.#
|
|
7503
|
+
result = this.#applyLocalInsert(op, source);
|
|
7427
7504
|
}
|
|
7428
7505
|
}
|
|
7429
7506
|
if (result.modified !== false) {
|
|
@@ -7432,7 +7509,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7432
7509
|
return result;
|
|
7433
7510
|
}
|
|
7434
7511
|
/** @internal */
|
|
7435
|
-
_detachChild(child) {
|
|
7512
|
+
_detachChild(child, source) {
|
|
7436
7513
|
if (child) {
|
|
7437
7514
|
const parentKey = nn(child._parentKey);
|
|
7438
7515
|
const reverse = child._toOps(nn(this._id), parentKey);
|
|
@@ -7447,19 +7524,23 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7447
7524
|
this.invalidate();
|
|
7448
7525
|
child._detach();
|
|
7449
7526
|
return {
|
|
7450
|
-
modified: makeUpdate(
|
|
7527
|
+
modified: makeUpdate(
|
|
7528
|
+
this,
|
|
7529
|
+
[deleteDelta(indexToDelete, previousNode)],
|
|
7530
|
+
source
|
|
7531
|
+
),
|
|
7451
7532
|
reverse
|
|
7452
7533
|
};
|
|
7453
7534
|
}
|
|
7454
7535
|
return { modified: false };
|
|
7455
7536
|
}
|
|
7456
|
-
#
|
|
7537
|
+
#applyRemoteSetChildKey(newKey, child) {
|
|
7457
7538
|
if (this.#implicitlyDeletedItems.has(child)) {
|
|
7458
7539
|
this.#implicitlyDeletedItems.delete(child);
|
|
7459
7540
|
child._setParentLink(this, newKey);
|
|
7460
7541
|
const newIndex = this.#insert(child);
|
|
7461
7542
|
return {
|
|
7462
|
-
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
7543
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)], REMOTE),
|
|
7463
7544
|
reverse: []
|
|
7464
7545
|
};
|
|
7465
7546
|
}
|
|
@@ -7480,7 +7561,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7480
7561
|
};
|
|
7481
7562
|
}
|
|
7482
7563
|
return {
|
|
7483
|
-
modified: makeUpdate(
|
|
7564
|
+
modified: makeUpdate(
|
|
7565
|
+
this,
|
|
7566
|
+
[moveDelta(previousIndex, newIndex, child)],
|
|
7567
|
+
REMOTE
|
|
7568
|
+
),
|
|
7484
7569
|
reverse: []
|
|
7485
7570
|
};
|
|
7486
7571
|
} else {
|
|
@@ -7497,12 +7582,16 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7497
7582
|
};
|
|
7498
7583
|
}
|
|
7499
7584
|
return {
|
|
7500
|
-
modified: makeUpdate(
|
|
7585
|
+
modified: makeUpdate(
|
|
7586
|
+
this,
|
|
7587
|
+
[moveDelta(previousIndex, newIndex, child)],
|
|
7588
|
+
REMOTE
|
|
7589
|
+
),
|
|
7501
7590
|
reverse: []
|
|
7502
7591
|
};
|
|
7503
7592
|
}
|
|
7504
7593
|
}
|
|
7505
|
-
#applySetChildKeyAck(newKey, child) {
|
|
7594
|
+
#applySetChildKeyAck(newKey, child, source) {
|
|
7506
7595
|
const previousKey = nn(child._parentKey);
|
|
7507
7596
|
if (this.#implicitlyDeletedItems.has(child)) {
|
|
7508
7597
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
@@ -7521,7 +7610,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7521
7610
|
child._setParentLink(this, newKey);
|
|
7522
7611
|
const newIndex = this.#insert(child);
|
|
7523
7612
|
return {
|
|
7524
|
-
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
7613
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)], source),
|
|
7525
7614
|
reverse: []
|
|
7526
7615
|
};
|
|
7527
7616
|
} else {
|
|
@@ -7549,15 +7638,17 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7549
7638
|
};
|
|
7550
7639
|
} else {
|
|
7551
7640
|
return {
|
|
7552
|
-
modified: makeUpdate(
|
|
7553
|
-
|
|
7554
|
-
|
|
7641
|
+
modified: makeUpdate(
|
|
7642
|
+
this,
|
|
7643
|
+
[moveDelta(previousIndex, newIndex, child)],
|
|
7644
|
+
source
|
|
7645
|
+
),
|
|
7555
7646
|
reverse: []
|
|
7556
7647
|
};
|
|
7557
7648
|
}
|
|
7558
7649
|
}
|
|
7559
7650
|
}
|
|
7560
|
-
#
|
|
7651
|
+
#applyLocalSetChildKey(newKey, child, source) {
|
|
7561
7652
|
const previousKey = nn(child._parentKey);
|
|
7562
7653
|
const previousIndex = this.#items.findIndex((item) => item === child);
|
|
7563
7654
|
const existingItemIndex = this._indexOfPosition(newKey);
|
|
@@ -7576,7 +7667,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7576
7667
|
};
|
|
7577
7668
|
}
|
|
7578
7669
|
return {
|
|
7579
|
-
modified: makeUpdate(
|
|
7670
|
+
modified: makeUpdate(
|
|
7671
|
+
this,
|
|
7672
|
+
[moveDelta(previousIndex, newIndex, child)],
|
|
7673
|
+
source
|
|
7674
|
+
),
|
|
7580
7675
|
reverse: [
|
|
7581
7676
|
{
|
|
7582
7677
|
type: OpCode.SET_PARENT_KEY,
|
|
@@ -7587,18 +7682,19 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7587
7682
|
};
|
|
7588
7683
|
}
|
|
7589
7684
|
/** @internal */
|
|
7590
|
-
_setChildKey(newKey, child,
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7685
|
+
_setChildKey(newKey, child, opSource) {
|
|
7686
|
+
const source = toUpdateSource(opSource);
|
|
7687
|
+
if (opSource.origin === "remote") {
|
|
7688
|
+
return this.#applyRemoteSetChildKey(newKey, child);
|
|
7689
|
+
} else if (!opSource.optimistic) {
|
|
7690
|
+
return this.#applySetChildKeyAck(newKey, child, source);
|
|
7595
7691
|
} else {
|
|
7596
|
-
return this.#
|
|
7692
|
+
return this.#applyLocalSetChildKey(newKey, child, source);
|
|
7597
7693
|
}
|
|
7598
7694
|
}
|
|
7599
7695
|
/** @internal */
|
|
7600
|
-
_apply(op,
|
|
7601
|
-
return super._apply(op,
|
|
7696
|
+
_apply(op, source) {
|
|
7697
|
+
return super._apply(op, source);
|
|
7602
7698
|
}
|
|
7603
7699
|
/** @internal */
|
|
7604
7700
|
_serialize() {
|
|
@@ -7639,6 +7735,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7639
7735
|
* instead of resolving its position against the client's stale view.
|
|
7640
7736
|
*/
|
|
7641
7737
|
#injectAt(element, index, intent) {
|
|
7738
|
+
this._warnIfOrphaned();
|
|
7642
7739
|
_optionalChain([this, 'access', _181 => _181._pool, 'optionalAccess', _182 => _182.assertStorageIsWritable, 'call', _183 => _183()]);
|
|
7643
7740
|
if (index < 0 || index > this.#items.length) {
|
|
7644
7741
|
throw new Error(
|
|
@@ -7659,7 +7756,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7659
7756
|
intent === "push" ? addIntentToRootOp(ops, "push") : ops,
|
|
7660
7757
|
[{ type: OpCode.DELETE_CRDT, id }],
|
|
7661
7758
|
/* @__PURE__ */ new Map([
|
|
7662
|
-
[this._id, makeUpdate(this, [insertDelta(index, value)])]
|
|
7759
|
+
[this._id, makeUpdate(this, [insertDelta(index, value)], LOCAL_EDIT)]
|
|
7663
7760
|
])
|
|
7664
7761
|
);
|
|
7665
7762
|
}
|
|
@@ -7670,6 +7767,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7670
7767
|
* @param targetIndex The index where the element should be after moving.
|
|
7671
7768
|
*/
|
|
7672
7769
|
move(index, targetIndex) {
|
|
7770
|
+
this._warnIfOrphaned();
|
|
7673
7771
|
_optionalChain([this, 'access', _192 => _192._pool, 'optionalAccess', _193 => _193.assertStorageIsWritable, 'call', _194 => _194()]);
|
|
7674
7772
|
if (targetIndex < 0) {
|
|
7675
7773
|
throw new Error("targetIndex cannot be less than 0");
|
|
@@ -7700,7 +7798,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7700
7798
|
this.#updateItemPositionAt(index, position);
|
|
7701
7799
|
if (this._pool && this._id) {
|
|
7702
7800
|
const storageUpdates = /* @__PURE__ */ new Map([
|
|
7703
|
-
[
|
|
7801
|
+
[
|
|
7802
|
+
this._id,
|
|
7803
|
+
makeUpdate(this, [moveDelta(index, targetIndex, item)], LOCAL_EDIT)
|
|
7804
|
+
]
|
|
7704
7805
|
]);
|
|
7705
7806
|
this._pool.dispatch(
|
|
7706
7807
|
[
|
|
@@ -7727,6 +7828,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7727
7828
|
* @param index The index of the element to delete
|
|
7728
7829
|
*/
|
|
7729
7830
|
delete(index) {
|
|
7831
|
+
this._warnIfOrphaned();
|
|
7730
7832
|
_optionalChain([this, 'access', _203 => _203._pool, 'optionalAccess', _204 => _204.assertStorageIsWritable, 'call', _205 => _205()]);
|
|
7731
7833
|
if (index < 0 || index >= this.#items.length) {
|
|
7732
7834
|
throw new Error(
|
|
@@ -7743,7 +7845,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7743
7845
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
7744
7846
|
storageUpdates.set(
|
|
7745
7847
|
nn(this._id),
|
|
7746
|
-
makeUpdate(this, [deleteDelta(index, item)])
|
|
7848
|
+
makeUpdate(this, [deleteDelta(index, item)], LOCAL_EDIT)
|
|
7747
7849
|
);
|
|
7748
7850
|
this._pool.dispatch(
|
|
7749
7851
|
[
|
|
@@ -7760,6 +7862,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7760
7862
|
}
|
|
7761
7863
|
}
|
|
7762
7864
|
clear() {
|
|
7865
|
+
this._warnIfOrphaned();
|
|
7763
7866
|
_optionalChain([this, 'access', _206 => _206._pool, 'optionalAccess', _207 => _207.assertStorageIsWritable, 'call', _208 => _208()]);
|
|
7764
7867
|
if (this._pool) {
|
|
7765
7868
|
const ops = [];
|
|
@@ -7783,7 +7886,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7783
7886
|
this.#items.clear();
|
|
7784
7887
|
this.invalidate();
|
|
7785
7888
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
7786
|
-
storageUpdates.set(
|
|
7889
|
+
storageUpdates.set(
|
|
7890
|
+
nn(this._id),
|
|
7891
|
+
makeUpdate(this, updateDelta, LOCAL_EDIT)
|
|
7892
|
+
);
|
|
7787
7893
|
this._pool.dispatch(ops, reverseOps, storageUpdates);
|
|
7788
7894
|
} else {
|
|
7789
7895
|
for (const item of this.#items) {
|
|
@@ -7794,6 +7900,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7794
7900
|
}
|
|
7795
7901
|
}
|
|
7796
7902
|
set(index, item) {
|
|
7903
|
+
this._warnIfOrphaned();
|
|
7797
7904
|
_optionalChain([this, 'access', _209 => _209._pool, 'optionalAccess', _210 => _210.assertStorageIsWritable, 'call', _211 => _211()]);
|
|
7798
7905
|
if (index < 0 || index >= this.#items.length) {
|
|
7799
7906
|
throw new Error(
|
|
@@ -7813,7 +7920,10 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7813
7920
|
const id = this._pool.generateId();
|
|
7814
7921
|
value._attach(id, this._pool);
|
|
7815
7922
|
const storageUpdates = /* @__PURE__ */ new Map();
|
|
7816
|
-
storageUpdates.set(
|
|
7923
|
+
storageUpdates.set(
|
|
7924
|
+
this._id,
|
|
7925
|
+
makeUpdate(this, [setDelta(index, value)], LOCAL_EDIT)
|
|
7926
|
+
);
|
|
7817
7927
|
const ops = addIntentToRootOp(
|
|
7818
7928
|
value._toOpsWithOpId(this._id, position, this._pool),
|
|
7819
7929
|
"set",
|
|
@@ -7986,11 +8096,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
|
|
|
7986
8096
|
);
|
|
7987
8097
|
}
|
|
7988
8098
|
};
|
|
7989
|
-
function makeUpdate(liveList, deltaUpdates) {
|
|
8099
|
+
function makeUpdate(liveList, deltaUpdates, source) {
|
|
7990
8100
|
return {
|
|
7991
8101
|
node: liveList,
|
|
7992
8102
|
type: "LiveList",
|
|
7993
|
-
updates: deltaUpdates
|
|
8103
|
+
updates: deltaUpdates,
|
|
8104
|
+
source
|
|
7994
8105
|
};
|
|
7995
8106
|
}
|
|
7996
8107
|
function setDelta(index, item) {
|
|
@@ -8109,7 +8220,9 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8109
8220
|
if (this._pool.getNode(id) !== void 0) {
|
|
8110
8221
|
return { modified: false };
|
|
8111
8222
|
}
|
|
8112
|
-
if (source ===
|
|
8223
|
+
if (source.origin === "remote") {
|
|
8224
|
+
this.#unacknowledgedSet.delete(key);
|
|
8225
|
+
} else if (!source.optimistic) {
|
|
8113
8226
|
const lastUpdateOpId = this.#unacknowledgedSet.get(key);
|
|
8114
8227
|
if (lastUpdateOpId === opId) {
|
|
8115
8228
|
this.#unacknowledgedSet.delete(key);
|
|
@@ -8117,8 +8230,6 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8117
8230
|
} else if (lastUpdateOpId !== void 0) {
|
|
8118
8231
|
return { modified: false };
|
|
8119
8232
|
}
|
|
8120
|
-
} else if (source === 1 /* THEIRS */) {
|
|
8121
|
-
this.#unacknowledgedSet.delete(key);
|
|
8122
8233
|
}
|
|
8123
8234
|
const previousValue = this.#map.get(key);
|
|
8124
8235
|
let reverse;
|
|
@@ -8137,7 +8248,8 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8137
8248
|
modified: {
|
|
8138
8249
|
node: this,
|
|
8139
8250
|
type: "LiveMap",
|
|
8140
|
-
updates: { [key]: { type: "update" } }
|
|
8251
|
+
updates: { [key]: { type: "update" } },
|
|
8252
|
+
source: toUpdateSource(source)
|
|
8141
8253
|
},
|
|
8142
8254
|
reverse
|
|
8143
8255
|
};
|
|
@@ -8150,7 +8262,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8150
8262
|
}
|
|
8151
8263
|
}
|
|
8152
8264
|
/** @internal */
|
|
8153
|
-
_detachChild(child) {
|
|
8265
|
+
_detachChild(child, source) {
|
|
8154
8266
|
const id = nn(this._id);
|
|
8155
8267
|
const parentKey = nn(child._parentKey);
|
|
8156
8268
|
const reverse = child._toOps(id, parentKey);
|
|
@@ -8169,7 +8281,8 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8169
8281
|
type: "delete",
|
|
8170
8282
|
deletedItem: liveNodeToLson(child)
|
|
8171
8283
|
}
|
|
8172
|
-
}
|
|
8284
|
+
},
|
|
8285
|
+
source
|
|
8173
8286
|
};
|
|
8174
8287
|
return { modified: storageUpdate, reverse };
|
|
8175
8288
|
}
|
|
@@ -8202,6 +8315,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8202
8315
|
* @param value The value of the element to add. Should be serializable to JSON.
|
|
8203
8316
|
*/
|
|
8204
8317
|
set(key, value) {
|
|
8318
|
+
this._warnIfOrphaned();
|
|
8205
8319
|
_optionalChain([this, 'access', _216 => _216._pool, 'optionalAccess', _217 => _217.assertStorageIsWritable, 'call', _218 => _218()]);
|
|
8206
8320
|
const oldValue = this.#map.get(key);
|
|
8207
8321
|
if (oldValue) {
|
|
@@ -8218,7 +8332,8 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8218
8332
|
storageUpdates.set(this._id, {
|
|
8219
8333
|
node: this,
|
|
8220
8334
|
type: "LiveMap",
|
|
8221
|
-
updates: { [key]: { type: "update" } }
|
|
8335
|
+
updates: { [key]: { type: "update" } },
|
|
8336
|
+
source: LOCAL_EDIT
|
|
8222
8337
|
});
|
|
8223
8338
|
const ops = item._toOpsWithOpId(this._id, key, this._pool);
|
|
8224
8339
|
this.#unacknowledgedSet.set(key, nn(ops[0].opId));
|
|
@@ -8248,6 +8363,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8248
8363
|
* @returns true if an element existed and has been removed, or false if the element does not exist.
|
|
8249
8364
|
*/
|
|
8250
8365
|
delete(key) {
|
|
8366
|
+
this._warnIfOrphaned();
|
|
8251
8367
|
_optionalChain([this, 'access', _219 => _219._pool, 'optionalAccess', _220 => _220.assertStorageIsWritable, 'call', _221 => _221()]);
|
|
8252
8368
|
const item = this.#map.get(key);
|
|
8253
8369
|
if (item === void 0) {
|
|
@@ -8267,7 +8383,8 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
|
|
|
8267
8383
|
type: "delete",
|
|
8268
8384
|
deletedItem: liveNodeToLson(item)
|
|
8269
8385
|
}
|
|
8270
|
-
}
|
|
8386
|
+
},
|
|
8387
|
+
source: LOCAL_EDIT
|
|
8271
8388
|
});
|
|
8272
8389
|
this._pool.dispatch(
|
|
8273
8390
|
[
|
|
@@ -8632,7 +8749,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8632
8749
|
}
|
|
8633
8750
|
return { modified: false };
|
|
8634
8751
|
}
|
|
8635
|
-
if (source ===
|
|
8752
|
+
if (source.origin === "local" && source.optimistic) {
|
|
8636
8753
|
this.#unackedOpsByKey.set(key, nn(opId));
|
|
8637
8754
|
} else if (this.#unackedOpsByKey.get(key) === void 0) {
|
|
8638
8755
|
} else if (this.#unackedOpsByKey.get(key) === opId) {
|
|
@@ -8670,12 +8787,13 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8670
8787
|
modified: {
|
|
8671
8788
|
node: this,
|
|
8672
8789
|
type: "LiveObject",
|
|
8673
|
-
updates: { [key]: { type: "update" } }
|
|
8790
|
+
updates: { [key]: { type: "update" } },
|
|
8791
|
+
source: toUpdateSource(source)
|
|
8674
8792
|
}
|
|
8675
8793
|
};
|
|
8676
8794
|
}
|
|
8677
8795
|
/** @internal */
|
|
8678
|
-
_detachChild(child) {
|
|
8796
|
+
_detachChild(child, source) {
|
|
8679
8797
|
if (child) {
|
|
8680
8798
|
const id = nn(this._id);
|
|
8681
8799
|
const parentKey = nn(child._parentKey);
|
|
@@ -8693,7 +8811,8 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8693
8811
|
type: "LiveObject",
|
|
8694
8812
|
updates: {
|
|
8695
8813
|
[parentKey]: { type: "delete", deletedItem }
|
|
8696
|
-
}
|
|
8814
|
+
},
|
|
8815
|
+
source
|
|
8697
8816
|
};
|
|
8698
8817
|
return { modified: storageUpdate, reverse };
|
|
8699
8818
|
}
|
|
@@ -8709,13 +8828,13 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8709
8828
|
}
|
|
8710
8829
|
}
|
|
8711
8830
|
/** @internal */
|
|
8712
|
-
_apply(op,
|
|
8831
|
+
_apply(op, source) {
|
|
8713
8832
|
if (op.type === OpCode.UPDATE_OBJECT) {
|
|
8714
|
-
return this.#applyUpdate(op,
|
|
8833
|
+
return this.#applyUpdate(op, source);
|
|
8715
8834
|
} else if (op.type === OpCode.DELETE_OBJECT_KEY) {
|
|
8716
|
-
return this.#applyDeleteObjectKey(op,
|
|
8835
|
+
return this.#applyDeleteObjectKey(op, source);
|
|
8717
8836
|
}
|
|
8718
|
-
return super._apply(op,
|
|
8837
|
+
return super._apply(op, source);
|
|
8719
8838
|
}
|
|
8720
8839
|
/** @internal */
|
|
8721
8840
|
_serialize() {
|
|
@@ -8739,7 +8858,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8739
8858
|
};
|
|
8740
8859
|
}
|
|
8741
8860
|
}
|
|
8742
|
-
#applyUpdate(op,
|
|
8861
|
+
#applyUpdate(op, source) {
|
|
8743
8862
|
let isModified = false;
|
|
8744
8863
|
const id = nn(this._id);
|
|
8745
8864
|
const reverse = [];
|
|
@@ -8767,7 +8886,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8767
8886
|
if (value === void 0) {
|
|
8768
8887
|
continue;
|
|
8769
8888
|
}
|
|
8770
|
-
if (
|
|
8889
|
+
if (source.origin === "local" && source.optimistic) {
|
|
8771
8890
|
this.#unackedOpsByKey.set(key, nn(op.opId));
|
|
8772
8891
|
} else if (this.#unackedOpsByKey.get(key) === void 0) {
|
|
8773
8892
|
isModified = true;
|
|
@@ -8794,18 +8913,19 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8794
8913
|
modified: {
|
|
8795
8914
|
node: this,
|
|
8796
8915
|
type: "LiveObject",
|
|
8797
|
-
updates: updateDelta
|
|
8916
|
+
updates: updateDelta,
|
|
8917
|
+
source: toUpdateSource(source)
|
|
8798
8918
|
},
|
|
8799
8919
|
reverse
|
|
8800
8920
|
} : { modified: false };
|
|
8801
8921
|
}
|
|
8802
|
-
#applyDeleteObjectKey(op,
|
|
8922
|
+
#applyDeleteObjectKey(op, source) {
|
|
8803
8923
|
const key = op.key;
|
|
8804
8924
|
const oldValue = this.#synced.get(key);
|
|
8805
8925
|
if (oldValue === void 0) {
|
|
8806
8926
|
return { modified: false };
|
|
8807
8927
|
}
|
|
8808
|
-
if (!
|
|
8928
|
+
if (!(source.origin === "local" && source.optimistic) && this.#unackedOpsByKey.get(key) !== void 0) {
|
|
8809
8929
|
return { modified: false };
|
|
8810
8930
|
}
|
|
8811
8931
|
const id = nn(this._id);
|
|
@@ -8831,7 +8951,8 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8831
8951
|
type: "LiveObject",
|
|
8832
8952
|
updates: {
|
|
8833
8953
|
[op.key]: { type: "delete", deletedItem: oldValue }
|
|
8834
|
-
}
|
|
8954
|
+
},
|
|
8955
|
+
source: toUpdateSource(source)
|
|
8835
8956
|
},
|
|
8836
8957
|
reverse
|
|
8837
8958
|
};
|
|
@@ -8862,6 +8983,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8862
8983
|
* Caveat: this method will not add changes to the undo/redo stack.
|
|
8863
8984
|
*/
|
|
8864
8985
|
setLocal(key, value) {
|
|
8986
|
+
this._warnIfOrphaned();
|
|
8865
8987
|
_optionalChain([this, 'access', _222 => _222._pool, 'optionalAccess', _223 => _223.assertStorageIsWritable, 'call', _224 => _224()]);
|
|
8866
8988
|
const deleteResult = this.#prepareDelete(key);
|
|
8867
8989
|
this.#local.set(key, value);
|
|
@@ -8877,7 +8999,8 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8877
8999
|
updates: {
|
|
8878
9000
|
..._optionalChain([existing, 'optionalAccess', _228 => _228.updates]),
|
|
8879
9001
|
[key]: { type: "update" }
|
|
8880
|
-
}
|
|
9002
|
+
},
|
|
9003
|
+
source: LOCAL_EDIT
|
|
8881
9004
|
});
|
|
8882
9005
|
this._pool.dispatch(ops, reverse, storageUpdates);
|
|
8883
9006
|
}
|
|
@@ -8895,6 +9018,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8895
9018
|
* #synced or pool/id are unavailable. Does NOT dispatch.
|
|
8896
9019
|
*/
|
|
8897
9020
|
#prepareDelete(key) {
|
|
9021
|
+
this._warnIfOrphaned();
|
|
8898
9022
|
_optionalChain([this, 'access', _229 => _229._pool, 'optionalAccess', _230 => _230.assertStorageIsWritable, 'call', _231 => _231()]);
|
|
8899
9023
|
const k = key;
|
|
8900
9024
|
if (this.#local.has(k) && !this.#synced.has(k)) {
|
|
@@ -8911,7 +9035,8 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8911
9035
|
type: "delete",
|
|
8912
9036
|
deletedItem: oldValue2
|
|
8913
9037
|
}
|
|
8914
|
-
}
|
|
9038
|
+
},
|
|
9039
|
+
source: LOCAL_EDIT
|
|
8915
9040
|
});
|
|
8916
9041
|
return [[], [], storageUpdates2];
|
|
8917
9042
|
}
|
|
@@ -8959,7 +9084,8 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8959
9084
|
type: "LiveObject",
|
|
8960
9085
|
updates: {
|
|
8961
9086
|
[key]: { type: "delete", deletedItem: oldValue }
|
|
8962
|
-
}
|
|
9087
|
+
},
|
|
9088
|
+
source: LOCAL_EDIT
|
|
8963
9089
|
});
|
|
8964
9090
|
return [ops, reverse, storageUpdates];
|
|
8965
9091
|
}
|
|
@@ -8979,6 +9105,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
8979
9105
|
* @param patch The object used to overrides properties
|
|
8980
9106
|
*/
|
|
8981
9107
|
update(patch) {
|
|
9108
|
+
this._warnIfOrphaned();
|
|
8982
9109
|
_optionalChain([this, 'access', _235 => _235._pool, 'optionalAccess', _236 => _236.assertStorageIsWritable, 'call', _237 => _237()]);
|
|
8983
9110
|
if (_LiveObject.detectLargeObjects) {
|
|
8984
9111
|
const data = {};
|
|
@@ -9097,7 +9224,8 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
9097
9224
|
storageUpdates.set(this._id, {
|
|
9098
9225
|
node: this,
|
|
9099
9226
|
type: "LiveObject",
|
|
9100
|
-
updates: updateDelta
|
|
9227
|
+
updates: updateDelta,
|
|
9228
|
+
source: LOCAL_EDIT
|
|
9101
9229
|
});
|
|
9102
9230
|
this._pool.dispatch(ops, reverseOps, storageUpdates);
|
|
9103
9231
|
}
|
|
@@ -9179,123 +9307,1313 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
|
|
|
9179
9307
|
}
|
|
9180
9308
|
}, _class2.__initStatic(), _class2);
|
|
9181
9309
|
|
|
9182
|
-
// src/crdts/
|
|
9183
|
-
function
|
|
9184
|
-
|
|
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");
|
|
9200
|
-
}
|
|
9201
|
-
}
|
|
9202
|
-
function isSameNodeOrChildOf(node, parent) {
|
|
9203
|
-
if (node === parent) {
|
|
9310
|
+
// src/crdts/liveTextOps.ts
|
|
9311
|
+
function attributesEqual(left, right) {
|
|
9312
|
+
if (left === right) {
|
|
9204
9313
|
return true;
|
|
9205
9314
|
}
|
|
9206
|
-
if (
|
|
9207
|
-
return
|
|
9315
|
+
if (left === void 0 || right === void 0) {
|
|
9316
|
+
return false;
|
|
9208
9317
|
}
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9318
|
+
const leftKeys = Object.keys(left);
|
|
9319
|
+
const rightKeys = Object.keys(right);
|
|
9320
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
9321
|
+
return false;
|
|
9322
|
+
}
|
|
9323
|
+
for (const key of leftKeys) {
|
|
9324
|
+
if (left[key] !== right[key]) {
|
|
9325
|
+
return false;
|
|
9217
9326
|
}
|
|
9218
|
-
});
|
|
9219
|
-
return LiveObject._fromItems(nodes, pool);
|
|
9220
|
-
}
|
|
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
9327
|
}
|
|
9328
|
+
return true;
|
|
9235
9329
|
}
|
|
9236
|
-
function
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9330
|
+
function cloneAttributes(attributes) {
|
|
9331
|
+
return attributes === void 0 ? void 0 : freeze({ ...attributes });
|
|
9332
|
+
}
|
|
9333
|
+
function normalizeSegments(segments) {
|
|
9334
|
+
const normalized = [];
|
|
9335
|
+
for (const segment of segments) {
|
|
9336
|
+
if (segment.text.length === 0) {
|
|
9337
|
+
continue;
|
|
9338
|
+
}
|
|
9339
|
+
const last = normalized.at(-1);
|
|
9340
|
+
const attributes = cloneAttributes(segment.attributes);
|
|
9341
|
+
if (last !== void 0 && attributesEqual(last.attributes, attributes)) {
|
|
9342
|
+
last.text += segment.text;
|
|
9343
|
+
} else {
|
|
9344
|
+
normalized.push({ text: segment.text, attributes });
|
|
9345
|
+
}
|
|
9249
9346
|
}
|
|
9347
|
+
return normalized;
|
|
9250
9348
|
}
|
|
9251
|
-
function
|
|
9252
|
-
return
|
|
9349
|
+
function dataToSegments(data) {
|
|
9350
|
+
return normalizeSegments(
|
|
9351
|
+
data.map(([text, attributes]) => ({
|
|
9352
|
+
text,
|
|
9353
|
+
attributes
|
|
9354
|
+
}))
|
|
9355
|
+
);
|
|
9253
9356
|
}
|
|
9254
|
-
function
|
|
9255
|
-
return
|
|
9357
|
+
function segmentsToData(segments) {
|
|
9358
|
+
return segments.map(
|
|
9359
|
+
(segment) => segment.attributes === void 0 ? [segment.text] : [segment.text, { ...segment.attributes }]
|
|
9360
|
+
);
|
|
9256
9361
|
}
|
|
9257
|
-
function
|
|
9258
|
-
return
|
|
9362
|
+
function textLength(segments) {
|
|
9363
|
+
return segments.reduce((sum, segment) => sum + segment.text.length, 0);
|
|
9259
9364
|
}
|
|
9260
|
-
function
|
|
9261
|
-
|
|
9365
|
+
function splitSegmentsAt(segments, index) {
|
|
9366
|
+
const result = [];
|
|
9367
|
+
let offset = 0;
|
|
9368
|
+
for (const segment of segments) {
|
|
9369
|
+
const end = offset + segment.text.length;
|
|
9370
|
+
if (index > offset && index < end) {
|
|
9371
|
+
const before2 = segment.text.slice(0, index - offset);
|
|
9372
|
+
const after2 = segment.text.slice(index - offset);
|
|
9373
|
+
result.push({ text: before2, attributes: segment.attributes });
|
|
9374
|
+
result.push({ text: after2, attributes: segment.attributes });
|
|
9375
|
+
} else {
|
|
9376
|
+
result.push({ text: segment.text, attributes: segment.attributes });
|
|
9377
|
+
}
|
|
9378
|
+
offset = end;
|
|
9379
|
+
}
|
|
9380
|
+
return result;
|
|
9262
9381
|
}
|
|
9263
|
-
function
|
|
9264
|
-
|
|
9382
|
+
function clipRange(index, length, contentLength) {
|
|
9383
|
+
const clippedIndex = Math.max(0, Math.min(index, contentLength));
|
|
9384
|
+
const clippedEnd = Math.max(
|
|
9385
|
+
clippedIndex,
|
|
9386
|
+
Math.min(index + length, contentLength)
|
|
9387
|
+
);
|
|
9388
|
+
return { index: clippedIndex, length: clippedEnd - clippedIndex };
|
|
9265
9389
|
}
|
|
9266
|
-
function
|
|
9267
|
-
|
|
9390
|
+
function isInSurrogatePair(text, index) {
|
|
9391
|
+
const previous = text.charCodeAt(index - 1);
|
|
9392
|
+
const next = text.charCodeAt(index);
|
|
9393
|
+
return previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343;
|
|
9268
9394
|
}
|
|
9269
|
-
function
|
|
9270
|
-
|
|
9395
|
+
function clipIndexToCodePointBoundary(text, index) {
|
|
9396
|
+
const clippedIndex = Math.max(0, Math.min(index, text.length));
|
|
9397
|
+
return isInSurrogatePair(text, clippedIndex) ? clippedIndex - 1 : clippedIndex;
|
|
9271
9398
|
}
|
|
9272
|
-
function
|
|
9273
|
-
|
|
9399
|
+
function clipRangeToCodePointBoundaries(text, index, length) {
|
|
9400
|
+
const clipped = clipRange(index, length, text.length);
|
|
9401
|
+
if (clipped.length === 0) {
|
|
9402
|
+
return {
|
|
9403
|
+
index: clipIndexToCodePointBoundary(text, clipped.index),
|
|
9404
|
+
length: 0
|
|
9405
|
+
};
|
|
9406
|
+
}
|
|
9407
|
+
const clippedEnd = clipped.index + clipped.length;
|
|
9408
|
+
const normalizedIndex = isInSurrogatePair(text, clipped.index) ? clipped.index - 1 : clipped.index;
|
|
9409
|
+
const normalizedEnd = isInSurrogatePair(text, clippedEnd) ? clippedEnd + 1 : clippedEnd;
|
|
9410
|
+
return {
|
|
9411
|
+
index: normalizedIndex,
|
|
9412
|
+
length: normalizedEnd - normalizedIndex
|
|
9413
|
+
};
|
|
9274
9414
|
}
|
|
9275
|
-
function
|
|
9276
|
-
if (
|
|
9277
|
-
return
|
|
9278
|
-
}
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9415
|
+
function applyInsert(segments, index, text, attributes) {
|
|
9416
|
+
if (text.length === 0) {
|
|
9417
|
+
return normalizeSegments(segments);
|
|
9418
|
+
}
|
|
9419
|
+
const split = splitSegmentsAt(segments, index);
|
|
9420
|
+
const result = [];
|
|
9421
|
+
let offset = 0;
|
|
9422
|
+
let inserted = false;
|
|
9423
|
+
for (const segment of split) {
|
|
9424
|
+
if (!inserted && offset === index) {
|
|
9425
|
+
result.push({ text, attributes });
|
|
9426
|
+
inserted = true;
|
|
9427
|
+
}
|
|
9428
|
+
result.push(segment);
|
|
9429
|
+
offset += segment.text.length;
|
|
9282
9430
|
}
|
|
9431
|
+
if (!inserted) {
|
|
9432
|
+
result.push({ text, attributes });
|
|
9433
|
+
}
|
|
9434
|
+
return normalizeSegments(result);
|
|
9283
9435
|
}
|
|
9284
|
-
function
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9436
|
+
function extractDeletedSegments(segments, index, length) {
|
|
9437
|
+
const split = splitSegmentsAt(
|
|
9438
|
+
splitSegmentsAt(segments, index),
|
|
9439
|
+
index + length
|
|
9440
|
+
);
|
|
9441
|
+
const deleted = [];
|
|
9442
|
+
let offset = 0;
|
|
9443
|
+
for (const segment of split) {
|
|
9444
|
+
const end = offset + segment.text.length;
|
|
9445
|
+
if (offset >= index && end <= index + length) {
|
|
9446
|
+
deleted.push({
|
|
9447
|
+
text: segment.text,
|
|
9448
|
+
attributes: segment.attributes
|
|
9449
|
+
});
|
|
9450
|
+
}
|
|
9451
|
+
offset = end;
|
|
9289
9452
|
}
|
|
9453
|
+
return normalizeSegments(deleted);
|
|
9290
9454
|
}
|
|
9291
|
-
function
|
|
9292
|
-
const
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9455
|
+
function applyDelete(segments, index, length) {
|
|
9456
|
+
const deletedSegments = extractDeletedSegments(segments, index, length);
|
|
9457
|
+
const split = splitSegmentsAt(
|
|
9458
|
+
splitSegmentsAt(segments, index),
|
|
9459
|
+
index + length
|
|
9460
|
+
);
|
|
9461
|
+
const result = [];
|
|
9462
|
+
let offset = 0;
|
|
9463
|
+
let deletedText = "";
|
|
9464
|
+
for (const segment of split) {
|
|
9465
|
+
const end = offset + segment.text.length;
|
|
9466
|
+
if (offset >= index && end <= index + length) {
|
|
9467
|
+
deletedText += segment.text;
|
|
9468
|
+
} else {
|
|
9469
|
+
result.push(segment);
|
|
9470
|
+
}
|
|
9471
|
+
offset = end;
|
|
9472
|
+
}
|
|
9473
|
+
return {
|
|
9474
|
+
segments: normalizeSegments(result),
|
|
9475
|
+
deletedText,
|
|
9476
|
+
deletedSegments
|
|
9477
|
+
};
|
|
9478
|
+
}
|
|
9479
|
+
function applyFormat(segments, index, length, attributes) {
|
|
9480
|
+
const split = splitSegmentsAt(
|
|
9481
|
+
splitSegmentsAt(segments, index),
|
|
9482
|
+
index + length
|
|
9483
|
+
);
|
|
9484
|
+
const result = [];
|
|
9485
|
+
let offset = 0;
|
|
9486
|
+
for (const segment of split) {
|
|
9487
|
+
const end = offset + segment.text.length;
|
|
9488
|
+
if (offset >= index && end <= index + length) {
|
|
9489
|
+
const nextAttributes = {
|
|
9490
|
+
..._nullishCoalesce(segment.attributes, () => ( {}))
|
|
9491
|
+
};
|
|
9492
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
9493
|
+
if (value === null) {
|
|
9494
|
+
delete nextAttributes[key];
|
|
9495
|
+
} else {
|
|
9496
|
+
nextAttributes[key] = value;
|
|
9497
|
+
}
|
|
9498
|
+
}
|
|
9499
|
+
result.push({
|
|
9500
|
+
text: segment.text,
|
|
9501
|
+
attributes: Object.keys(nextAttributes).length === 0 ? void 0 : freeze(nextAttributes)
|
|
9502
|
+
});
|
|
9503
|
+
} else {
|
|
9504
|
+
result.push(segment);
|
|
9505
|
+
}
|
|
9506
|
+
offset = end;
|
|
9507
|
+
}
|
|
9508
|
+
return normalizeSegments(result);
|
|
9509
|
+
}
|
|
9510
|
+
function formatReverseOperations(segments, index, length, patch) {
|
|
9511
|
+
const split = splitSegmentsAt(
|
|
9512
|
+
splitSegmentsAt(segments, index),
|
|
9513
|
+
index + length
|
|
9514
|
+
);
|
|
9515
|
+
const result = [];
|
|
9516
|
+
let offset = 0;
|
|
9517
|
+
for (const segment of split) {
|
|
9518
|
+
const end = offset + segment.text.length;
|
|
9519
|
+
if (offset >= index && end <= index + length) {
|
|
9520
|
+
const attributes = {};
|
|
9521
|
+
const current = _nullishCoalesce(segment.attributes, () => ( {}));
|
|
9522
|
+
for (const key of Object.keys(patch)) {
|
|
9523
|
+
const value = Object.hasOwn(current, key) ? current[key] : void 0;
|
|
9524
|
+
attributes[key] = _nullishCoalesce(value, () => ( null));
|
|
9525
|
+
}
|
|
9526
|
+
result.push({
|
|
9527
|
+
type: "format",
|
|
9528
|
+
index: offset,
|
|
9529
|
+
length: segment.text.length,
|
|
9530
|
+
attributes
|
|
9531
|
+
});
|
|
9532
|
+
}
|
|
9533
|
+
offset = end;
|
|
9534
|
+
}
|
|
9535
|
+
return result;
|
|
9536
|
+
}
|
|
9537
|
+
function mapIndexThroughOperation(index, op) {
|
|
9538
|
+
if (op.type === "insert") {
|
|
9539
|
+
return op.index <= index ? index + op.text.length : index;
|
|
9540
|
+
} else if (op.type === "delete") {
|
|
9541
|
+
if (op.index >= index) {
|
|
9542
|
+
return index;
|
|
9543
|
+
}
|
|
9544
|
+
return Math.max(op.index, index - op.length);
|
|
9545
|
+
} else {
|
|
9546
|
+
return index;
|
|
9547
|
+
}
|
|
9548
|
+
}
|
|
9549
|
+
function mapTextIndexThroughOperations(index, ops) {
|
|
9550
|
+
let mapped = index;
|
|
9551
|
+
for (const op of ops) {
|
|
9552
|
+
mapped = mapIndexThroughOperation(mapped, op);
|
|
9553
|
+
}
|
|
9554
|
+
return mapped;
|
|
9555
|
+
}
|
|
9556
|
+
function inverseMapIndexThroughOperation(index, op) {
|
|
9557
|
+
if (op.type === "insert") {
|
|
9558
|
+
if (index <= op.index) {
|
|
9559
|
+
return index;
|
|
9560
|
+
}
|
|
9561
|
+
return Math.max(op.index, index - op.text.length);
|
|
9562
|
+
} else if (op.type === "delete") {
|
|
9563
|
+
return op.index <= index ? index + op.length : index;
|
|
9564
|
+
} else {
|
|
9565
|
+
return index;
|
|
9566
|
+
}
|
|
9567
|
+
}
|
|
9568
|
+
function inverseMapTextIndexThroughOperations(index, ops) {
|
|
9569
|
+
let mapped = index;
|
|
9570
|
+
for (let i = ops.length - 1; i >= 0; i--) {
|
|
9571
|
+
mapped = inverseMapIndexThroughOperation(mapped, ops[i]);
|
|
9572
|
+
}
|
|
9573
|
+
return mapped;
|
|
9574
|
+
}
|
|
9575
|
+
function oppositeOrder(order) {
|
|
9576
|
+
return order === "before" ? "after" : "before";
|
|
9577
|
+
}
|
|
9578
|
+
function mapIndexOverDelete(index, deleteIndex, deleteLength) {
|
|
9579
|
+
if (deleteIndex >= index) {
|
|
9580
|
+
return index;
|
|
9581
|
+
}
|
|
9582
|
+
return Math.max(deleteIndex, index - deleteLength);
|
|
9583
|
+
}
|
|
9584
|
+
function transformInsert(op, over, order) {
|
|
9585
|
+
if (over.type === "insert") {
|
|
9586
|
+
const shifts = over.index < op.index || over.index === op.index && order === "after";
|
|
9587
|
+
return [shifts ? { ...op, index: op.index + over.text.length } : { ...op }];
|
|
9588
|
+
} else if (over.type === "delete") {
|
|
9589
|
+
return [
|
|
9590
|
+
{ ...op, index: mapIndexOverDelete(op.index, over.index, over.length) }
|
|
9591
|
+
];
|
|
9592
|
+
} else {
|
|
9593
|
+
return [{ ...op }];
|
|
9594
|
+
}
|
|
9595
|
+
}
|
|
9596
|
+
function transformDelete(op, over) {
|
|
9597
|
+
const start = op.index;
|
|
9598
|
+
const end = op.index + op.length;
|
|
9599
|
+
if (over.type === "insert") {
|
|
9600
|
+
const at = over.index;
|
|
9601
|
+
const len = over.text.length;
|
|
9602
|
+
if (at <= start) {
|
|
9603
|
+
return [{ ...op, index: start + len }];
|
|
9604
|
+
}
|
|
9605
|
+
if (at >= end) {
|
|
9606
|
+
return [{ ...op }];
|
|
9607
|
+
}
|
|
9608
|
+
return [
|
|
9609
|
+
{ type: "delete", index: start, length: at - start },
|
|
9610
|
+
{ type: "delete", index: start + len, length: end - at }
|
|
9611
|
+
];
|
|
9612
|
+
} else if (over.type === "delete") {
|
|
9613
|
+
const newStart = mapIndexOverDelete(start, over.index, over.length);
|
|
9614
|
+
const newEnd = mapIndexOverDelete(end, over.index, over.length);
|
|
9615
|
+
return newEnd - newStart > 0 ? [{ type: "delete", index: newStart, length: newEnd - newStart }] : [];
|
|
9616
|
+
} else {
|
|
9617
|
+
return [{ ...op }];
|
|
9618
|
+
}
|
|
9619
|
+
}
|
|
9620
|
+
function transformFormat(op, over, order) {
|
|
9621
|
+
const start = op.index;
|
|
9622
|
+
const end = op.index + op.length;
|
|
9623
|
+
if (over.type === "insert") {
|
|
9624
|
+
const at = over.index;
|
|
9625
|
+
const len = over.text.length;
|
|
9626
|
+
if (at <= start) {
|
|
9627
|
+
return [{ ...op, index: start + len }];
|
|
9628
|
+
}
|
|
9629
|
+
if (at >= end) {
|
|
9630
|
+
return [{ ...op }];
|
|
9631
|
+
}
|
|
9632
|
+
return [
|
|
9633
|
+
{
|
|
9634
|
+
type: "format",
|
|
9635
|
+
index: start,
|
|
9636
|
+
length: at - start,
|
|
9637
|
+
attributes: op.attributes
|
|
9638
|
+
},
|
|
9639
|
+
{
|
|
9640
|
+
type: "format",
|
|
9641
|
+
index: at + len,
|
|
9642
|
+
length: end - at,
|
|
9643
|
+
attributes: op.attributes
|
|
9644
|
+
}
|
|
9645
|
+
];
|
|
9646
|
+
} else if (over.type === "delete") {
|
|
9647
|
+
const newStart = mapIndexOverDelete(start, over.index, over.length);
|
|
9648
|
+
const newEnd = mapIndexOverDelete(end, over.index, over.length);
|
|
9649
|
+
return newEnd - newStart > 0 ? [
|
|
9650
|
+
{
|
|
9651
|
+
type: "format",
|
|
9652
|
+
index: newStart,
|
|
9653
|
+
length: newEnd - newStart,
|
|
9654
|
+
attributes: op.attributes
|
|
9655
|
+
}
|
|
9656
|
+
] : [];
|
|
9657
|
+
} else {
|
|
9658
|
+
if (order === "after") {
|
|
9659
|
+
return [{ ...op }];
|
|
9660
|
+
}
|
|
9661
|
+
const overlapStart = Math.max(start, over.index);
|
|
9662
|
+
const overlapEnd = Math.min(end, over.index + over.length);
|
|
9663
|
+
if (overlapStart >= overlapEnd) {
|
|
9664
|
+
return [{ ...op }];
|
|
9665
|
+
}
|
|
9666
|
+
const hasConflict = Object.keys(op.attributes).some(
|
|
9667
|
+
(key) => Object.hasOwn(over.attributes, key)
|
|
9668
|
+
);
|
|
9669
|
+
if (!hasConflict) {
|
|
9670
|
+
return [{ ...op }];
|
|
9671
|
+
}
|
|
9672
|
+
const reduced = {};
|
|
9673
|
+
for (const [key, value] of Object.entries(op.attributes)) {
|
|
9674
|
+
if (!Object.hasOwn(over.attributes, key)) {
|
|
9675
|
+
reduced[key] = value;
|
|
9676
|
+
}
|
|
9677
|
+
}
|
|
9678
|
+
const pieces = [];
|
|
9679
|
+
if (start < overlapStart) {
|
|
9680
|
+
pieces.push({
|
|
9681
|
+
type: "format",
|
|
9682
|
+
index: start,
|
|
9683
|
+
length: overlapStart - start,
|
|
9684
|
+
attributes: op.attributes
|
|
9685
|
+
});
|
|
9686
|
+
}
|
|
9687
|
+
if (Object.keys(reduced).length > 0) {
|
|
9688
|
+
pieces.push({
|
|
9689
|
+
type: "format",
|
|
9690
|
+
index: overlapStart,
|
|
9691
|
+
length: overlapEnd - overlapStart,
|
|
9692
|
+
attributes: reduced
|
|
9693
|
+
});
|
|
9694
|
+
}
|
|
9695
|
+
if (overlapEnd < end) {
|
|
9696
|
+
pieces.push({
|
|
9697
|
+
type: "format",
|
|
9698
|
+
index: overlapEnd,
|
|
9699
|
+
length: end - overlapEnd,
|
|
9700
|
+
attributes: op.attributes
|
|
9701
|
+
});
|
|
9702
|
+
}
|
|
9703
|
+
return pieces;
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9706
|
+
function transformSingle(op, over, order) {
|
|
9707
|
+
switch (op.type) {
|
|
9708
|
+
case "insert":
|
|
9709
|
+
return transformInsert(op, over, order);
|
|
9710
|
+
case "delete":
|
|
9711
|
+
return transformDelete(op, over);
|
|
9712
|
+
case "format":
|
|
9713
|
+
return transformFormat(op, over, order);
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
function transformTextOperationsX(a, b, order) {
|
|
9717
|
+
if (a.length === 0 || b.length === 0) {
|
|
9718
|
+
return [[...a], [...b]];
|
|
9719
|
+
}
|
|
9720
|
+
if (a.length === 1 && b.length === 1) {
|
|
9721
|
+
return [
|
|
9722
|
+
transformSingle(a[0], b[0], order),
|
|
9723
|
+
transformSingle(b[0], a[0], oppositeOrder(order))
|
|
9724
|
+
];
|
|
9725
|
+
}
|
|
9726
|
+
if (a.length > 1) {
|
|
9727
|
+
const [headA1, b1] = transformTextOperationsX([a[0]], b, order);
|
|
9728
|
+
const [restA1, b2] = transformTextOperationsX(a.slice(1), b1, order);
|
|
9729
|
+
return [[...headA1, ...restA1], b2];
|
|
9730
|
+
}
|
|
9731
|
+
const [a1, headB1] = transformTextOperationsX(a, [b[0]], order);
|
|
9732
|
+
const [a2, restB1] = transformTextOperationsX(a1, b.slice(1), order);
|
|
9733
|
+
return [a2, [...headB1, ...restB1]];
|
|
9734
|
+
}
|
|
9735
|
+
function transformTextOperations(ops, over, order) {
|
|
9736
|
+
return transformTextOperationsX(ops, over, order)[0];
|
|
9737
|
+
}
|
|
9738
|
+
function textOperationsEqual(a, b) {
|
|
9739
|
+
return a === b || stableStringify(a) === stableStringify(b);
|
|
9740
|
+
}
|
|
9741
|
+
function applyTextOperationsToSegments(segments, ops) {
|
|
9742
|
+
let next = [...segments];
|
|
9743
|
+
for (const op of ops) {
|
|
9744
|
+
if (op.type === "insert") {
|
|
9745
|
+
const index = Math.max(0, Math.min(op.index, textLength(next)));
|
|
9746
|
+
next = applyInsert(next, index, op.text, op.attributes);
|
|
9747
|
+
} else if (op.type === "delete") {
|
|
9748
|
+
const index = Math.max(0, Math.min(op.index, textLength(next)));
|
|
9749
|
+
const clipped = clipRange(index, op.length, textLength(next));
|
|
9750
|
+
next = applyDelete(next, clipped.index, clipped.length).segments;
|
|
9751
|
+
} else {
|
|
9752
|
+
const index = Math.max(0, Math.min(op.index, textLength(next)));
|
|
9753
|
+
const clipped = clipRange(index, op.length, textLength(next));
|
|
9754
|
+
next = applyFormat(next, clipped.index, clipped.length, op.attributes);
|
|
9755
|
+
}
|
|
9756
|
+
}
|
|
9757
|
+
return next;
|
|
9758
|
+
}
|
|
9759
|
+
function applyLiveTextOperations(data, ops) {
|
|
9760
|
+
return segmentsToData(
|
|
9761
|
+
applyTextOperationsToSegments(dataToSegments(data), ops)
|
|
9762
|
+
);
|
|
9763
|
+
}
|
|
9764
|
+
function normalizeLiveTextOperations(data, operations) {
|
|
9765
|
+
let shadow = dataToSegments(data);
|
|
9766
|
+
const normalized = [];
|
|
9767
|
+
for (const operation of operations) {
|
|
9768
|
+
const text = shadow.map((segment) => segment.text).join("");
|
|
9769
|
+
let normalizedOperation;
|
|
9770
|
+
if (operation.type === "insert") {
|
|
9771
|
+
normalizedOperation = {
|
|
9772
|
+
...operation,
|
|
9773
|
+
index: clipIndexToCodePointBoundary(text, operation.index)
|
|
9774
|
+
};
|
|
9775
|
+
} else {
|
|
9776
|
+
const range = clipRangeToCodePointBoundaries(
|
|
9777
|
+
text,
|
|
9778
|
+
operation.index,
|
|
9779
|
+
operation.length
|
|
9780
|
+
);
|
|
9781
|
+
normalizedOperation = {
|
|
9782
|
+
...operation,
|
|
9783
|
+
index: range.index,
|
|
9784
|
+
length: range.length
|
|
9785
|
+
};
|
|
9786
|
+
}
|
|
9787
|
+
normalized.push(normalizedOperation);
|
|
9788
|
+
shadow = applyTextOperationsToSegments(shadow, [normalizedOperation]);
|
|
9789
|
+
}
|
|
9790
|
+
return normalized;
|
|
9791
|
+
}
|
|
9792
|
+
function invertTextOperations(segments, ops) {
|
|
9793
|
+
let shadow = [...segments];
|
|
9794
|
+
const reverse = [];
|
|
9795
|
+
for (const op of ops) {
|
|
9796
|
+
if (op.type === "insert") {
|
|
9797
|
+
shadow = applyInsert(shadow, op.index, op.text, op.attributes);
|
|
9798
|
+
reverse.unshift({
|
|
9799
|
+
type: "delete",
|
|
9800
|
+
index: op.index,
|
|
9801
|
+
length: op.text.length
|
|
9802
|
+
});
|
|
9803
|
+
} else if (op.type === "delete") {
|
|
9804
|
+
const deletedSegments = extractDeletedSegments(
|
|
9805
|
+
shadow,
|
|
9806
|
+
op.index,
|
|
9807
|
+
op.length
|
|
9808
|
+
);
|
|
9809
|
+
shadow = applyDelete(shadow, op.index, op.length).segments;
|
|
9810
|
+
const inserts = [];
|
|
9811
|
+
let insertIndex = op.index;
|
|
9812
|
+
for (const segment of deletedSegments) {
|
|
9813
|
+
inserts.push({
|
|
9814
|
+
type: "insert",
|
|
9815
|
+
index: insertIndex,
|
|
9816
|
+
text: segment.text,
|
|
9817
|
+
attributes: segment.attributes
|
|
9818
|
+
});
|
|
9819
|
+
insertIndex += segment.text.length;
|
|
9820
|
+
}
|
|
9821
|
+
for (let index = inserts.length - 1; index >= 0; index--) {
|
|
9822
|
+
reverse.unshift(inserts[index]);
|
|
9823
|
+
}
|
|
9824
|
+
} else {
|
|
9825
|
+
const inverse = formatReverseOperations(
|
|
9826
|
+
shadow,
|
|
9827
|
+
op.index,
|
|
9828
|
+
op.length,
|
|
9829
|
+
op.attributes
|
|
9830
|
+
);
|
|
9831
|
+
shadow = applyFormat(shadow, op.index, op.length, op.attributes);
|
|
9832
|
+
reverse.unshift(...inverse.reverse());
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
return reverse;
|
|
9836
|
+
}
|
|
9837
|
+
|
|
9838
|
+
// src/crdts/LiveText.ts
|
|
9839
|
+
var ACCEPTED_OPS_HISTORY_LIMIT = 1e3;
|
|
9840
|
+
var LiveText = class _LiveText extends AbstractCrdt {
|
|
9841
|
+
/** The local document: #confirmed ⊕ #inFlightOps ⊕ #queuedOps. */
|
|
9842
|
+
#segments;
|
|
9843
|
+
/** The server-confirmed document (only authoritative ops applied). */
|
|
9844
|
+
#confirmed;
|
|
9845
|
+
#version;
|
|
9846
|
+
/** The op currently awaiting server acknowledgement (at most one). */
|
|
9847
|
+
#inFlightOpId;
|
|
9848
|
+
/** Its ops, continuously re-expressed against current server state. */
|
|
9849
|
+
#inFlightOps = [];
|
|
9850
|
+
/** Local edits made while an op is in flight; sent after the ack. */
|
|
9851
|
+
#queuedOps = [];
|
|
9852
|
+
#acceptedOps = [];
|
|
9853
|
+
/**
|
|
9854
|
+
* Creates a new LiveText document.
|
|
9855
|
+
*
|
|
9856
|
+
* @param textOrData Initial plain text, or an array of `[text]` /
|
|
9857
|
+
* `[text, attributes]` segments. Defaults to an empty document.
|
|
9858
|
+
*
|
|
9859
|
+
* @example
|
|
9860
|
+
* new LiveText();
|
|
9861
|
+
* new LiveText("Hello world");
|
|
9862
|
+
* new LiveText([["Hello ", { bold: true }], ["world"]]);
|
|
9863
|
+
*/
|
|
9864
|
+
constructor(textOrData = "", version = 0) {
|
|
9865
|
+
super();
|
|
9866
|
+
this.#segments = typeof textOrData === "string" ? textOrData.length === 0 ? [] : [{ text: textOrData }] : dataToSegments(textOrData);
|
|
9867
|
+
this.#confirmed = [...this.#segments];
|
|
9868
|
+
this.#version = version;
|
|
9869
|
+
Object.assign(this[kInternal], {
|
|
9870
|
+
encodeIndex: (localIndex) => this.#encodeIndex(localIndex),
|
|
9871
|
+
decodeIndex: (index, fromVersion) => this.#decodeIndex(index, fromVersion)
|
|
9872
|
+
});
|
|
9873
|
+
}
|
|
9874
|
+
get version() {
|
|
9875
|
+
return this.#version;
|
|
9876
|
+
}
|
|
9877
|
+
get length() {
|
|
9878
|
+
return textLength(this.#segments);
|
|
9879
|
+
}
|
|
9880
|
+
/** @internal */
|
|
9881
|
+
static _deserialize([id, item], _parentToChildren, pool) {
|
|
9882
|
+
const text = new _LiveText(item.data, item.version);
|
|
9883
|
+
text._attach(id, pool);
|
|
9884
|
+
return text;
|
|
9885
|
+
}
|
|
9886
|
+
/** @internal */
|
|
9887
|
+
_toOps(parentId, parentKey) {
|
|
9888
|
+
if (this._id === void 0) {
|
|
9889
|
+
throw new Error("Cannot serialize LiveText if it is not attached");
|
|
9890
|
+
}
|
|
9891
|
+
return [
|
|
9892
|
+
{
|
|
9893
|
+
type: OpCode.CREATE_TEXT,
|
|
9894
|
+
id: this._id,
|
|
9895
|
+
parentId,
|
|
9896
|
+
parentKey,
|
|
9897
|
+
data: this.toJSON(),
|
|
9898
|
+
version: this.#version
|
|
9899
|
+
}
|
|
9900
|
+
];
|
|
9901
|
+
}
|
|
9902
|
+
/** @internal */
|
|
9903
|
+
_serialize() {
|
|
9904
|
+
if (this.parent.type !== "HasParent") {
|
|
9905
|
+
throw new Error("Cannot serialize LiveText if parent is missing");
|
|
9906
|
+
}
|
|
9907
|
+
return {
|
|
9908
|
+
type: CrdtType.TEXT,
|
|
9909
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
9910
|
+
parentKey: this.parent.key,
|
|
9911
|
+
data: this.toJSON(),
|
|
9912
|
+
version: this.#version
|
|
9913
|
+
};
|
|
9914
|
+
}
|
|
9915
|
+
/** @internal */
|
|
9916
|
+
_attachChild(_op) {
|
|
9917
|
+
throw new Error("LiveText cannot contain child nodes");
|
|
9918
|
+
}
|
|
9919
|
+
/** @internal */
|
|
9920
|
+
_detachChild(_crdt) {
|
|
9921
|
+
throw new Error("LiveText cannot contain child nodes");
|
|
9922
|
+
}
|
|
9923
|
+
/** @internal */
|
|
9924
|
+
_apply(op, source) {
|
|
9925
|
+
if (op.type !== OpCode.UPDATE_TEXT) {
|
|
9926
|
+
return super._apply(op, source);
|
|
9927
|
+
}
|
|
9928
|
+
if (source.origin === "local" && source.optimistic) {
|
|
9929
|
+
return this.#applyLocal(op, toUpdateSource(source));
|
|
9930
|
+
}
|
|
9931
|
+
if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
|
|
9932
|
+
return this.#applyAck(op, toUpdateSource(source));
|
|
9933
|
+
}
|
|
9934
|
+
if (op.opId !== void 0 && this.#acceptedOps.some((entry) => entry.opId === op.opId)) {
|
|
9935
|
+
this.#version = Math.max(this.#version, _nullishCoalesce(op.version, () => ( op.baseVersion + 1)));
|
|
9936
|
+
return { modified: false };
|
|
9937
|
+
}
|
|
9938
|
+
return this.#applyRemote(op, toUpdateSource(source));
|
|
9939
|
+
}
|
|
9940
|
+
/**
|
|
9941
|
+
* Inserts text at the given index.
|
|
9942
|
+
*
|
|
9943
|
+
* @param index Character index at which to insert. Values outside the
|
|
9944
|
+
* document range are clipped.
|
|
9945
|
+
* @param text Text to insert.
|
|
9946
|
+
* @param attributes Optional inline attributes for the inserted text.
|
|
9947
|
+
*
|
|
9948
|
+
* @example
|
|
9949
|
+
* const text = new LiveText("Hello");
|
|
9950
|
+
* text.insert(5, " world");
|
|
9951
|
+
* text.insert(0, "Say: ", { italic: true });
|
|
9952
|
+
*/
|
|
9953
|
+
insert(index, text, attributes) {
|
|
9954
|
+
const clippedIndex = clipIndexToCodePointBoundary(this.toString(), index);
|
|
9955
|
+
this.#dispatch([{ type: "insert", index: clippedIndex, text, attributes }]);
|
|
9956
|
+
}
|
|
9957
|
+
/**
|
|
9958
|
+
* Deletes `length` characters starting at `index`.
|
|
9959
|
+
*
|
|
9960
|
+
* @example
|
|
9961
|
+
* const text = new LiveText("Hello world");
|
|
9962
|
+
* text.delete(5, 6); // "Hello"
|
|
9963
|
+
*/
|
|
9964
|
+
delete(index, length) {
|
|
9965
|
+
const clipped = clipRangeToCodePointBoundaries(
|
|
9966
|
+
this.toString(),
|
|
9967
|
+
index,
|
|
9968
|
+
length
|
|
9969
|
+
);
|
|
9970
|
+
if (clipped.length === 0) {
|
|
9971
|
+
return;
|
|
9972
|
+
}
|
|
9973
|
+
this.#dispatch([
|
|
9974
|
+
{ type: "delete", index: clipped.index, length: clipped.length }
|
|
9975
|
+
]);
|
|
9976
|
+
}
|
|
9977
|
+
/**
|
|
9978
|
+
* Replaces a range of text with new text.
|
|
9979
|
+
*
|
|
9980
|
+
* @example
|
|
9981
|
+
* const text = new LiveText("Hello world");
|
|
9982
|
+
* text.replace(0, 5, "Hi"); // "Hi world"
|
|
9983
|
+
*/
|
|
9984
|
+
replace(index, length, text, attributes) {
|
|
9985
|
+
const clipped = clipRangeToCodePointBoundaries(
|
|
9986
|
+
this.toString(),
|
|
9987
|
+
index,
|
|
9988
|
+
length
|
|
9989
|
+
);
|
|
9990
|
+
const ops = [];
|
|
9991
|
+
if (clipped.length > 0) {
|
|
9992
|
+
ops.push({
|
|
9993
|
+
type: "delete",
|
|
9994
|
+
index: clipped.index,
|
|
9995
|
+
length: clipped.length
|
|
9996
|
+
});
|
|
9997
|
+
}
|
|
9998
|
+
if (text.length > 0) {
|
|
9999
|
+
ops.push({ type: "insert", index: clipped.index, text, attributes });
|
|
10000
|
+
}
|
|
10001
|
+
this.#dispatch(ops);
|
|
10002
|
+
}
|
|
10003
|
+
/**
|
|
10004
|
+
* Encode a local-document index (an offset into this LiveText's current
|
|
10005
|
+
* #segments, which CodeMirror or any consumer mirrors as its document)
|
|
10006
|
+
* into server-confirmed coordinates suitable for broadcasting to peers via
|
|
10007
|
+
* presence or any other side channel.
|
|
10008
|
+
*
|
|
10009
|
+
* The returned index is in this LiveText's current #confirmed coordinates
|
|
10010
|
+
* — that is, with this client's local pending ops inverse-mapped out.
|
|
10011
|
+
* Pair it with the current {@link LiveText.version} when sending so the
|
|
10012
|
+
* receiver can call {@link PrivateLiveTextApi.decodeIndex} to land the
|
|
10013
|
+
* position in their own local document coordinates regardless of their
|
|
10014
|
+
* private pending ops.
|
|
10015
|
+
*
|
|
10016
|
+
* Index ambiguity at boundaries is resolved by an inverse-of-forward
|
|
10017
|
+
* convention: a position at or before a local insertion is reported as
|
|
10018
|
+
* the position right before the insertion in #confirmed; a position past
|
|
10019
|
+
* the insertion shifts left by the insertion's length. Positions inside
|
|
10020
|
+
* an own-pending insertion collapse to the insertion point.
|
|
10021
|
+
*/
|
|
10022
|
+
#encodeIndex(localIndex) {
|
|
10023
|
+
let mapped = Math.max(0, Math.min(localIndex, this.length));
|
|
10024
|
+
mapped = inverseMapTextIndexThroughOperations(mapped, this.#queuedOps);
|
|
10025
|
+
mapped = inverseMapTextIndexThroughOperations(mapped, this.#inFlightOps);
|
|
10026
|
+
return mapped;
|
|
10027
|
+
}
|
|
10028
|
+
/**
|
|
10029
|
+
* Decode an `(index, fromVersion)` pair produced by
|
|
10030
|
+
* {@link PrivateLiveTextApi.encodeIndex} — typically on a peer — into an
|
|
10031
|
+
* offset in this LiveText's current local document (an index suitable for
|
|
10032
|
+
* placing a CodeMirror marker, an annotation anchor, or anything else that
|
|
10033
|
+
* lives over #segments).
|
|
10034
|
+
*
|
|
10035
|
+
* Composes the accepted ops applied since `fromVersion` (drawn from
|
|
10036
|
+
* #acceptedOps in locally-applied form) with this client's own local
|
|
10037
|
+
* pending ops, in that order. The result is in current #segments
|
|
10038
|
+
* coordinates.
|
|
10039
|
+
*
|
|
10040
|
+
* Returns `null` when the position cannot be decoded against the current
|
|
10041
|
+
* state:
|
|
10042
|
+
* - `fromVersion` is greater than this LiveText's current version: the
|
|
10043
|
+
* peer is ahead of us. The caller should park the message and retry
|
|
10044
|
+
* after more accepted ops arrive.
|
|
10045
|
+
* - `fromVersion` falls outside the retained accepted-ops history. This
|
|
10046
|
+
* only happens after very long-lived disconnections; the caller can
|
|
10047
|
+
* fall back to using the raw index and letting subsequent local
|
|
10048
|
+
* transactions map it (with bounded drift).
|
|
10049
|
+
*/
|
|
10050
|
+
#decodeIndex(index, fromVersion) {
|
|
10051
|
+
if (fromVersion > this.#version) {
|
|
10052
|
+
return null;
|
|
10053
|
+
}
|
|
10054
|
+
if (fromVersion < this.#version) {
|
|
10055
|
+
const oldest = _optionalChain([this, 'access', _238 => _238.#acceptedOps, 'access', _239 => _239[0], 'optionalAccess', _240 => _240.version]);
|
|
10056
|
+
if (oldest === void 0 || oldest > fromVersion + 1) {
|
|
10057
|
+
return null;
|
|
10058
|
+
}
|
|
10059
|
+
}
|
|
10060
|
+
let mapped = index;
|
|
10061
|
+
for (const entry of this.#acceptedOps) {
|
|
10062
|
+
if (entry.version <= fromVersion) continue;
|
|
10063
|
+
if (entry.version > this.#version) break;
|
|
10064
|
+
if (entry.ops.length === 0) continue;
|
|
10065
|
+
mapped = mapTextIndexThroughOperations(mapped, entry.ops);
|
|
10066
|
+
}
|
|
10067
|
+
mapped = mapTextIndexThroughOperations(mapped, this.#inFlightOps);
|
|
10068
|
+
mapped = mapTextIndexThroughOperations(mapped, this.#queuedOps);
|
|
10069
|
+
return Math.max(0, Math.min(mapped, this.length));
|
|
10070
|
+
}
|
|
10071
|
+
/**
|
|
10072
|
+
* Applies or removes inline attributes on a range of text.
|
|
10073
|
+
*
|
|
10074
|
+
* Set an attribute to `null` to remove it from the range.
|
|
10075
|
+
*
|
|
10076
|
+
* @example
|
|
10077
|
+
* const text = new LiveText("Hello world");
|
|
10078
|
+
* text.format(0, 5, { bold: true });
|
|
10079
|
+
* text.format(0, 5, { bold: null });
|
|
10080
|
+
*/
|
|
10081
|
+
format(index, length, attributes) {
|
|
10082
|
+
const clipped = clipRangeToCodePointBoundaries(
|
|
10083
|
+
this.toString(),
|
|
10084
|
+
index,
|
|
10085
|
+
length
|
|
10086
|
+
);
|
|
10087
|
+
if (clipped.length === 0) {
|
|
10088
|
+
return;
|
|
10089
|
+
}
|
|
10090
|
+
this.#dispatch([
|
|
10091
|
+
{
|
|
10092
|
+
type: "format",
|
|
10093
|
+
index: clipped.index,
|
|
10094
|
+
length: clipped.length,
|
|
10095
|
+
attributes
|
|
10096
|
+
}
|
|
10097
|
+
]);
|
|
10098
|
+
}
|
|
10099
|
+
/** Local edits made through the public API. */
|
|
10100
|
+
#dispatch(ops) {
|
|
10101
|
+
if (ops.length === 0) {
|
|
10102
|
+
return;
|
|
10103
|
+
}
|
|
10104
|
+
this._warnIfOrphaned();
|
|
10105
|
+
_optionalChain([this, 'access', _241 => _241._pool, 'optionalAccess', _242 => _242.assertStorageIsWritable, 'call', _243 => _243()]);
|
|
10106
|
+
const attached = this._pool !== void 0 && this._id !== void 0;
|
|
10107
|
+
const reverse = attached ? this.#invertOperations(ops) : [];
|
|
10108
|
+
const changes = this.#applyOperationsLocally(ops);
|
|
10109
|
+
if (!attached) {
|
|
10110
|
+
return;
|
|
10111
|
+
}
|
|
10112
|
+
const pool = nn(this._pool);
|
|
10113
|
+
const id = nn(this._id);
|
|
10114
|
+
const updates = /* @__PURE__ */ new Map([
|
|
10115
|
+
[
|
|
10116
|
+
id,
|
|
10117
|
+
{
|
|
10118
|
+
type: "LiveText",
|
|
10119
|
+
node: this,
|
|
10120
|
+
version: this.#version,
|
|
10121
|
+
updates: changes,
|
|
10122
|
+
source: LOCAL_EDIT
|
|
10123
|
+
}
|
|
10124
|
+
]
|
|
10125
|
+
]);
|
|
10126
|
+
if (this.#inFlightOpId === void 0) {
|
|
10127
|
+
const opId = pool.generateOpId();
|
|
10128
|
+
this.#inFlightOpId = opId;
|
|
10129
|
+
this.#inFlightOps = [...ops];
|
|
10130
|
+
pool.dispatch(
|
|
10131
|
+
[
|
|
10132
|
+
{
|
|
10133
|
+
type: OpCode.UPDATE_TEXT,
|
|
10134
|
+
id,
|
|
10135
|
+
opId,
|
|
10136
|
+
baseVersion: this.#version,
|
|
10137
|
+
ops: [...ops]
|
|
10138
|
+
}
|
|
10139
|
+
],
|
|
10140
|
+
reverse,
|
|
10141
|
+
updates
|
|
10142
|
+
);
|
|
10143
|
+
} else {
|
|
10144
|
+
this.#queuedOps.push(...ops);
|
|
10145
|
+
pool.dispatch([], reverse, updates, { clearRedoStack: true });
|
|
10146
|
+
}
|
|
10147
|
+
}
|
|
10148
|
+
/**
|
|
10149
|
+
* A local replay of an existing wire op: an undo/redo frame, or an
|
|
10150
|
+
* unacknowledged op re-sent after a reconnect.
|
|
10151
|
+
*/
|
|
10152
|
+
#applyLocal(op, source) {
|
|
10153
|
+
const mutableOp = op;
|
|
10154
|
+
if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
|
|
10155
|
+
this.#inFlightOps = [...this.#inFlightOps, ...this.#queuedOps];
|
|
10156
|
+
this.#queuedOps = [];
|
|
10157
|
+
mutableOp.baseVersion = this.#version;
|
|
10158
|
+
mutableOp.ops = [...this.#inFlightOps];
|
|
10159
|
+
return { modified: false };
|
|
10160
|
+
}
|
|
10161
|
+
let ops = op.ops;
|
|
10162
|
+
for (const entry of this.#acceptedOps) {
|
|
10163
|
+
if (entry.version > op.baseVersion && entry.ops.length > 0) {
|
|
10164
|
+
ops = transformTextOperations(ops, entry.ops, "after");
|
|
10165
|
+
}
|
|
10166
|
+
}
|
|
10167
|
+
const reverse = this.#invertOperations(ops);
|
|
10168
|
+
const changes = this.#applyOperationsLocally(ops);
|
|
10169
|
+
if (this.#inFlightOpId === void 0 && ops.length > 0) {
|
|
10170
|
+
this.#inFlightOpId = nn(op.opId, "Local ops must have an opId");
|
|
10171
|
+
this.#inFlightOps = [...ops];
|
|
10172
|
+
mutableOp.baseVersion = this.#version;
|
|
10173
|
+
mutableOp.ops = [...ops];
|
|
10174
|
+
} else {
|
|
10175
|
+
this.#queuedOps.push(...ops);
|
|
10176
|
+
mutableOp.baseVersion = this.#version;
|
|
10177
|
+
mutableOp.ops = [];
|
|
10178
|
+
}
|
|
10179
|
+
if (changes.length === 0) {
|
|
10180
|
+
return { modified: false };
|
|
10181
|
+
}
|
|
10182
|
+
return {
|
|
10183
|
+
reverse,
|
|
10184
|
+
modified: {
|
|
10185
|
+
type: "LiveText",
|
|
10186
|
+
node: this,
|
|
10187
|
+
version: this.#version,
|
|
10188
|
+
updates: changes,
|
|
10189
|
+
source
|
|
10190
|
+
}
|
|
10191
|
+
};
|
|
10192
|
+
}
|
|
10193
|
+
/** Server acknowledgement of our in-flight op. */
|
|
10194
|
+
#applyAck(op, source) {
|
|
10195
|
+
const ackedVersion = _nullishCoalesce(op.version, () => ( Math.max(this.#version, op.baseVersion + 1)));
|
|
10196
|
+
const predicted = this.#inFlightOps;
|
|
10197
|
+
const opId = this.#inFlightOpId;
|
|
10198
|
+
this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
|
|
10199
|
+
this.#inFlightOpId = void 0;
|
|
10200
|
+
this.#inFlightOps = [];
|
|
10201
|
+
let appliedOps = [];
|
|
10202
|
+
let result = { modified: false };
|
|
10203
|
+
if (!textOperationsEqual(op.ops, predicted)) {
|
|
10204
|
+
error2(
|
|
10205
|
+
"LiveText: acknowledgement did not match the local prediction; resynchronizing"
|
|
10206
|
+
);
|
|
10207
|
+
const rebuilt = this.#rebuildLocalFromConfirmed();
|
|
10208
|
+
appliedOps = rebuilt.appliedOps;
|
|
10209
|
+
if (rebuilt.changes.length > 0) {
|
|
10210
|
+
result = {
|
|
10211
|
+
reverse: [],
|
|
10212
|
+
modified: {
|
|
10213
|
+
type: "LiveText",
|
|
10214
|
+
node: this,
|
|
10215
|
+
version: ackedVersion,
|
|
10216
|
+
updates: rebuilt.changes,
|
|
10217
|
+
source
|
|
10218
|
+
}
|
|
10219
|
+
};
|
|
10220
|
+
}
|
|
10221
|
+
}
|
|
10222
|
+
this.#version = Math.max(this.#version, ackedVersion);
|
|
10223
|
+
this.#recordAccepted(ackedVersion, appliedOps, opId);
|
|
10224
|
+
this.#flushQueued();
|
|
10225
|
+
return result;
|
|
10226
|
+
}
|
|
10227
|
+
/** An accepted op from another client (or a server-fabricated fix op). */
|
|
10228
|
+
#applyRemote(op, source) {
|
|
10229
|
+
const version = _nullishCoalesce(op.version, () => ( this.#version + 1));
|
|
10230
|
+
this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
|
|
10231
|
+
const [overInFlight, inFlight] = transformTextOperationsX(
|
|
10232
|
+
op.ops,
|
|
10233
|
+
this.#inFlightOps,
|
|
10234
|
+
"before"
|
|
10235
|
+
);
|
|
10236
|
+
const [applied, queued] = transformTextOperationsX(
|
|
10237
|
+
overInFlight,
|
|
10238
|
+
this.#queuedOps,
|
|
10239
|
+
"before"
|
|
10240
|
+
);
|
|
10241
|
+
this.#inFlightOps = inFlight;
|
|
10242
|
+
this.#queuedOps = queued;
|
|
10243
|
+
this.#recordAccepted(version, applied, op.opId);
|
|
10244
|
+
if (applied.length === 0) {
|
|
10245
|
+
this.#version = Math.max(this.#version, version);
|
|
10246
|
+
return { modified: false };
|
|
10247
|
+
}
|
|
10248
|
+
const reverse = this.#invertOperations(applied);
|
|
10249
|
+
const changes = this.#applyOperationsLocally(applied);
|
|
10250
|
+
this.#version = Math.max(this.#version, version);
|
|
10251
|
+
return {
|
|
10252
|
+
reverse,
|
|
10253
|
+
modified: {
|
|
10254
|
+
type: "LiveText",
|
|
10255
|
+
node: this,
|
|
10256
|
+
version: this.#version,
|
|
10257
|
+
updates: changes,
|
|
10258
|
+
source
|
|
10259
|
+
}
|
|
10260
|
+
};
|
|
10261
|
+
}
|
|
10262
|
+
/** Send the queued ops as the next in-flight op (after an ack). */
|
|
10263
|
+
#flushQueued() {
|
|
10264
|
+
if (this.#queuedOps.length === 0 || this._pool === void 0 || this._id === void 0) {
|
|
10265
|
+
return;
|
|
10266
|
+
}
|
|
10267
|
+
const opId = this._pool.generateOpId();
|
|
10268
|
+
this.#inFlightOpId = opId;
|
|
10269
|
+
this.#inFlightOps = this.#queuedOps;
|
|
10270
|
+
this.#queuedOps = [];
|
|
10271
|
+
this._pool.dispatch(
|
|
10272
|
+
[
|
|
10273
|
+
{
|
|
10274
|
+
type: OpCode.UPDATE_TEXT,
|
|
10275
|
+
id: this._id,
|
|
10276
|
+
opId,
|
|
10277
|
+
baseVersion: this.#version,
|
|
10278
|
+
ops: [...this.#inFlightOps]
|
|
10279
|
+
}
|
|
10280
|
+
],
|
|
10281
|
+
[],
|
|
10282
|
+
/* @__PURE__ */ new Map(),
|
|
10283
|
+
// The local content was already applied (and made undoable) when the
|
|
10284
|
+
// edits happened; this is purely an outbound flush.
|
|
10285
|
+
{ clearRedoStack: false }
|
|
10286
|
+
);
|
|
10287
|
+
}
|
|
10288
|
+
/**
|
|
10289
|
+
* Rebuild the local document as confirmed ⊕ queued ops, returning the
|
|
10290
|
+
* coarse delta that was applied. Only used by defensive recovery paths.
|
|
10291
|
+
*/
|
|
10292
|
+
#rebuildLocalFromConfirmed() {
|
|
10293
|
+
const before2 = this.#segments;
|
|
10294
|
+
const after2 = applyTextOperationsToSegments(this.#confirmed, [
|
|
10295
|
+
...this.#inFlightOps,
|
|
10296
|
+
...this.#queuedOps
|
|
10297
|
+
]);
|
|
10298
|
+
if (stableStringify(segmentsToData(before2)) === stableStringify(segmentsToData(after2))) {
|
|
10299
|
+
this.#segments = after2;
|
|
10300
|
+
return { appliedOps: [], changes: [] };
|
|
10301
|
+
}
|
|
10302
|
+
const beforeText = before2.map((segment) => segment.text).join("");
|
|
10303
|
+
this.#segments = after2;
|
|
10304
|
+
this.invalidate();
|
|
10305
|
+
const appliedOps = [];
|
|
10306
|
+
const changes = [];
|
|
10307
|
+
if (beforeText.length > 0) {
|
|
10308
|
+
appliedOps.push({ type: "delete", index: 0, length: beforeText.length });
|
|
10309
|
+
changes.push({
|
|
10310
|
+
type: "delete",
|
|
10311
|
+
index: 0,
|
|
10312
|
+
length: beforeText.length,
|
|
10313
|
+
deletedText: beforeText
|
|
10314
|
+
});
|
|
10315
|
+
}
|
|
10316
|
+
let index = 0;
|
|
10317
|
+
for (const segment of after2) {
|
|
10318
|
+
appliedOps.push({
|
|
10319
|
+
type: "insert",
|
|
10320
|
+
index,
|
|
10321
|
+
text: segment.text,
|
|
10322
|
+
attributes: segment.attributes
|
|
10323
|
+
});
|
|
10324
|
+
changes.push({
|
|
10325
|
+
type: "insert",
|
|
10326
|
+
index,
|
|
10327
|
+
text: segment.text,
|
|
10328
|
+
attributes: segment.attributes
|
|
10329
|
+
});
|
|
10330
|
+
index += segment.text.length;
|
|
10331
|
+
}
|
|
10332
|
+
return { appliedOps, changes };
|
|
10333
|
+
}
|
|
10334
|
+
/**
|
|
10335
|
+
* Reconcile this node against an authoritative storage snapshot (e.g.
|
|
10336
|
+
* after a reconnect). The confirmed state and version are replaced by the
|
|
10337
|
+
* snapshot's; pending (in-flight + queued) ops are preserved on top and
|
|
10338
|
+
* will be re-sent by the offline-ops replay.
|
|
10339
|
+
*
|
|
10340
|
+
* @internal
|
|
10341
|
+
*/
|
|
10342
|
+
_resyncText(data, version, source) {
|
|
10343
|
+
this.#confirmed = dataToSegments(data);
|
|
10344
|
+
this.#version = version;
|
|
10345
|
+
this.#acceptedOps = [];
|
|
10346
|
+
const rebuilt = this.#rebuildLocalFromConfirmed();
|
|
10347
|
+
if (rebuilt.changes.length === 0) {
|
|
10348
|
+
return void 0;
|
|
10349
|
+
}
|
|
10350
|
+
return {
|
|
10351
|
+
type: "LiveText",
|
|
10352
|
+
node: this,
|
|
10353
|
+
version: this.#version,
|
|
10354
|
+
updates: rebuilt.changes,
|
|
10355
|
+
source
|
|
10356
|
+
};
|
|
10357
|
+
}
|
|
10358
|
+
/**
|
|
10359
|
+
* Called when the server rejected one of our ops. Drops all pending state
|
|
10360
|
+
* for this node (edits queued behind a rejected op cannot be trusted
|
|
10361
|
+
* either); the room follows up with a storage resync.
|
|
10362
|
+
*
|
|
10363
|
+
* @internal
|
|
10364
|
+
*/
|
|
10365
|
+
_rejectPendingOp(opId) {
|
|
10366
|
+
if (opId !== this.#inFlightOpId) {
|
|
10367
|
+
return;
|
|
10368
|
+
}
|
|
10369
|
+
this.#inFlightOpId = void 0;
|
|
10370
|
+
this.#inFlightOps = [];
|
|
10371
|
+
this.#queuedOps = [];
|
|
10372
|
+
}
|
|
10373
|
+
#recordAccepted(version, ops, opId) {
|
|
10374
|
+
if (this.#acceptedOps.some((entry) => entry.version === version)) {
|
|
10375
|
+
return;
|
|
10376
|
+
}
|
|
10377
|
+
this.#acceptedOps.push({ version, opId, ops: [...ops] });
|
|
10378
|
+
this.#acceptedOps.sort((left, right) => left.version - right.version);
|
|
10379
|
+
if (this.#acceptedOps.length > ACCEPTED_OPS_HISTORY_LIMIT) {
|
|
10380
|
+
this.#acceptedOps.splice(
|
|
10381
|
+
0,
|
|
10382
|
+
this.#acceptedOps.length - ACCEPTED_OPS_HISTORY_LIMIT
|
|
10383
|
+
);
|
|
10384
|
+
}
|
|
10385
|
+
}
|
|
10386
|
+
#applyOperationsLocally(ops) {
|
|
10387
|
+
const changes = [];
|
|
10388
|
+
for (const op of ops) {
|
|
10389
|
+
if (op.type === "insert") {
|
|
10390
|
+
this.#segments = applyInsert(
|
|
10391
|
+
this.#segments,
|
|
10392
|
+
op.index,
|
|
10393
|
+
op.text,
|
|
10394
|
+
op.attributes
|
|
10395
|
+
);
|
|
10396
|
+
changes.push({
|
|
10397
|
+
type: "insert",
|
|
10398
|
+
index: op.index,
|
|
10399
|
+
text: op.text,
|
|
10400
|
+
attributes: op.attributes
|
|
10401
|
+
});
|
|
10402
|
+
} else if (op.type === "delete") {
|
|
10403
|
+
const result = applyDelete(this.#segments, op.index, op.length);
|
|
10404
|
+
this.#segments = result.segments;
|
|
10405
|
+
changes.push({
|
|
10406
|
+
type: "delete",
|
|
10407
|
+
index: op.index,
|
|
10408
|
+
length: op.length,
|
|
10409
|
+
deletedText: result.deletedText
|
|
10410
|
+
});
|
|
10411
|
+
} else {
|
|
10412
|
+
this.#segments = applyFormat(
|
|
10413
|
+
this.#segments,
|
|
10414
|
+
op.index,
|
|
10415
|
+
op.length,
|
|
10416
|
+
op.attributes
|
|
10417
|
+
);
|
|
10418
|
+
changes.push({
|
|
10419
|
+
type: "format",
|
|
10420
|
+
index: op.index,
|
|
10421
|
+
length: op.length,
|
|
10422
|
+
attributes: op.attributes
|
|
10423
|
+
});
|
|
10424
|
+
}
|
|
10425
|
+
}
|
|
10426
|
+
this.invalidate();
|
|
10427
|
+
return changes;
|
|
10428
|
+
}
|
|
10429
|
+
#invertOperations(ops) {
|
|
10430
|
+
return [
|
|
10431
|
+
{
|
|
10432
|
+
type: OpCode.UPDATE_TEXT,
|
|
10433
|
+
id: nn(this._id),
|
|
10434
|
+
baseVersion: this.#version,
|
|
10435
|
+
ops: invertTextOperations(this.#segments, ops)
|
|
10436
|
+
}
|
|
10437
|
+
];
|
|
10438
|
+
}
|
|
10439
|
+
/** Returns the plain text content without attributes. Equivalent to joining the text from each segment in {@link LiveText.toJSON}. */
|
|
10440
|
+
toString() {
|
|
10441
|
+
return this.#segments.map((segment) => segment.text).join("");
|
|
10442
|
+
}
|
|
10443
|
+
/**
|
|
10444
|
+
* Returns a JSON-compatible snapshot of the document as a {@link LiveTextData}
|
|
10445
|
+
* array.
|
|
10446
|
+
*
|
|
10447
|
+
* @example
|
|
10448
|
+
* new LiveText([["Hello ", { bold: true }], ["world"]]).toJSON();
|
|
10449
|
+
* // [["Hello ", { bold: true }], ["world"]]
|
|
10450
|
+
*/
|
|
10451
|
+
toJSON() {
|
|
10452
|
+
return super.toJSON();
|
|
10453
|
+
}
|
|
10454
|
+
/** @internal */
|
|
10455
|
+
_toJSON() {
|
|
10456
|
+
return segmentsToData(this.#segments);
|
|
10457
|
+
}
|
|
10458
|
+
/** @internal */
|
|
10459
|
+
toTreeNode(key) {
|
|
10460
|
+
return super.toTreeNode(key);
|
|
10461
|
+
}
|
|
10462
|
+
/** @internal */
|
|
10463
|
+
_toTreeNode(key) {
|
|
10464
|
+
const nodeId = _nullishCoalesce(this._id, () => ( nanoid()));
|
|
10465
|
+
const payload = this.toJSON().map(
|
|
10466
|
+
(segment, index) => ({
|
|
10467
|
+
type: "Json",
|
|
10468
|
+
id: `${nodeId}:${index}`,
|
|
10469
|
+
key: String(index),
|
|
10470
|
+
payload: segment
|
|
10471
|
+
})
|
|
10472
|
+
);
|
|
10473
|
+
payload.push({
|
|
10474
|
+
type: "Json",
|
|
10475
|
+
id: `${nodeId}:version`,
|
|
10476
|
+
key: "version",
|
|
10477
|
+
payload: this.version
|
|
10478
|
+
});
|
|
10479
|
+
return {
|
|
10480
|
+
type: "LiveText",
|
|
10481
|
+
id: nodeId,
|
|
10482
|
+
key,
|
|
10483
|
+
payload
|
|
10484
|
+
};
|
|
10485
|
+
}
|
|
10486
|
+
clone() {
|
|
10487
|
+
return new _LiveText(this.toJSON(), this.#version);
|
|
10488
|
+
}
|
|
10489
|
+
};
|
|
10490
|
+
|
|
10491
|
+
// src/crdts/liveblocks-helpers.ts
|
|
10492
|
+
function creationOpToLiveNode(op) {
|
|
10493
|
+
return lsonToLiveNode(creationOpToLson(op));
|
|
10494
|
+
}
|
|
10495
|
+
function creationOpToLson(op) {
|
|
10496
|
+
switch (op.type) {
|
|
10497
|
+
case OpCode.CREATE_FILE:
|
|
10498
|
+
return new LiveFile(op.data);
|
|
10499
|
+
case OpCode.CREATE_REGISTER:
|
|
10500
|
+
return op.data;
|
|
10501
|
+
case OpCode.CREATE_OBJECT:
|
|
10502
|
+
return new LiveObject(op.data);
|
|
10503
|
+
case OpCode.CREATE_MAP:
|
|
10504
|
+
return new LiveMap();
|
|
10505
|
+
case OpCode.CREATE_LIST:
|
|
10506
|
+
return new LiveList([]);
|
|
10507
|
+
case OpCode.CREATE_TEXT:
|
|
10508
|
+
return new LiveText(op.data, op.version);
|
|
10509
|
+
default:
|
|
10510
|
+
return assertNever(op, "Unknown creation Op");
|
|
10511
|
+
}
|
|
10512
|
+
}
|
|
10513
|
+
function isSameNodeOrChildOf(node, parent) {
|
|
10514
|
+
if (node === parent) {
|
|
10515
|
+
return true;
|
|
10516
|
+
}
|
|
10517
|
+
if (node.parent.type === "HasParent") {
|
|
10518
|
+
return isSameNodeOrChildOf(node.parent.node, parent);
|
|
10519
|
+
}
|
|
10520
|
+
return false;
|
|
10521
|
+
}
|
|
10522
|
+
function liveObjectFromNodeStream(nodes) {
|
|
10523
|
+
const pool = createManagedPool({
|
|
10524
|
+
getCurrentConnectionId: () => {
|
|
10525
|
+
throw new Error(
|
|
10526
|
+
"Cannot mutate a historic storage version: it is a read-only snapshot"
|
|
10527
|
+
);
|
|
10528
|
+
}
|
|
10529
|
+
});
|
|
10530
|
+
return LiveObject._fromItems(nodes, pool);
|
|
10531
|
+
}
|
|
10532
|
+
function deserialize(node, parentToChildren, pool) {
|
|
10533
|
+
if (isObjectStorageNode(node)) {
|
|
10534
|
+
return LiveObject._deserialize(node, parentToChildren, pool);
|
|
10535
|
+
} else if (isListStorageNode(node)) {
|
|
10536
|
+
return LiveList._deserialize(node, parentToChildren, pool);
|
|
10537
|
+
} else if (isMapStorageNode(node)) {
|
|
10538
|
+
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
10539
|
+
} else if (isRegisterStorageNode(node)) {
|
|
10540
|
+
return LiveRegister._deserialize(node, parentToChildren, pool);
|
|
10541
|
+
} else if (isTextStorageNode(node)) {
|
|
10542
|
+
return LiveText._deserialize(node, parentToChildren, pool);
|
|
10543
|
+
} else if (isFileStorageNode(node)) {
|
|
10544
|
+
return LiveFile._deserialize(node, parentToChildren, pool);
|
|
10545
|
+
} else {
|
|
10546
|
+
throw new Error("Unexpected CRDT type");
|
|
10547
|
+
}
|
|
10548
|
+
}
|
|
10549
|
+
function deserializeToLson(node, parentToChildren, pool) {
|
|
10550
|
+
if (isObjectStorageNode(node)) {
|
|
10551
|
+
return LiveObject._deserialize(node, parentToChildren, pool);
|
|
10552
|
+
} else if (isListStorageNode(node)) {
|
|
10553
|
+
return LiveList._deserialize(node, parentToChildren, pool);
|
|
10554
|
+
} else if (isMapStorageNode(node)) {
|
|
10555
|
+
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
10556
|
+
} else if (isRegisterStorageNode(node)) {
|
|
10557
|
+
return node[1].data;
|
|
10558
|
+
} else if (isTextStorageNode(node)) {
|
|
10559
|
+
return LiveText._deserialize(node, parentToChildren, pool);
|
|
10560
|
+
} else if (isFileStorageNode(node)) {
|
|
10561
|
+
return LiveFile._deserialize(node, parentToChildren, pool);
|
|
10562
|
+
} else {
|
|
10563
|
+
throw new Error("Unexpected CRDT type");
|
|
10564
|
+
}
|
|
10565
|
+
}
|
|
10566
|
+
function isLiveStructure(value) {
|
|
10567
|
+
return isLiveList(value) || isLiveMap(value) || isLiveObject(value) || isLiveText(value) || isLiveFile(value);
|
|
10568
|
+
}
|
|
10569
|
+
function isLiveNode(value) {
|
|
10570
|
+
return isLiveStructure(value) || isLiveRegister(value);
|
|
10571
|
+
}
|
|
10572
|
+
function isLiveList(value) {
|
|
10573
|
+
return value instanceof LiveList;
|
|
10574
|
+
}
|
|
10575
|
+
function isLiveMap(value) {
|
|
10576
|
+
return value instanceof LiveMap;
|
|
10577
|
+
}
|
|
10578
|
+
function isLiveObject(value) {
|
|
10579
|
+
return value instanceof LiveObject;
|
|
10580
|
+
}
|
|
10581
|
+
function isLiveText(value) {
|
|
10582
|
+
return value instanceof LiveText;
|
|
10583
|
+
}
|
|
10584
|
+
function isLiveFile(value) {
|
|
10585
|
+
return value instanceof LiveFile;
|
|
10586
|
+
}
|
|
10587
|
+
function isLiveRegister(value) {
|
|
10588
|
+
return value instanceof LiveRegister;
|
|
10589
|
+
}
|
|
10590
|
+
function cloneLson(value) {
|
|
10591
|
+
return value === void 0 ? void 0 : isLiveStructure(value) ? value.clone() : deepClone(value);
|
|
10592
|
+
}
|
|
10593
|
+
function liveNodeToLson(obj) {
|
|
10594
|
+
if (obj instanceof LiveRegister) {
|
|
10595
|
+
return obj.data;
|
|
10596
|
+
} else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject || obj instanceof LiveText || obj instanceof LiveFile) {
|
|
10597
|
+
return obj;
|
|
10598
|
+
} else {
|
|
10599
|
+
return assertNever(obj, "Unknown AbstractCrdt");
|
|
10600
|
+
}
|
|
10601
|
+
}
|
|
10602
|
+
function lsonToLiveNode(value) {
|
|
10603
|
+
if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList || value instanceof LiveText || value instanceof LiveFile) {
|
|
10604
|
+
return value;
|
|
10605
|
+
} else {
|
|
10606
|
+
return new LiveRegister(value);
|
|
10607
|
+
}
|
|
10608
|
+
}
|
|
10609
|
+
function dumpPool(pool) {
|
|
10610
|
+
const rows = Array.from(pool.nodes.values(), (node) => {
|
|
10611
|
+
const parent = node.parent;
|
|
10612
|
+
const parentId = parent.type === "HasParent" ? _nullishCoalesce(parent.node._id, () => ( "?")) : parent.type === "Orphaned" ? "<orphaned>" : "-";
|
|
10613
|
+
let value;
|
|
10614
|
+
if (node instanceof LiveRegister) {
|
|
10615
|
+
value = stringifyOrLog(node.data);
|
|
10616
|
+
} else if (node instanceof LiveList) {
|
|
9299
10617
|
value = "<LiveList>";
|
|
9300
10618
|
} else if (node instanceof LiveMap) {
|
|
9301
10619
|
value = "<LiveMap>";
|
|
@@ -9344,7 +10662,26 @@ function isJsonEq(a, b) {
|
|
|
9344
10662
|
}
|
|
9345
10663
|
return true;
|
|
9346
10664
|
}
|
|
9347
|
-
function
|
|
10665
|
+
function liveTextDataToReplaceOps(before2, after2) {
|
|
10666
|
+
const ops = [];
|
|
10667
|
+
const beforeLength = before2.reduce(
|
|
10668
|
+
(length, [text]) => length + text.length,
|
|
10669
|
+
0
|
|
10670
|
+
);
|
|
10671
|
+
if (beforeLength > 0) {
|
|
10672
|
+
ops.push({ type: "delete", index: 0, length: beforeLength });
|
|
10673
|
+
}
|
|
10674
|
+
let index = 0;
|
|
10675
|
+
for (const [text, attributes] of after2) {
|
|
10676
|
+
if (text.length === 0) {
|
|
10677
|
+
continue;
|
|
10678
|
+
}
|
|
10679
|
+
ops.push({ type: "insert", index, text, attributes });
|
|
10680
|
+
index += text.length;
|
|
10681
|
+
}
|
|
10682
|
+
return ops;
|
|
10683
|
+
}
|
|
10684
|
+
function diffNodeMap(prev, next, options) {
|
|
9348
10685
|
const ops = [];
|
|
9349
10686
|
const idsToRecreate = /* @__PURE__ */ new Set();
|
|
9350
10687
|
next.forEach((nextCrdt, id) => {
|
|
@@ -9436,6 +10773,16 @@ function diffNodeMap(prev, next) {
|
|
|
9436
10773
|
parentKey: crdt.parentKey
|
|
9437
10774
|
});
|
|
9438
10775
|
break;
|
|
10776
|
+
case CrdtType.TEXT:
|
|
10777
|
+
ops.push({
|
|
10778
|
+
type: OpCode.CREATE_TEXT,
|
|
10779
|
+
id,
|
|
10780
|
+
parentId: crdt.parentId,
|
|
10781
|
+
parentKey: crdt.parentKey,
|
|
10782
|
+
data: crdt.data,
|
|
10783
|
+
version: crdt.version
|
|
10784
|
+
});
|
|
10785
|
+
break;
|
|
9439
10786
|
}
|
|
9440
10787
|
}
|
|
9441
10788
|
next.forEach((crdt, id) => {
|
|
@@ -9462,6 +10809,17 @@ function diffNodeMap(prev, next) {
|
|
|
9462
10809
|
}
|
|
9463
10810
|
}
|
|
9464
10811
|
}
|
|
10812
|
+
if (_optionalChain([options, 'optionalAccess', _244 => _244.includeLiveTextUpdates]) === true && crdt.type === CrdtType.TEXT && currentCrdt.type === CrdtType.TEXT && !isJsonEq(crdt.data, currentCrdt.data)) {
|
|
10813
|
+
ops.push({
|
|
10814
|
+
type: OpCode.UPDATE_TEXT,
|
|
10815
|
+
id,
|
|
10816
|
+
// A restore is a new edit in the current timeline. The version from
|
|
10817
|
+
// the historic snapshot describes its old timeline and must not move
|
|
10818
|
+
// this node's current version backwards.
|
|
10819
|
+
baseVersion: currentCrdt.version,
|
|
10820
|
+
ops: liveTextDataToReplaceOps(currentCrdt.data, crdt.data)
|
|
10821
|
+
});
|
|
10822
|
+
}
|
|
9465
10823
|
if (crdt.parentKey !== currentCrdt.parentKey) {
|
|
9466
10824
|
ops.push({
|
|
9467
10825
|
type: OpCode.SET_PARENT_KEY,
|
|
@@ -9502,19 +10860,36 @@ function mergeListStorageUpdates(first, second) {
|
|
|
9502
10860
|
updates: updates.concat(second.updates)
|
|
9503
10861
|
};
|
|
9504
10862
|
}
|
|
10863
|
+
function mergeTextStorageUpdates(first, second) {
|
|
10864
|
+
return {
|
|
10865
|
+
...second,
|
|
10866
|
+
updates: first.updates.concat(second.updates)
|
|
10867
|
+
};
|
|
10868
|
+
}
|
|
10869
|
+
function mergeUpdateSources(first, second) {
|
|
10870
|
+
if (first.origin === "remote" || second.origin === "remote") {
|
|
10871
|
+
return REMOTE;
|
|
10872
|
+
}
|
|
10873
|
+
if (second.via !== "edit") return second;
|
|
10874
|
+
if (first.via !== "edit") return first;
|
|
10875
|
+
return LOCAL_EDIT;
|
|
10876
|
+
}
|
|
9505
10877
|
function mergeStorageUpdates(first, second) {
|
|
9506
10878
|
if (first === void 0) {
|
|
9507
10879
|
return second;
|
|
9508
10880
|
}
|
|
10881
|
+
const source = mergeUpdateSources(first.source, second.source);
|
|
9509
10882
|
if (first.type === "LiveObject" && second.type === "LiveObject") {
|
|
9510
|
-
return mergeObjectStorageUpdates(first, second);
|
|
10883
|
+
return { ...mergeObjectStorageUpdates(first, second), source };
|
|
9511
10884
|
} else if (first.type === "LiveMap" && second.type === "LiveMap") {
|
|
9512
|
-
return mergeMapStorageUpdates(first, second);
|
|
10885
|
+
return { ...mergeMapStorageUpdates(first, second), source };
|
|
9513
10886
|
} else if (first.type === "LiveList" && second.type === "LiveList") {
|
|
9514
|
-
return mergeListStorageUpdates(first, second);
|
|
10887
|
+
return { ...mergeListStorageUpdates(first, second), source };
|
|
10888
|
+
} else if (first.type === "LiveText" && second.type === "LiveText") {
|
|
10889
|
+
return { ...mergeTextStorageUpdates(first, second), source };
|
|
9515
10890
|
} else {
|
|
10891
|
+
return { ...second, source };
|
|
9516
10892
|
}
|
|
9517
|
-
return second;
|
|
9518
10893
|
}
|
|
9519
10894
|
|
|
9520
10895
|
// src/devtools/bridge.ts
|
|
@@ -9530,7 +10905,7 @@ function sendToPanel(message, options) {
|
|
|
9530
10905
|
...message,
|
|
9531
10906
|
source: "liveblocks-devtools-client"
|
|
9532
10907
|
};
|
|
9533
|
-
if (!(_optionalChain([options, 'optionalAccess',
|
|
10908
|
+
if (!(_optionalChain([options, 'optionalAccess', _245 => _245.force]) || _bridgeActive)) {
|
|
9534
10909
|
return;
|
|
9535
10910
|
}
|
|
9536
10911
|
window.postMessage(fullMsg, "*");
|
|
@@ -9538,7 +10913,7 @@ function sendToPanel(message, options) {
|
|
|
9538
10913
|
var eventSource = makeEventSource();
|
|
9539
10914
|
if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
|
|
9540
10915
|
window.addEventListener("message", (event) => {
|
|
9541
|
-
if (event.source === window && _optionalChain([event, 'access',
|
|
10916
|
+
if (event.source === window && _optionalChain([event, 'access', _246 => _246.data, 'optionalAccess', _247 => _247.source]) === "liveblocks-devtools-panel") {
|
|
9542
10917
|
eventSource.notify(event.data);
|
|
9543
10918
|
} else {
|
|
9544
10919
|
}
|
|
@@ -9680,7 +11055,7 @@ function fullSync(room) {
|
|
|
9680
11055
|
msg: "room::sync::full",
|
|
9681
11056
|
roomId: room.id,
|
|
9682
11057
|
status: room.getStatus(),
|
|
9683
|
-
storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess',
|
|
11058
|
+
storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _248 => _248.toTreeNode, 'call', _249 => _249("root"), 'access', _250 => _250.payload]), () => ( null)),
|
|
9684
11059
|
me,
|
|
9685
11060
|
others
|
|
9686
11061
|
});
|
|
@@ -10367,15 +11742,15 @@ function installBackgroundTabSpy() {
|
|
|
10367
11742
|
const doc = typeof document !== "undefined" ? document : void 0;
|
|
10368
11743
|
const inBackgroundSince = { current: null };
|
|
10369
11744
|
function onVisibilityChange() {
|
|
10370
|
-
if (_optionalChain([doc, 'optionalAccess',
|
|
11745
|
+
if (_optionalChain([doc, 'optionalAccess', _251 => _251.visibilityState]) === "hidden") {
|
|
10371
11746
|
inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
|
|
10372
11747
|
} else {
|
|
10373
11748
|
inBackgroundSince.current = null;
|
|
10374
11749
|
}
|
|
10375
11750
|
}
|
|
10376
|
-
_optionalChain([doc, 'optionalAccess',
|
|
11751
|
+
_optionalChain([doc, 'optionalAccess', _252 => _252.addEventListener, 'call', _253 => _253("visibilitychange", onVisibilityChange)]);
|
|
10377
11752
|
const unsub = () => {
|
|
10378
|
-
_optionalChain([doc, 'optionalAccess',
|
|
11753
|
+
_optionalChain([doc, 'optionalAccess', _254 => _254.removeEventListener, 'call', _255 => _255("visibilitychange", onVisibilityChange)]);
|
|
10379
11754
|
};
|
|
10380
11755
|
return [inBackgroundSince, unsub];
|
|
10381
11756
|
}
|
|
@@ -10399,7 +11774,7 @@ function makeNodeMapBuffer() {
|
|
|
10399
11774
|
function topLevelKeysOf(nodes) {
|
|
10400
11775
|
const keys2 = /* @__PURE__ */ new Set();
|
|
10401
11776
|
const root = nodes.get("root");
|
|
10402
|
-
for (const key in _optionalChain([root, 'optionalAccess',
|
|
11777
|
+
for (const key in _optionalChain([root, 'optionalAccess', _256 => _256.data])) {
|
|
10403
11778
|
keys2.add(key);
|
|
10404
11779
|
}
|
|
10405
11780
|
for (const node of nodes.values()) {
|
|
@@ -10471,6 +11846,8 @@ function createRoom(options, config) {
|
|
|
10471
11846
|
activeBatch: null,
|
|
10472
11847
|
unacknowledgedOps
|
|
10473
11848
|
};
|
|
11849
|
+
let nextHistoryItemId = 0;
|
|
11850
|
+
let historyDisabled = 0;
|
|
10474
11851
|
const nodeMapBuffer = makeNodeMapBuffer();
|
|
10475
11852
|
const stopwatch = config.enableDebugLogging ? makeStopWatch() : void 0;
|
|
10476
11853
|
let lastTokenKey;
|
|
@@ -10555,7 +11932,7 @@ function createRoom(options, config) {
|
|
|
10555
11932
|
}
|
|
10556
11933
|
}
|
|
10557
11934
|
});
|
|
10558
|
-
function onDispatch(ops, reverse, storageUpdates) {
|
|
11935
|
+
function onDispatch(ops, reverse, storageUpdates, options2) {
|
|
10559
11936
|
if (context.activeBatch) {
|
|
10560
11937
|
for (const op of ops) {
|
|
10561
11938
|
context.activeBatch.ops.push(op);
|
|
@@ -10570,19 +11947,24 @@ function createRoom(options, config) {
|
|
|
10570
11947
|
);
|
|
10571
11948
|
}
|
|
10572
11949
|
context.activeBatch.reverseOps.pushLeft(reverse);
|
|
11950
|
+
if (_optionalChain([options2, 'optionalAccess', _257 => _257.clearRedoStack])) {
|
|
11951
|
+
context.activeBatch.clearRedoStack = true;
|
|
11952
|
+
}
|
|
10573
11953
|
} else {
|
|
10574
11954
|
if (reverse.length > 0) {
|
|
10575
11955
|
addToUndoStack(reverse);
|
|
10576
11956
|
}
|
|
11957
|
+
if (_nullishCoalesce(_optionalChain([options2, 'optionalAccess', _258 => _258.clearRedoStack]), () => ( ops.length > 0))) {
|
|
11958
|
+
clearRedoStack();
|
|
11959
|
+
}
|
|
10577
11960
|
if (ops.length > 0) {
|
|
10578
|
-
context.redoStack.length = 0;
|
|
10579
11961
|
dispatchOps(ops);
|
|
10580
11962
|
}
|
|
10581
11963
|
notify({ storageUpdates });
|
|
10582
11964
|
}
|
|
10583
11965
|
}
|
|
10584
11966
|
function isStorageWritable() {
|
|
10585
|
-
const permissionMatrix = _optionalChain([context, 'access',
|
|
11967
|
+
const permissionMatrix = _optionalChain([context, 'access', _259 => _259.dynamicSessionInfoSig, 'access', _260 => _260.get, 'call', _261 => _261(), 'optionalAccess', _262 => _262.permissionMatrix]);
|
|
10586
11968
|
return permissionMatrix !== void 0 ? hasPermissionAccess(permissionMatrix, "storage", "write") : true;
|
|
10587
11969
|
}
|
|
10588
11970
|
const eventHub = {
|
|
@@ -10595,6 +11977,7 @@ function createRoom(options, config) {
|
|
|
10595
11977
|
others: makeEventSource(),
|
|
10596
11978
|
storageBatch: makeEventSource(),
|
|
10597
11979
|
history: makeEventSource(),
|
|
11980
|
+
privateHistory: makeEventSource(),
|
|
10598
11981
|
storageDidLoad: makeEventSource(),
|
|
10599
11982
|
storageStatus: makeEventSource(),
|
|
10600
11983
|
ydoc: makeEventSource(),
|
|
@@ -10682,12 +12065,12 @@ function createRoom(options, config) {
|
|
|
10682
12065
|
self,
|
|
10683
12066
|
(me) => me !== null ? userToTreeNode("Me", me) : null
|
|
10684
12067
|
);
|
|
10685
|
-
function diffCurrentStorageAgainst(target) {
|
|
12068
|
+
function diffCurrentStorageAgainst(target, options2) {
|
|
10686
12069
|
const current = /* @__PURE__ */ new Map();
|
|
10687
12070
|
for (const [id, crdt] of context.pool.nodes) {
|
|
10688
12071
|
current.set(id, crdt._serialize());
|
|
10689
12072
|
}
|
|
10690
|
-
return diffNodeMap(current, target);
|
|
12073
|
+
return diffNodeMap(current, target, options2);
|
|
10691
12074
|
}
|
|
10692
12075
|
function createOrUpdateRootFromMessage(nodes) {
|
|
10693
12076
|
if (nodes.size === 0) {
|
|
@@ -10695,6 +12078,23 @@ function createRoom(options, config) {
|
|
|
10695
12078
|
}
|
|
10696
12079
|
if (context.root !== void 0) {
|
|
10697
12080
|
const result = applyRemoteOps(diffCurrentStorageAgainst(nodes));
|
|
12081
|
+
for (const [id, crdt] of nodes) {
|
|
12082
|
+
if (crdt.type === CrdtType.TEXT) {
|
|
12083
|
+
const node = context.pool.nodes.get(id);
|
|
12084
|
+
if (node !== void 0 && isLiveText(node)) {
|
|
12085
|
+
const update = node._resyncText(crdt.data, crdt.version, REMOTE);
|
|
12086
|
+
if (update !== void 0) {
|
|
12087
|
+
result.updates.storageUpdates.set(
|
|
12088
|
+
id,
|
|
12089
|
+
mergeStorageUpdates(
|
|
12090
|
+
result.updates.storageUpdates.get(id),
|
|
12091
|
+
update
|
|
12092
|
+
)
|
|
12093
|
+
);
|
|
12094
|
+
}
|
|
12095
|
+
}
|
|
12096
|
+
}
|
|
12097
|
+
}
|
|
10698
12098
|
notify(result.updates);
|
|
10699
12099
|
} else {
|
|
10700
12100
|
context.root = LiveObject._fromItems(
|
|
@@ -10702,7 +12102,7 @@ function createRoom(options, config) {
|
|
|
10702
12102
|
context.pool
|
|
10703
12103
|
);
|
|
10704
12104
|
}
|
|
10705
|
-
const canWrite = _nullishCoalesce(_optionalChain([self, 'access',
|
|
12105
|
+
const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _263 => _263.get, 'call', _264 => _264(), 'optionalAccess', _265 => _265.canWrite]), () => ( true));
|
|
10706
12106
|
const serverTopLevelKeys = topLevelKeysOf(nodes);
|
|
10707
12107
|
const root = context.root;
|
|
10708
12108
|
disableHistory(() => {
|
|
@@ -10719,12 +12119,23 @@ function createRoom(options, config) {
|
|
|
10719
12119
|
}
|
|
10720
12120
|
});
|
|
10721
12121
|
}
|
|
12122
|
+
function notifyPrivateHistory(event) {
|
|
12123
|
+
if (historyDisabled > 0) return;
|
|
12124
|
+
eventHub.privateHistory.notify(event);
|
|
12125
|
+
}
|
|
12126
|
+
function clearRedoStack() {
|
|
12127
|
+
if (context.redoStack.length === 0) return;
|
|
12128
|
+
const ids = context.redoStack.map((item) => item.id);
|
|
12129
|
+
context.redoStack.length = 0;
|
|
12130
|
+
notifyPrivateHistory({ action: "discard", ids });
|
|
12131
|
+
}
|
|
10722
12132
|
function reconcileStorageWithNodes(nodes) {
|
|
10723
12133
|
if (context.root === void 0) {
|
|
10724
12134
|
throw new Error("Cannot reconcile storage before it is loaded");
|
|
10725
12135
|
}
|
|
10726
12136
|
const ops = diffCurrentStorageAgainst(
|
|
10727
|
-
new Map(nodes)
|
|
12137
|
+
new Map(nodes),
|
|
12138
|
+
{ includeLiveTextUpdates: true }
|
|
10728
12139
|
);
|
|
10729
12140
|
if (ops.length === 0) {
|
|
10730
12141
|
return;
|
|
@@ -10743,9 +12154,14 @@ function createRoom(options, config) {
|
|
|
10743
12154
|
}
|
|
10744
12155
|
function _addToRealUndoStack(frames) {
|
|
10745
12156
|
if (context.undoStack.length >= 50) {
|
|
10746
|
-
context.undoStack.shift();
|
|
12157
|
+
const evicted = context.undoStack.shift();
|
|
12158
|
+
if (evicted !== void 0) {
|
|
12159
|
+
notifyPrivateHistory({ action: "discard", ids: [evicted.id] });
|
|
12160
|
+
}
|
|
10747
12161
|
}
|
|
10748
|
-
|
|
12162
|
+
const id = nextHistoryItemId++;
|
|
12163
|
+
context.undoStack.push({ id, frames });
|
|
12164
|
+
notifyPrivateHistory({ action: "push", id });
|
|
10749
12165
|
onHistoryChange();
|
|
10750
12166
|
}
|
|
10751
12167
|
function addToUndoStack(frames) {
|
|
@@ -10769,7 +12185,10 @@ function createRoom(options, config) {
|
|
|
10769
12185
|
eventHub.myPresence.notify(context.myPresence.get());
|
|
10770
12186
|
}
|
|
10771
12187
|
if (storageUpdates !== void 0 && storageUpdates.size > 0) {
|
|
10772
|
-
const updates2 = Array.from(storageUpdates.values())
|
|
12188
|
+
const updates2 = Array.from(storageUpdates.values(), (update) => ({
|
|
12189
|
+
...update,
|
|
12190
|
+
source: toUpdateSource(update.source)
|
|
12191
|
+
}));
|
|
10773
12192
|
eventHub.storageBatch.notify(updates2);
|
|
10774
12193
|
}
|
|
10775
12194
|
notifyStorageStatus();
|
|
@@ -10783,19 +12202,69 @@ function createRoom(options, config) {
|
|
|
10783
12202
|
"Internal. Tried to get connection id but connection was never open"
|
|
10784
12203
|
);
|
|
10785
12204
|
}
|
|
10786
|
-
|
|
12205
|
+
const viaByOpId = /* @__PURE__ */ new Map();
|
|
12206
|
+
function viaOfAckedOp(opId) {
|
|
12207
|
+
const via = viaByOpId.get(opId);
|
|
12208
|
+
if (via === void 0) {
|
|
12209
|
+
return "edit";
|
|
12210
|
+
}
|
|
12211
|
+
viaByOpId.delete(opId);
|
|
12212
|
+
return via;
|
|
12213
|
+
}
|
|
12214
|
+
function applyLocalOps(frames, localSource = LOCAL_EDIT) {
|
|
10787
12215
|
const [pframes, ops] = partition(
|
|
10788
12216
|
frames,
|
|
10789
12217
|
(f) => f.type === "presence"
|
|
10790
12218
|
);
|
|
10791
|
-
const
|
|
12219
|
+
const restoredTextIds = /* @__PURE__ */ new Map();
|
|
12220
|
+
for (const op of ops) {
|
|
12221
|
+
if (op.type === OpCode.CREATE_TEXT && op.opId === void 0 && context.pool.nodes.get(op.id) === void 0 && !restoredTextIds.has(op.id)) {
|
|
12222
|
+
restoredTextIds.set(op.id, context.pool.generateId());
|
|
12223
|
+
}
|
|
12224
|
+
}
|
|
12225
|
+
const remappedOps = restoredTextIds.size === 0 ? ops : ops.map((op) => {
|
|
12226
|
+
if (op.opId !== void 0) {
|
|
12227
|
+
return op;
|
|
12228
|
+
}
|
|
12229
|
+
const id = restoredTextIds.get(op.id);
|
|
12230
|
+
if (isCreateOp(op)) {
|
|
12231
|
+
const parentId = restoredTextIds.get(op.parentId);
|
|
12232
|
+
const deletedId = op.deletedId === void 0 ? void 0 : restoredTextIds.get(op.deletedId);
|
|
12233
|
+
if (id === void 0 && parentId === void 0 && deletedId === void 0) {
|
|
12234
|
+
return op;
|
|
12235
|
+
}
|
|
12236
|
+
if (op.type === OpCode.CREATE_TEXT && id !== void 0) {
|
|
12237
|
+
return {
|
|
12238
|
+
...op,
|
|
12239
|
+
id,
|
|
12240
|
+
version: 0,
|
|
12241
|
+
...parentId === void 0 ? {} : { parentId },
|
|
12242
|
+
...deletedId === void 0 ? {} : { deletedId }
|
|
12243
|
+
};
|
|
12244
|
+
}
|
|
12245
|
+
return {
|
|
12246
|
+
...op,
|
|
12247
|
+
...id === void 0 ? {} : { id },
|
|
12248
|
+
...parentId === void 0 ? {} : { parentId },
|
|
12249
|
+
...deletedId === void 0 ? {} : { deletedId }
|
|
12250
|
+
};
|
|
12251
|
+
}
|
|
12252
|
+
return id === void 0 ? op : { ...op, id };
|
|
12253
|
+
});
|
|
12254
|
+
const opsWithOpIds = remappedOps.map(
|
|
10792
12255
|
(op) => op.opId === void 0 ? { ...op, opId: context.pool.generateOpId() } : op
|
|
10793
12256
|
);
|
|
12257
|
+
if (localSource.via !== "edit") {
|
|
12258
|
+
for (const op of opsWithOpIds) {
|
|
12259
|
+
viaByOpId.set(op.opId, localSource.via);
|
|
12260
|
+
}
|
|
12261
|
+
}
|
|
10794
12262
|
const { reverse, updates } = applyOps(
|
|
10795
12263
|
pframes,
|
|
10796
12264
|
opsWithOpIds,
|
|
10797
12265
|
/* isLocal */
|
|
10798
|
-
true
|
|
12266
|
+
true,
|
|
12267
|
+
localSource
|
|
10799
12268
|
);
|
|
10800
12269
|
return { opsToEmit: opsWithOpIds, reverse, updates };
|
|
10801
12270
|
}
|
|
@@ -10807,7 +12276,7 @@ function createRoom(options, config) {
|
|
|
10807
12276
|
false
|
|
10808
12277
|
);
|
|
10809
12278
|
}
|
|
10810
|
-
function applyOps(pframes, ops, isLocal) {
|
|
12279
|
+
function applyOps(pframes, ops, isLocal, localSource = LOCAL_EDIT) {
|
|
10811
12280
|
const output = {
|
|
10812
12281
|
reverse: new Deque(),
|
|
10813
12282
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
@@ -10836,12 +12305,16 @@ function createRoom(options, config) {
|
|
|
10836
12305
|
for (const op of ops) {
|
|
10837
12306
|
let source;
|
|
10838
12307
|
if (isLocal) {
|
|
10839
|
-
source =
|
|
12308
|
+
source = { ...localSource, optimistic: true };
|
|
10840
12309
|
} else if (op.opId !== void 0) {
|
|
10841
12310
|
context.unacknowledgedOps.delete(op.opId);
|
|
10842
|
-
source =
|
|
12311
|
+
source = {
|
|
12312
|
+
origin: "local",
|
|
12313
|
+
via: viaOfAckedOp(op.opId),
|
|
12314
|
+
optimistic: false
|
|
12315
|
+
};
|
|
10843
12316
|
} else {
|
|
10844
|
-
source =
|
|
12317
|
+
source = REMOTE;
|
|
10845
12318
|
}
|
|
10846
12319
|
const applyOpResult = applyOp(op, source);
|
|
10847
12320
|
if (applyOpResult.modified) {
|
|
@@ -10856,7 +12329,7 @@ function createRoom(options, config) {
|
|
|
10856
12329
|
);
|
|
10857
12330
|
output.reverse.pushLeft(applyOpResult.reverse);
|
|
10858
12331
|
}
|
|
10859
|
-
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_FILE) {
|
|
12332
|
+
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) {
|
|
10860
12333
|
createdNodeIds.add(op.id);
|
|
10861
12334
|
}
|
|
10862
12335
|
}
|
|
@@ -10876,12 +12349,13 @@ function createRoom(options, config) {
|
|
|
10876
12349
|
switch (op.type) {
|
|
10877
12350
|
case OpCode.DELETE_OBJECT_KEY:
|
|
10878
12351
|
case OpCode.UPDATE_OBJECT:
|
|
12352
|
+
case OpCode.UPDATE_TEXT:
|
|
10879
12353
|
case OpCode.DELETE_CRDT: {
|
|
10880
12354
|
const node = context.pool.nodes.get(op.id);
|
|
10881
12355
|
if (node === void 0) {
|
|
10882
12356
|
return { modified: false };
|
|
10883
12357
|
}
|
|
10884
|
-
return node._apply(op, source
|
|
12358
|
+
return node._apply(op, source);
|
|
10885
12359
|
}
|
|
10886
12360
|
case OpCode.SET_PARENT_KEY: {
|
|
10887
12361
|
const node = context.pool.nodes.get(op.id);
|
|
@@ -10900,6 +12374,7 @@ function createRoom(options, config) {
|
|
|
10900
12374
|
case OpCode.CREATE_OBJECT:
|
|
10901
12375
|
case OpCode.CREATE_LIST:
|
|
10902
12376
|
case OpCode.CREATE_MAP:
|
|
12377
|
+
case OpCode.CREATE_TEXT:
|
|
10903
12378
|
case OpCode.CREATE_FILE:
|
|
10904
12379
|
case OpCode.CREATE_REGISTER: {
|
|
10905
12380
|
if (op.parentId === void 0) {
|
|
@@ -10935,7 +12410,7 @@ function createRoom(options, config) {
|
|
|
10935
12410
|
}
|
|
10936
12411
|
context.myPresence.patch(patch);
|
|
10937
12412
|
if (context.activeBatch) {
|
|
10938
|
-
if (_optionalChain([options2, 'optionalAccess',
|
|
12413
|
+
if (_optionalChain([options2, 'optionalAccess', _266 => _266.addToHistory])) {
|
|
10939
12414
|
context.activeBatch.reverseOps.pushLeft({
|
|
10940
12415
|
type: "presence",
|
|
10941
12416
|
data: oldValues
|
|
@@ -10944,7 +12419,7 @@ function createRoom(options, config) {
|
|
|
10944
12419
|
context.activeBatch.updates.presence = true;
|
|
10945
12420
|
} else {
|
|
10946
12421
|
flushNowOrSoon();
|
|
10947
|
-
if (_optionalChain([options2, 'optionalAccess',
|
|
12422
|
+
if (_optionalChain([options2, 'optionalAccess', _267 => _267.addToHistory])) {
|
|
10948
12423
|
addToUndoStack([{ type: "presence", data: oldValues }]);
|
|
10949
12424
|
}
|
|
10950
12425
|
notify({ presence: true });
|
|
@@ -11123,11 +12598,11 @@ function createRoom(options, config) {
|
|
|
11123
12598
|
break;
|
|
11124
12599
|
}
|
|
11125
12600
|
case ServerMsgCode.STORAGE_CHUNK:
|
|
11126
|
-
_optionalChain([stopwatch, 'optionalAccess',
|
|
12601
|
+
_optionalChain([stopwatch, 'optionalAccess', _268 => _268.lap, 'call', _269 => _269()]);
|
|
11127
12602
|
nodeMapBuffer.append(compactNodesToNodeStream(message.nodes));
|
|
11128
12603
|
break;
|
|
11129
12604
|
case ServerMsgCode.STORAGE_STREAM_END: {
|
|
11130
|
-
const timing = _optionalChain([stopwatch, 'optionalAccess',
|
|
12605
|
+
const timing = _optionalChain([stopwatch, 'optionalAccess', _270 => _270.stop, 'call', _271 => _271()]);
|
|
11131
12606
|
if (timing) {
|
|
11132
12607
|
const ms = (v) => `${v.toFixed(1)}ms`;
|
|
11133
12608
|
const rest = timing.laps.slice(1);
|
|
@@ -11154,16 +12629,38 @@ function createRoom(options, config) {
|
|
|
11154
12629
|
}
|
|
11155
12630
|
break;
|
|
11156
12631
|
}
|
|
11157
|
-
// Receiving a RejectedOps message
|
|
11158
|
-
//
|
|
11159
|
-
//
|
|
11160
|
-
//
|
|
12632
|
+
// Receiving a RejectedOps message means the server refused some of
|
|
12633
|
+
// our ops, so our optimistic local state is out of sync with the
|
|
12634
|
+
// server. For LiveText ops this is a normal (if rare) situation —
|
|
12635
|
+
// e.g. a client that was offline long enough to fall outside the
|
|
12636
|
+
// server's retained history window — and we can recover: drop the
|
|
12637
|
+
// rejected pending state and re-fetch the authoritative storage
|
|
12638
|
+
// snapshot. For other ops (e.g. permission rejections), rolling back
|
|
12639
|
+
// particular Ops is hard/impossible, so we keep the old behavior of
|
|
12640
|
+
// accepting the out-of-sync reality and surfacing an error.
|
|
11161
12641
|
case ServerMsgCode.REJECT_STORAGE_OP: {
|
|
11162
12642
|
errorWithTitle(
|
|
11163
12643
|
"Storage mutation rejection error",
|
|
11164
12644
|
message.reason
|
|
11165
12645
|
);
|
|
11166
|
-
|
|
12646
|
+
let needsStorageResync = false;
|
|
12647
|
+
for (const opId of message.opIds) {
|
|
12648
|
+
const rejectedOp = context.unacknowledgedOps.get(opId);
|
|
12649
|
+
context.unacknowledgedOps.delete(opId);
|
|
12650
|
+
context.buffer.storageOperations = context.buffer.storageOperations.filter((op) => op.opId !== opId);
|
|
12651
|
+
viaByOpId.delete(opId);
|
|
12652
|
+
if (rejectedOp !== void 0 && rejectedOp.type === OpCode.UPDATE_TEXT) {
|
|
12653
|
+
const node = context.pool.nodes.get(rejectedOp.id);
|
|
12654
|
+
if (node !== void 0 && isLiveText(node)) {
|
|
12655
|
+
node._rejectPendingOp(opId);
|
|
12656
|
+
needsStorageResync = true;
|
|
12657
|
+
}
|
|
12658
|
+
}
|
|
12659
|
+
}
|
|
12660
|
+
if (needsStorageResync) {
|
|
12661
|
+
refreshStorage();
|
|
12662
|
+
flushNowOrSoon();
|
|
12663
|
+
} else if (process.env.NODE_ENV !== "production") {
|
|
11167
12664
|
throw new Error(
|
|
11168
12665
|
`Storage mutations rejected by server: ${message.reason}`
|
|
11169
12666
|
);
|
|
@@ -11262,11 +12759,11 @@ function createRoom(options, config) {
|
|
|
11262
12759
|
} else if (pendingFeedsRequests.has(requestId)) {
|
|
11263
12760
|
const pending = pendingFeedsRequests.get(requestId);
|
|
11264
12761
|
pendingFeedsRequests.delete(requestId);
|
|
11265
|
-
_optionalChain([pending, 'optionalAccess',
|
|
12762
|
+
_optionalChain([pending, 'optionalAccess', _272 => _272.reject, 'call', _273 => _273(err)]);
|
|
11266
12763
|
} else if (pendingFeedMessagesRequests.has(requestId)) {
|
|
11267
12764
|
const pending = pendingFeedMessagesRequests.get(requestId);
|
|
11268
12765
|
pendingFeedMessagesRequests.delete(requestId);
|
|
11269
|
-
_optionalChain([pending, 'optionalAccess',
|
|
12766
|
+
_optionalChain([pending, 'optionalAccess', _274 => _274.reject, 'call', _275 => _275(err)]);
|
|
11270
12767
|
}
|
|
11271
12768
|
eventHub.feeds.notify(message);
|
|
11272
12769
|
break;
|
|
@@ -11420,10 +12917,10 @@ function createRoom(options, config) {
|
|
|
11420
12917
|
timeoutId,
|
|
11421
12918
|
kind,
|
|
11422
12919
|
feedId,
|
|
11423
|
-
messageId: _optionalChain([options2, 'optionalAccess',
|
|
11424
|
-
expectedClientMessageId: _optionalChain([options2, 'optionalAccess',
|
|
12920
|
+
messageId: _optionalChain([options2, 'optionalAccess', _276 => _276.messageId]),
|
|
12921
|
+
expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _277 => _277.expectedClientMessageId])
|
|
11425
12922
|
});
|
|
11426
|
-
if (kind === "add-message" && _optionalChain([options2, 'optionalAccess',
|
|
12923
|
+
if (kind === "add-message" && _optionalChain([options2, 'optionalAccess', _278 => _278.expectedClientMessageId]) === void 0) {
|
|
11427
12924
|
const q = _nullishCoalesce(pendingAddMessageFifoByFeed.get(feedId), () => ( []));
|
|
11428
12925
|
q.push(requestId);
|
|
11429
12926
|
pendingAddMessageFifoByFeed.set(feedId, q);
|
|
@@ -11474,10 +12971,10 @@ function createRoom(options, config) {
|
|
|
11474
12971
|
}
|
|
11475
12972
|
if (!matched) {
|
|
11476
12973
|
const q = pendingAddMessageFifoByFeed.get(message.feedId);
|
|
11477
|
-
const headId = _optionalChain([q, 'optionalAccess',
|
|
12974
|
+
const headId = _optionalChain([q, 'optionalAccess', _279 => _279[0]]);
|
|
11478
12975
|
if (headId !== void 0) {
|
|
11479
12976
|
const pending = pendingFeedMutations.get(headId);
|
|
11480
|
-
if (_optionalChain([pending, 'optionalAccess',
|
|
12977
|
+
if (_optionalChain([pending, 'optionalAccess', _280 => _280.kind]) === "add-message" && pending.expectedClientMessageId === void 0) {
|
|
11481
12978
|
settleFeedMutation(headId, "ok");
|
|
11482
12979
|
}
|
|
11483
12980
|
}
|
|
@@ -11513,7 +13010,7 @@ function createRoom(options, config) {
|
|
|
11513
13010
|
const unacknowledgedOps2 = [...context.unacknowledgedOps.values()];
|
|
11514
13011
|
createOrUpdateRootFromMessage(nodes);
|
|
11515
13012
|
applyAndSendOfflineOps(unacknowledgedOps2);
|
|
11516
|
-
_optionalChain([_resolveStoragePromise, 'optionalCall',
|
|
13013
|
+
_optionalChain([_resolveStoragePromise, 'optionalCall', _281 => _281()]);
|
|
11517
13014
|
notifyStorageStatus();
|
|
11518
13015
|
eventHub.storageDidLoad.notify();
|
|
11519
13016
|
}
|
|
@@ -11522,7 +13019,7 @@ function createRoom(options, config) {
|
|
|
11522
13019
|
if (!messages.some((msg) => msg.type === ClientMsgCode.FETCH_STORAGE)) {
|
|
11523
13020
|
messages.push({ type: ClientMsgCode.FETCH_STORAGE });
|
|
11524
13021
|
nodeMapBuffer.take();
|
|
11525
|
-
_optionalChain([stopwatch, 'optionalAccess',
|
|
13022
|
+
_optionalChain([stopwatch, 'optionalAccess', _282 => _282.start, 'call', _283 => _283()]);
|
|
11526
13023
|
}
|
|
11527
13024
|
}
|
|
11528
13025
|
function startLoadingStorage() {
|
|
@@ -11576,10 +13073,10 @@ function createRoom(options, config) {
|
|
|
11576
13073
|
const message = {
|
|
11577
13074
|
type: ClientMsgCode.FETCH_FEEDS,
|
|
11578
13075
|
requestId,
|
|
11579
|
-
cursor: _optionalChain([options2, 'optionalAccess',
|
|
11580
|
-
since: _optionalChain([options2, 'optionalAccess',
|
|
11581
|
-
limit: _optionalChain([options2, 'optionalAccess',
|
|
11582
|
-
metadata: _optionalChain([options2, 'optionalAccess',
|
|
13076
|
+
cursor: _optionalChain([options2, 'optionalAccess', _284 => _284.cursor]),
|
|
13077
|
+
since: _optionalChain([options2, 'optionalAccess', _285 => _285.since]),
|
|
13078
|
+
limit: _optionalChain([options2, 'optionalAccess', _286 => _286.limit]),
|
|
13079
|
+
metadata: _optionalChain([options2, 'optionalAccess', _287 => _287.metadata])
|
|
11583
13080
|
};
|
|
11584
13081
|
context.buffer.messages.push(message);
|
|
11585
13082
|
flushNowOrSoon();
|
|
@@ -11599,9 +13096,9 @@ function createRoom(options, config) {
|
|
|
11599
13096
|
type: ClientMsgCode.FETCH_FEED_MESSAGES,
|
|
11600
13097
|
requestId,
|
|
11601
13098
|
feedId,
|
|
11602
|
-
cursor: _optionalChain([options2, 'optionalAccess',
|
|
11603
|
-
since: _optionalChain([options2, 'optionalAccess',
|
|
11604
|
-
limit: _optionalChain([options2, 'optionalAccess',
|
|
13099
|
+
cursor: _optionalChain([options2, 'optionalAccess', _288 => _288.cursor]),
|
|
13100
|
+
since: _optionalChain([options2, 'optionalAccess', _289 => _289.since]),
|
|
13101
|
+
limit: _optionalChain([options2, 'optionalAccess', _290 => _290.limit])
|
|
11605
13102
|
};
|
|
11606
13103
|
context.buffer.messages.push(message);
|
|
11607
13104
|
flushNowOrSoon();
|
|
@@ -11620,8 +13117,8 @@ function createRoom(options, config) {
|
|
|
11620
13117
|
type: ClientMsgCode.ADD_FEED,
|
|
11621
13118
|
requestId,
|
|
11622
13119
|
feedId,
|
|
11623
|
-
metadata: _optionalChain([options2, 'optionalAccess',
|
|
11624
|
-
createdAt: _optionalChain([options2, 'optionalAccess',
|
|
13120
|
+
metadata: _optionalChain([options2, 'optionalAccess', _291 => _291.metadata]),
|
|
13121
|
+
createdAt: _optionalChain([options2, 'optionalAccess', _292 => _292.createdAt])
|
|
11625
13122
|
};
|
|
11626
13123
|
context.buffer.messages.push(message);
|
|
11627
13124
|
flushNowOrSoon();
|
|
@@ -11655,15 +13152,15 @@ function createRoom(options, config) {
|
|
|
11655
13152
|
function addFeedMessage(feedId, data, options2) {
|
|
11656
13153
|
const requestId = nanoid();
|
|
11657
13154
|
const promise = registerFeedMutation(requestId, "add-message", feedId, {
|
|
11658
|
-
expectedClientMessageId: _optionalChain([options2, 'optionalAccess',
|
|
13155
|
+
expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _293 => _293.id])
|
|
11659
13156
|
});
|
|
11660
13157
|
const message = {
|
|
11661
13158
|
type: ClientMsgCode.ADD_FEED_MESSAGE,
|
|
11662
13159
|
requestId,
|
|
11663
13160
|
feedId,
|
|
11664
13161
|
data,
|
|
11665
|
-
id: _optionalChain([options2, 'optionalAccess',
|
|
11666
|
-
createdAt: _optionalChain([options2, 'optionalAccess',
|
|
13162
|
+
id: _optionalChain([options2, 'optionalAccess', _294 => _294.id]),
|
|
13163
|
+
createdAt: _optionalChain([options2, 'optionalAccess', _295 => _295.createdAt])
|
|
11667
13164
|
};
|
|
11668
13165
|
context.buffer.messages.push(message);
|
|
11669
13166
|
flushNowOrSoon();
|
|
@@ -11680,7 +13177,7 @@ function createRoom(options, config) {
|
|
|
11680
13177
|
feedId,
|
|
11681
13178
|
messageId,
|
|
11682
13179
|
data,
|
|
11683
|
-
updatedAt: _optionalChain([options2, 'optionalAccess',
|
|
13180
|
+
updatedAt: _optionalChain([options2, 'optionalAccess', _296 => _296.updatedAt])
|
|
11684
13181
|
};
|
|
11685
13182
|
context.buffer.messages.push(message);
|
|
11686
13183
|
flushNowOrSoon();
|
|
@@ -11705,14 +13202,15 @@ function createRoom(options, config) {
|
|
|
11705
13202
|
if (context.activeBatch) {
|
|
11706
13203
|
throw new Error("undo is not allowed during a batch");
|
|
11707
13204
|
}
|
|
11708
|
-
const
|
|
11709
|
-
if (
|
|
13205
|
+
const item = context.undoStack.pop();
|
|
13206
|
+
if (item === void 0) {
|
|
11710
13207
|
return;
|
|
11711
13208
|
}
|
|
11712
13209
|
context.pausedHistory = null;
|
|
11713
|
-
const result = applyLocalOps(frames);
|
|
13210
|
+
const result = applyLocalOps(item.frames, LOCAL_UNDO);
|
|
13211
|
+
context.redoStack.push({ id: item.id, frames: result.reverse });
|
|
13212
|
+
notifyPrivateHistory({ action: "undo", id: item.id });
|
|
11714
13213
|
notify(result.updates);
|
|
11715
|
-
context.redoStack.push(result.reverse);
|
|
11716
13214
|
onHistoryChange();
|
|
11717
13215
|
for (const op of result.opsToEmit) {
|
|
11718
13216
|
context.buffer.storageOperations.push(op);
|
|
@@ -11723,14 +13221,15 @@ function createRoom(options, config) {
|
|
|
11723
13221
|
if (context.activeBatch) {
|
|
11724
13222
|
throw new Error("redo is not allowed during a batch");
|
|
11725
13223
|
}
|
|
11726
|
-
const
|
|
11727
|
-
if (
|
|
13224
|
+
const item = context.redoStack.pop();
|
|
13225
|
+
if (item === void 0) {
|
|
11728
13226
|
return;
|
|
11729
13227
|
}
|
|
11730
13228
|
context.pausedHistory = null;
|
|
11731
|
-
const result = applyLocalOps(frames);
|
|
13229
|
+
const result = applyLocalOps(item.frames, LOCAL_REDO);
|
|
13230
|
+
context.undoStack.push({ id: item.id, frames: result.reverse });
|
|
13231
|
+
notifyPrivateHistory({ action: "redo", id: item.id });
|
|
11732
13232
|
notify(result.updates);
|
|
11733
|
-
context.undoStack.push(result.reverse);
|
|
11734
13233
|
onHistoryChange();
|
|
11735
13234
|
for (const op of result.opsToEmit) {
|
|
11736
13235
|
context.buffer.storageOperations.push(op);
|
|
@@ -11740,6 +13239,8 @@ function createRoom(options, config) {
|
|
|
11740
13239
|
function clear() {
|
|
11741
13240
|
context.undoStack.length = 0;
|
|
11742
13241
|
context.redoStack.length = 0;
|
|
13242
|
+
notifyPrivateHistory({ action: "clear" });
|
|
13243
|
+
onHistoryChange();
|
|
11743
13244
|
}
|
|
11744
13245
|
function batch2(callback) {
|
|
11745
13246
|
if (context.activeBatch) {
|
|
@@ -11767,8 +13268,8 @@ function createRoom(options, config) {
|
|
|
11767
13268
|
if (currentBatch.scheduleHistoryResume) {
|
|
11768
13269
|
commitPausedHistoryToUndoStack();
|
|
11769
13270
|
}
|
|
11770
|
-
if (currentBatch.ops.length > 0) {
|
|
11771
|
-
|
|
13271
|
+
if (currentBatch.ops.length > 0 || currentBatch.clearRedoStack) {
|
|
13272
|
+
clearRedoStack();
|
|
11772
13273
|
}
|
|
11773
13274
|
if (currentBatch.ops.length > 0) {
|
|
11774
13275
|
dispatchOps(currentBatch.ops);
|
|
@@ -11797,7 +13298,6 @@ function createRoom(options, config) {
|
|
|
11797
13298
|
}
|
|
11798
13299
|
commitPausedHistoryToUndoStack();
|
|
11799
13300
|
}
|
|
11800
|
-
let historyDisabled = 0;
|
|
11801
13301
|
function disableHistory(fn) {
|
|
11802
13302
|
const origUndo = context.undoStack;
|
|
11803
13303
|
const origRedo = context.redoStack;
|
|
@@ -11887,8 +13387,8 @@ function createRoom(options, config) {
|
|
|
11887
13387
|
async function getThreads(options2) {
|
|
11888
13388
|
return httpClient.getThreads({
|
|
11889
13389
|
roomId,
|
|
11890
|
-
query: _optionalChain([options2, 'optionalAccess',
|
|
11891
|
-
cursor: _optionalChain([options2, 'optionalAccess',
|
|
13390
|
+
query: _optionalChain([options2, 'optionalAccess', _297 => _297.query]),
|
|
13391
|
+
cursor: _optionalChain([options2, 'optionalAccess', _298 => _298.cursor])
|
|
11892
13392
|
});
|
|
11893
13393
|
}
|
|
11894
13394
|
async function getThread(threadId) {
|
|
@@ -12021,7 +13521,7 @@ function createRoom(options, config) {
|
|
|
12021
13521
|
function getSubscriptionSettings(options2) {
|
|
12022
13522
|
return httpClient.getSubscriptionSettings({
|
|
12023
13523
|
roomId,
|
|
12024
|
-
signal: _optionalChain([options2, 'optionalAccess',
|
|
13524
|
+
signal: _optionalChain([options2, 'optionalAccess', _299 => _299.signal])
|
|
12025
13525
|
});
|
|
12026
13526
|
}
|
|
12027
13527
|
function updateSubscriptionSettings(settings) {
|
|
@@ -12043,30 +13543,45 @@ function createRoom(options, config) {
|
|
|
12043
13543
|
{
|
|
12044
13544
|
[kInternal]: {
|
|
12045
13545
|
get presenceBuffer() {
|
|
12046
|
-
return deepClone(_nullishCoalesce(_optionalChain([context, 'access',
|
|
13546
|
+
return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _300 => _300.buffer, 'access', _301 => _301.presenceUpdates, 'optionalAccess', _302 => _302.data]), () => ( null)));
|
|
12047
13547
|
},
|
|
12048
13548
|
// prettier-ignore
|
|
12049
13549
|
get undoStack() {
|
|
12050
|
-
return
|
|
13550
|
+
return structuredClone(
|
|
13551
|
+
context.undoStack.map((item) => ({
|
|
13552
|
+
id: item.id,
|
|
13553
|
+
frames: item.frames
|
|
13554
|
+
}))
|
|
13555
|
+
);
|
|
13556
|
+
},
|
|
13557
|
+
// prettier-ignore
|
|
13558
|
+
get redoStack() {
|
|
13559
|
+
return structuredClone(
|
|
13560
|
+
context.redoStack.map((item) => ({
|
|
13561
|
+
id: item.id,
|
|
13562
|
+
frames: item.frames
|
|
13563
|
+
}))
|
|
13564
|
+
);
|
|
12051
13565
|
},
|
|
12052
13566
|
// prettier-ignore
|
|
12053
13567
|
get nodeCount() {
|
|
12054
13568
|
return context.pool.nodes.size;
|
|
12055
13569
|
},
|
|
12056
13570
|
// prettier-ignore
|
|
13571
|
+
history: eventHub.privateHistory.observable,
|
|
12057
13572
|
getYjsProvider() {
|
|
12058
13573
|
return context.yjsProvider;
|
|
12059
13574
|
},
|
|
12060
13575
|
setYjsProvider(newProvider) {
|
|
12061
|
-
_optionalChain([context, 'access',
|
|
13576
|
+
_optionalChain([context, 'access', _303 => _303.yjsProvider, 'optionalAccess', _304 => _304.off, 'call', _305 => _305("status", yjsStatusDidChange)]);
|
|
12062
13577
|
context.yjsProvider = newProvider;
|
|
12063
|
-
_optionalChain([newProvider, 'optionalAccess',
|
|
13578
|
+
_optionalChain([newProvider, 'optionalAccess', _306 => _306.on, 'call', _307 => _307("status", yjsStatusDidChange)]);
|
|
12064
13579
|
context.yjsProviderDidChange.notify();
|
|
12065
13580
|
},
|
|
12066
13581
|
yjsProviderDidChange: context.yjsProviderDidChange.observable,
|
|
12067
13582
|
// send metadata when using a text editor
|
|
12068
13583
|
reportTextEditor,
|
|
12069
|
-
getPermissionMatrix: () => _optionalChain([context, 'access',
|
|
13584
|
+
getPermissionMatrix: () => _optionalChain([context, 'access', _308 => _308.dynamicSessionInfoSig, 'access', _309 => _309.get, 'call', _310 => _310(), 'optionalAccess', _311 => _311.permissionMatrix]),
|
|
12070
13585
|
// create a text mention when using a text editor
|
|
12071
13586
|
createTextMention,
|
|
12072
13587
|
// delete a text mention when using a text editor
|
|
@@ -12129,7 +13644,7 @@ ${dumpPool(
|
|
|
12129
13644
|
source.dispose();
|
|
12130
13645
|
}
|
|
12131
13646
|
eventHub.roomWillDestroy.notify();
|
|
12132
|
-
_optionalChain([context, 'access',
|
|
13647
|
+
_optionalChain([context, 'access', _312 => _312.yjsProvider, 'optionalAccess', _313 => _313.off, 'call', _314 => _314("status", yjsStatusDidChange)]);
|
|
12133
13648
|
syncSourceForStorage.destroy();
|
|
12134
13649
|
syncSourceForYjs.destroy();
|
|
12135
13650
|
uninstallBgTabSpy();
|
|
@@ -12293,7 +13808,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
|
|
|
12293
13808
|
}
|
|
12294
13809
|
if (isLiveNode(first)) {
|
|
12295
13810
|
const node = first;
|
|
12296
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
13811
|
+
if (_optionalChain([options, 'optionalAccess', _315 => _315.isDeep])) {
|
|
12297
13812
|
const storageCallback = second;
|
|
12298
13813
|
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
12299
13814
|
} else {
|
|
@@ -12383,8 +13898,8 @@ function createClient(options) {
|
|
|
12383
13898
|
const authManager = createAuthManager(options, (token) => {
|
|
12384
13899
|
currentUserId.set(() => token.uid);
|
|
12385
13900
|
});
|
|
12386
|
-
const fetchPolyfill = _optionalChain([clientOptions, 'access',
|
|
12387
|
-
_optionalChain([globalThis, 'access',
|
|
13901
|
+
const fetchPolyfill = _optionalChain([clientOptions, 'access', _316 => _316.polyfills, 'optionalAccess', _317 => _317.fetch]) || /* istanbul ignore next */
|
|
13902
|
+
_optionalChain([globalThis, 'access', _318 => _318.fetch, 'optionalAccess', _319 => _319.bind, 'call', _320 => _320(globalThis)]);
|
|
12388
13903
|
const httpClient = createApiClient({
|
|
12389
13904
|
baseUrl,
|
|
12390
13905
|
fetchPolyfill,
|
|
@@ -12401,7 +13916,7 @@ function createClient(options) {
|
|
|
12401
13916
|
delegates: {
|
|
12402
13917
|
createSocket: makeCreateSocketDelegateForAi(
|
|
12403
13918
|
baseUrl,
|
|
12404
|
-
_optionalChain([clientOptions, 'access',
|
|
13919
|
+
_optionalChain([clientOptions, 'access', _321 => _321.polyfills, 'optionalAccess', _322 => _322.WebSocket])
|
|
12405
13920
|
),
|
|
12406
13921
|
authenticate: async () => {
|
|
12407
13922
|
const resp = await authManager.getAuthValue({
|
|
@@ -12472,7 +13987,7 @@ function createClient(options) {
|
|
|
12472
13987
|
createSocket: makeCreateSocketDelegateForRoom(
|
|
12473
13988
|
roomId,
|
|
12474
13989
|
baseUrl,
|
|
12475
|
-
_optionalChain([clientOptions, 'access',
|
|
13990
|
+
_optionalChain([clientOptions, 'access', _323 => _323.polyfills, 'optionalAccess', _324 => _324.WebSocket])
|
|
12476
13991
|
),
|
|
12477
13992
|
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
12478
13993
|
})),
|
|
@@ -12494,7 +14009,7 @@ function createClient(options) {
|
|
|
12494
14009
|
const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
|
|
12495
14010
|
if (shouldConnect) {
|
|
12496
14011
|
if (typeof atob === "undefined") {
|
|
12497
|
-
if (_optionalChain([clientOptions, 'access',
|
|
14012
|
+
if (_optionalChain([clientOptions, 'access', _325 => _325.polyfills, 'optionalAccess', _326 => _326.atob]) === void 0) {
|
|
12498
14013
|
throw new Error(
|
|
12499
14014
|
"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"
|
|
12500
14015
|
);
|
|
@@ -12506,7 +14021,7 @@ function createClient(options) {
|
|
|
12506
14021
|
return leaseRoom(newRoomDetails);
|
|
12507
14022
|
}
|
|
12508
14023
|
function getRoom(roomId) {
|
|
12509
|
-
const room = _optionalChain([roomsById, 'access',
|
|
14024
|
+
const room = _optionalChain([roomsById, 'access', _327 => _327.get, 'call', _328 => _328(roomId), 'optionalAccess', _329 => _329.room]);
|
|
12510
14025
|
return room ? room : null;
|
|
12511
14026
|
}
|
|
12512
14027
|
function logout() {
|
|
@@ -12522,7 +14037,7 @@ function createClient(options) {
|
|
|
12522
14037
|
const batchedResolveUsers = new Batch(
|
|
12523
14038
|
async (batchedUserIds) => {
|
|
12524
14039
|
const userIds = batchedUserIds.flat();
|
|
12525
|
-
const users = await _optionalChain([resolveUsers, 'optionalCall',
|
|
14040
|
+
const users = await _optionalChain([resolveUsers, 'optionalCall', _330 => _330({ userIds })]);
|
|
12526
14041
|
warnOnceIf(
|
|
12527
14042
|
!resolveUsers,
|
|
12528
14043
|
"Set the resolveUsers option in createClient to specify user info."
|
|
@@ -12539,7 +14054,7 @@ function createClient(options) {
|
|
|
12539
14054
|
const batchedResolveRoomsInfo = new Batch(
|
|
12540
14055
|
async (batchedRoomIds) => {
|
|
12541
14056
|
const roomIds = batchedRoomIds.flat();
|
|
12542
|
-
const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall',
|
|
14057
|
+
const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _331 => _331({ roomIds })]);
|
|
12543
14058
|
warnOnceIf(
|
|
12544
14059
|
!resolveRoomsInfo,
|
|
12545
14060
|
"Set the resolveRoomsInfo option in createClient to specify room info."
|
|
@@ -12556,7 +14071,7 @@ function createClient(options) {
|
|
|
12556
14071
|
const batchedResolveGroupsInfo = new Batch(
|
|
12557
14072
|
async (batchedGroupIds) => {
|
|
12558
14073
|
const groupIds = batchedGroupIds.flat();
|
|
12559
|
-
const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall',
|
|
14074
|
+
const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _332 => _332({ groupIds })]);
|
|
12560
14075
|
warnOnceIf(
|
|
12561
14076
|
!resolveGroupsInfo,
|
|
12562
14077
|
"Set the resolveGroupsInfo option in createClient to specify group info."
|
|
@@ -12615,7 +14130,7 @@ function createClient(options) {
|
|
|
12615
14130
|
}
|
|
12616
14131
|
};
|
|
12617
14132
|
const win = typeof window !== "undefined" ? window : void 0;
|
|
12618
|
-
_optionalChain([win, 'optionalAccess',
|
|
14133
|
+
_optionalChain([win, 'optionalAccess', _333 => _333.addEventListener, 'call', _334 => _334("beforeunload", maybePreventClose)]);
|
|
12619
14134
|
}
|
|
12620
14135
|
async function getNotificationSettings(options2) {
|
|
12621
14136
|
const plainSettings = await httpClient.getNotificationSettings(options2);
|
|
@@ -12743,7 +14258,7 @@ var commentBodyElementsTypes = {
|
|
|
12743
14258
|
mention: "inline"
|
|
12744
14259
|
};
|
|
12745
14260
|
function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
12746
|
-
if (!body || !_optionalChain([body, 'optionalAccess',
|
|
14261
|
+
if (!body || !_optionalChain([body, 'optionalAccess', _335 => _335.content])) {
|
|
12747
14262
|
return;
|
|
12748
14263
|
}
|
|
12749
14264
|
const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
|
|
@@ -12753,13 +14268,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
|
12753
14268
|
for (const block of body.content) {
|
|
12754
14269
|
if (type === "all" || type === "block") {
|
|
12755
14270
|
if (guard(block)) {
|
|
12756
|
-
_optionalChain([visitor, 'optionalCall',
|
|
14271
|
+
_optionalChain([visitor, 'optionalCall', _336 => _336(block)]);
|
|
12757
14272
|
}
|
|
12758
14273
|
}
|
|
12759
14274
|
if (type === "all" || type === "inline") {
|
|
12760
14275
|
for (const inline of block.children) {
|
|
12761
14276
|
if (guard(inline)) {
|
|
12762
|
-
_optionalChain([visitor, 'optionalCall',
|
|
14277
|
+
_optionalChain([visitor, 'optionalCall', _337 => _337(inline)]);
|
|
12763
14278
|
}
|
|
12764
14279
|
}
|
|
12765
14280
|
}
|
|
@@ -12929,7 +14444,7 @@ var stringifyCommentBodyPlainElements = {
|
|
|
12929
14444
|
text: ({ element }) => element.text,
|
|
12930
14445
|
link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
|
|
12931
14446
|
mention: ({ element, user, group }) => {
|
|
12932
|
-
return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
14447
|
+
return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _338 => _338.name]), () => ( _optionalChain([group, 'optionalAccess', _339 => _339.name]))), () => ( element.id))}`;
|
|
12933
14448
|
}
|
|
12934
14449
|
};
|
|
12935
14450
|
var stringifyCommentBodyHtmlElements = {
|
|
@@ -12959,7 +14474,7 @@ var stringifyCommentBodyHtmlElements = {
|
|
|
12959
14474
|
return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
|
|
12960
14475
|
},
|
|
12961
14476
|
mention: ({ element, user, group }) => {
|
|
12962
|
-
return html`<span data-mention>@${_optionalChain([user, 'optionalAccess',
|
|
14477
|
+
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>`;
|
|
12963
14478
|
}
|
|
12964
14479
|
};
|
|
12965
14480
|
var stringifyCommentBodyMarkdownElements = {
|
|
@@ -12989,20 +14504,20 @@ var stringifyCommentBodyMarkdownElements = {
|
|
|
12989
14504
|
return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
|
|
12990
14505
|
},
|
|
12991
14506
|
mention: ({ element, user, group }) => {
|
|
12992
|
-
return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
14507
|
+
return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _344 => _344.name]), () => ( _optionalChain([group, 'optionalAccess', _345 => _345.name]))), () => ( element.id))}`;
|
|
12993
14508
|
}
|
|
12994
14509
|
};
|
|
12995
14510
|
async function stringifyCommentBody(body, options) {
|
|
12996
|
-
const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
12997
|
-
const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
14511
|
+
const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _346 => _346.format]), () => ( "plain"));
|
|
14512
|
+
const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _347 => _347.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
|
|
12998
14513
|
const elements = {
|
|
12999
14514
|
...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
|
|
13000
|
-
..._optionalChain([options, 'optionalAccess',
|
|
14515
|
+
..._optionalChain([options, 'optionalAccess', _348 => _348.elements])
|
|
13001
14516
|
};
|
|
13002
14517
|
const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
|
|
13003
14518
|
body,
|
|
13004
|
-
_optionalChain([options, 'optionalAccess',
|
|
13005
|
-
_optionalChain([options, 'optionalAccess',
|
|
14519
|
+
_optionalChain([options, 'optionalAccess', _349 => _349.resolveUsers]),
|
|
14520
|
+
_optionalChain([options, 'optionalAccess', _350 => _350.resolveGroupsInfo])
|
|
13006
14521
|
);
|
|
13007
14522
|
const blocks = body.content.flatMap((block, blockIndex) => {
|
|
13008
14523
|
switch (block.type) {
|
|
@@ -13084,6 +14599,12 @@ function toPlainLson(lson) {
|
|
|
13084
14599
|
liveblocksType: "LiveList",
|
|
13085
14600
|
data: [...lson].map((item) => toPlainLson(item))
|
|
13086
14601
|
};
|
|
14602
|
+
} else if (lson instanceof LiveText) {
|
|
14603
|
+
return {
|
|
14604
|
+
liveblocksType: "LiveText",
|
|
14605
|
+
data: lson.toJSON(),
|
|
14606
|
+
version: lson.version
|
|
14607
|
+
};
|
|
13087
14608
|
} else if (lson instanceof LiveFile) {
|
|
13088
14609
|
return {
|
|
13089
14610
|
liveblocksType: "LiveFile",
|
|
@@ -13142,9 +14663,9 @@ function makePoller(callback, intervalMs, options) {
|
|
|
13142
14663
|
const startTime = performance.now();
|
|
13143
14664
|
const doc = typeof document !== "undefined" ? document : void 0;
|
|
13144
14665
|
const win = typeof window !== "undefined" ? window : void 0;
|
|
13145
|
-
const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
14666
|
+
const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _351 => _351.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
|
|
13146
14667
|
const context = {
|
|
13147
|
-
inForeground: _optionalChain([doc, 'optionalAccess',
|
|
14668
|
+
inForeground: _optionalChain([doc, 'optionalAccess', _352 => _352.visibilityState]) !== "hidden",
|
|
13148
14669
|
lastSuccessfulPollAt: startTime,
|
|
13149
14670
|
count: 0,
|
|
13150
14671
|
backoff: 0
|
|
@@ -13225,11 +14746,11 @@ function makePoller(callback, intervalMs, options) {
|
|
|
13225
14746
|
pollNowIfStale();
|
|
13226
14747
|
}
|
|
13227
14748
|
function onVisibilityChange() {
|
|
13228
|
-
setInForeground(_optionalChain([doc, 'optionalAccess',
|
|
14749
|
+
setInForeground(_optionalChain([doc, 'optionalAccess', _353 => _353.visibilityState]) !== "hidden");
|
|
13229
14750
|
}
|
|
13230
|
-
_optionalChain([doc, 'optionalAccess',
|
|
13231
|
-
_optionalChain([win, 'optionalAccess',
|
|
13232
|
-
_optionalChain([win, 'optionalAccess',
|
|
14751
|
+
_optionalChain([doc, 'optionalAccess', _354 => _354.addEventListener, 'call', _355 => _355("visibilitychange", onVisibilityChange)]);
|
|
14752
|
+
_optionalChain([win, 'optionalAccess', _356 => _356.addEventListener, 'call', _357 => _357("online", onVisibilityChange)]);
|
|
14753
|
+
_optionalChain([win, 'optionalAccess', _358 => _358.addEventListener, 'call', _359 => _359("focus", pollNowIfStale)]);
|
|
13233
14754
|
fsm.start();
|
|
13234
14755
|
return {
|
|
13235
14756
|
inc,
|
|
@@ -13378,5 +14899,10 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
|
13378
14899
|
|
|
13379
14900
|
|
|
13380
14901
|
|
|
13381
|
-
|
|
14902
|
+
|
|
14903
|
+
|
|
14904
|
+
|
|
14905
|
+
|
|
14906
|
+
|
|
14907
|
+
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;
|
|
13382
14908
|
//# sourceMappingURL=index.cjs.map
|