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