@liveblocks/core 3.23.0 → 3.23.1-exp2
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 +1849 -376
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +613 -274
- package/dist/index.d.ts +613 -274
- package/dist/index.js +1777 -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.1-exp2";
|
|
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,1361 @@ 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 invertTextOperations(segments, ops) {
|
|
9742
|
+
let shadow = [...segments];
|
|
9743
|
+
const reverse = [];
|
|
9744
|
+
for (const op of ops) {
|
|
9745
|
+
if (op.type === "insert") {
|
|
9746
|
+
shadow = applyInsert(shadow, op.index, op.text, op.attributes);
|
|
9747
|
+
reverse.unshift({
|
|
9748
|
+
type: "delete",
|
|
9749
|
+
index: op.index,
|
|
9750
|
+
length: op.text.length
|
|
9751
|
+
});
|
|
9752
|
+
} else if (op.type === "delete") {
|
|
9753
|
+
const deletedSegments = extractDeletedSegments(
|
|
9754
|
+
shadow,
|
|
9755
|
+
op.index,
|
|
9756
|
+
op.length
|
|
9757
|
+
);
|
|
9758
|
+
shadow = applyDelete(shadow, op.index, op.length).segments;
|
|
9759
|
+
const inserts = [];
|
|
9760
|
+
let insertIndex = op.index;
|
|
9761
|
+
for (const segment of deletedSegments) {
|
|
9762
|
+
inserts.push({
|
|
9763
|
+
type: "insert",
|
|
9764
|
+
index: insertIndex,
|
|
9765
|
+
text: segment.text,
|
|
9766
|
+
attributes: segment.attributes
|
|
9767
|
+
});
|
|
9768
|
+
insertIndex += segment.text.length;
|
|
9769
|
+
}
|
|
9770
|
+
for (let index = inserts.length - 1; index >= 0; index--) {
|
|
9771
|
+
reverse.unshift(inserts[index]);
|
|
9772
|
+
}
|
|
9773
|
+
} else {
|
|
9774
|
+
const inverse = formatReverseOperations(
|
|
9775
|
+
shadow,
|
|
9776
|
+
op.index,
|
|
9777
|
+
op.length,
|
|
9778
|
+
op.attributes
|
|
9779
|
+
);
|
|
9780
|
+
shadow = applyFormat(shadow, op.index, op.length, op.attributes);
|
|
9781
|
+
reverse.unshift(...inverse.reverse());
|
|
9782
|
+
}
|
|
9783
|
+
}
|
|
9784
|
+
return reverse;
|
|
9785
|
+
}
|
|
9786
|
+
|
|
9787
|
+
// src/crdts/LiveText.ts
|
|
9788
|
+
var ACCEPTED_OPS_HISTORY_LIMIT = 1e3;
|
|
9789
|
+
var LiveText = class _LiveText extends AbstractCrdt {
|
|
9790
|
+
/** The local document: #confirmed ⊕ #inFlightOps ⊕ #queuedOps. */
|
|
9791
|
+
#segments;
|
|
9792
|
+
/** The server-confirmed document (only authoritative ops applied). */
|
|
9793
|
+
#confirmed;
|
|
9794
|
+
#version;
|
|
9795
|
+
/** The op currently awaiting server acknowledgement (at most one). */
|
|
9796
|
+
#inFlightOpId;
|
|
9797
|
+
/** Its ops, continuously re-expressed against current server state. */
|
|
9798
|
+
#inFlightOps = [];
|
|
9799
|
+
/** Local edits made while an op is in flight; sent after the ack. */
|
|
9800
|
+
#queuedOps = [];
|
|
9801
|
+
#acceptedOps = [];
|
|
9802
|
+
/**
|
|
9803
|
+
* Creates a new LiveText document.
|
|
9804
|
+
*
|
|
9805
|
+
* @param textOrData Initial plain text, or an array of `[text]` /
|
|
9806
|
+
* `[text, attributes]` segments. Defaults to an empty document.
|
|
9807
|
+
*
|
|
9808
|
+
* @example
|
|
9809
|
+
* new LiveText();
|
|
9810
|
+
* new LiveText("Hello world");
|
|
9811
|
+
* new LiveText([["Hello ", { bold: true }], ["world"]]);
|
|
9812
|
+
*/
|
|
9813
|
+
constructor(textOrData = "", version = 0) {
|
|
9814
|
+
super();
|
|
9815
|
+
this.#segments = typeof textOrData === "string" ? textOrData.length === 0 ? [] : [{ text: textOrData }] : dataToSegments(textOrData);
|
|
9816
|
+
this.#confirmed = [...this.#segments];
|
|
9817
|
+
this.#version = version;
|
|
9818
|
+
Object.assign(this[kInternal], {
|
|
9819
|
+
encodeIndex: (localIndex) => this.#encodeIndex(localIndex),
|
|
9820
|
+
decodeIndex: (index, fromVersion) => this.#decodeIndex(index, fromVersion)
|
|
9821
|
+
});
|
|
9822
|
+
}
|
|
9823
|
+
get version() {
|
|
9824
|
+
return this.#version;
|
|
9825
|
+
}
|
|
9826
|
+
get length() {
|
|
9827
|
+
return textLength(this.#segments);
|
|
9828
|
+
}
|
|
9829
|
+
/** @internal */
|
|
9830
|
+
static _deserialize([id, item], _parentToChildren, pool) {
|
|
9831
|
+
const text = new _LiveText(item.data, item.version);
|
|
9832
|
+
text._attach(id, pool);
|
|
9833
|
+
return text;
|
|
9834
|
+
}
|
|
9835
|
+
/** @internal */
|
|
9836
|
+
_toOps(parentId, parentKey) {
|
|
9837
|
+
if (this._id === void 0) {
|
|
9838
|
+
throw new Error("Cannot serialize LiveText if it is not attached");
|
|
9839
|
+
}
|
|
9840
|
+
return [
|
|
9841
|
+
{
|
|
9842
|
+
type: OpCode.CREATE_TEXT,
|
|
9843
|
+
id: this._id,
|
|
9844
|
+
parentId,
|
|
9845
|
+
parentKey,
|
|
9846
|
+
data: this.toJSON(),
|
|
9847
|
+
version: this.#version
|
|
9848
|
+
}
|
|
9849
|
+
];
|
|
9850
|
+
}
|
|
9851
|
+
/** @internal */
|
|
9852
|
+
_serialize() {
|
|
9853
|
+
if (this.parent.type !== "HasParent") {
|
|
9854
|
+
throw new Error("Cannot serialize LiveText if parent is missing");
|
|
9855
|
+
}
|
|
9856
|
+
return {
|
|
9857
|
+
type: CrdtType.TEXT,
|
|
9858
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
9859
|
+
parentKey: this.parent.key,
|
|
9860
|
+
data: this.toJSON(),
|
|
9861
|
+
version: this.#version
|
|
9862
|
+
};
|
|
9863
|
+
}
|
|
9864
|
+
/** @internal */
|
|
9865
|
+
_attachChild(_op) {
|
|
9866
|
+
throw new Error("LiveText cannot contain child nodes");
|
|
9867
|
+
}
|
|
9868
|
+
/** @internal */
|
|
9869
|
+
_detachChild(_crdt) {
|
|
9870
|
+
throw new Error("LiveText cannot contain child nodes");
|
|
9871
|
+
}
|
|
9872
|
+
/** @internal */
|
|
9873
|
+
_apply(op, source) {
|
|
9874
|
+
if (op.type !== OpCode.UPDATE_TEXT) {
|
|
9875
|
+
return super._apply(op, source);
|
|
9876
|
+
}
|
|
9877
|
+
if (source.origin === "local" && source.optimistic) {
|
|
9878
|
+
return this.#applyLocal(op, toUpdateSource(source));
|
|
9879
|
+
}
|
|
9880
|
+
if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
|
|
9881
|
+
return this.#applyAck(op, toUpdateSource(source));
|
|
9882
|
+
}
|
|
9883
|
+
if (op.opId !== void 0 && this.#acceptedOps.some((entry) => entry.opId === op.opId)) {
|
|
9884
|
+
this.#version = Math.max(this.#version, _nullishCoalesce(op.version, () => ( op.baseVersion + 1)));
|
|
9885
|
+
return { modified: false };
|
|
9886
|
+
}
|
|
9887
|
+
return this.#applyRemote(op, toUpdateSource(source));
|
|
9888
|
+
}
|
|
9889
|
+
/**
|
|
9890
|
+
* Inserts text at the given index.
|
|
9891
|
+
*
|
|
9892
|
+
* @param index Character index at which to insert. Values outside the
|
|
9893
|
+
* document range are clipped.
|
|
9894
|
+
* @param text Text to insert.
|
|
9895
|
+
* @param attributes Optional inline attributes for the inserted text.
|
|
9896
|
+
*
|
|
9897
|
+
* @example
|
|
9898
|
+
* const text = new LiveText("Hello");
|
|
9899
|
+
* text.insert(5, " world");
|
|
9900
|
+
* text.insert(0, "Say: ", { italic: true });
|
|
9901
|
+
*/
|
|
9902
|
+
insert(index, text, attributes) {
|
|
9903
|
+
const clippedIndex = clipIndexToCodePointBoundary(this.toString(), index);
|
|
9904
|
+
this.#dispatch([{ type: "insert", index: clippedIndex, text, attributes }]);
|
|
9905
|
+
}
|
|
9906
|
+
/**
|
|
9907
|
+
* Deletes `length` characters starting at `index`.
|
|
9908
|
+
*
|
|
9909
|
+
* @example
|
|
9910
|
+
* const text = new LiveText("Hello world");
|
|
9911
|
+
* text.delete(5, 6); // "Hello"
|
|
9912
|
+
*/
|
|
9913
|
+
delete(index, length) {
|
|
9914
|
+
const clipped = clipRangeToCodePointBoundaries(
|
|
9915
|
+
this.toString(),
|
|
9916
|
+
index,
|
|
9917
|
+
length
|
|
9918
|
+
);
|
|
9919
|
+
if (clipped.length === 0) {
|
|
9920
|
+
return;
|
|
9921
|
+
}
|
|
9922
|
+
this.#dispatch([
|
|
9923
|
+
{ type: "delete", index: clipped.index, length: clipped.length }
|
|
9924
|
+
]);
|
|
9925
|
+
}
|
|
9926
|
+
/**
|
|
9927
|
+
* Replaces a range of text with new text.
|
|
9928
|
+
*
|
|
9929
|
+
* @example
|
|
9930
|
+
* const text = new LiveText("Hello world");
|
|
9931
|
+
* text.replace(0, 5, "Hi"); // "Hi world"
|
|
9932
|
+
*/
|
|
9933
|
+
replace(index, length, text, attributes) {
|
|
9934
|
+
const clipped = clipRangeToCodePointBoundaries(
|
|
9935
|
+
this.toString(),
|
|
9936
|
+
index,
|
|
9937
|
+
length
|
|
9938
|
+
);
|
|
9939
|
+
const ops = [];
|
|
9940
|
+
if (clipped.length > 0) {
|
|
9941
|
+
ops.push({
|
|
9942
|
+
type: "delete",
|
|
9943
|
+
index: clipped.index,
|
|
9944
|
+
length: clipped.length
|
|
9945
|
+
});
|
|
9946
|
+
}
|
|
9947
|
+
if (text.length > 0) {
|
|
9948
|
+
ops.push({ type: "insert", index: clipped.index, text, attributes });
|
|
9949
|
+
}
|
|
9950
|
+
this.#dispatch(ops);
|
|
9951
|
+
}
|
|
9952
|
+
/**
|
|
9953
|
+
* Encode a local-document index (an offset into this LiveText's current
|
|
9954
|
+
* #segments, which CodeMirror or any consumer mirrors as its document)
|
|
9955
|
+
* into server-confirmed coordinates suitable for broadcasting to peers via
|
|
9956
|
+
* presence or any other side channel.
|
|
9957
|
+
*
|
|
9958
|
+
* The returned index is in this LiveText's current #confirmed coordinates
|
|
9959
|
+
* — that is, with this client's local pending ops inverse-mapped out.
|
|
9960
|
+
* Pair it with the current {@link LiveText.version} when sending so the
|
|
9961
|
+
* receiver can call {@link PrivateLiveTextApi.decodeIndex} to land the
|
|
9962
|
+
* position in their own local document coordinates regardless of their
|
|
9963
|
+
* private pending ops.
|
|
9964
|
+
*
|
|
9965
|
+
* Index ambiguity at boundaries is resolved by an inverse-of-forward
|
|
9966
|
+
* convention: a position at or before a local insertion is reported as
|
|
9967
|
+
* the position right before the insertion in #confirmed; a position past
|
|
9968
|
+
* the insertion shifts left by the insertion's length. Positions inside
|
|
9969
|
+
* an own-pending insertion collapse to the insertion point.
|
|
9970
|
+
*/
|
|
9971
|
+
#encodeIndex(localIndex) {
|
|
9972
|
+
let mapped = Math.max(0, Math.min(localIndex, this.length));
|
|
9973
|
+
mapped = inverseMapTextIndexThroughOperations(mapped, this.#queuedOps);
|
|
9974
|
+
mapped = inverseMapTextIndexThroughOperations(mapped, this.#inFlightOps);
|
|
9975
|
+
return mapped;
|
|
9976
|
+
}
|
|
9977
|
+
/**
|
|
9978
|
+
* Decode an `(index, fromVersion)` pair produced by
|
|
9979
|
+
* {@link PrivateLiveTextApi.encodeIndex} — typically on a peer — into an
|
|
9980
|
+
* offset in this LiveText's current local document (an index suitable for
|
|
9981
|
+
* placing a CodeMirror marker, an annotation anchor, or anything else that
|
|
9982
|
+
* lives over #segments).
|
|
9983
|
+
*
|
|
9984
|
+
* Composes the accepted ops applied since `fromVersion` (drawn from
|
|
9985
|
+
* #acceptedOps in locally-applied form) with this client's own local
|
|
9986
|
+
* pending ops, in that order. The result is in current #segments
|
|
9987
|
+
* coordinates.
|
|
9988
|
+
*
|
|
9989
|
+
* Returns `null` when the position cannot be decoded against the current
|
|
9990
|
+
* state:
|
|
9991
|
+
* - `fromVersion` is greater than this LiveText's current version: the
|
|
9992
|
+
* peer is ahead of us. The caller should park the message and retry
|
|
9993
|
+
* after more accepted ops arrive.
|
|
9994
|
+
* - `fromVersion` falls outside the retained accepted-ops history. This
|
|
9995
|
+
* only happens after very long-lived disconnections; the caller can
|
|
9996
|
+
* fall back to using the raw index and letting subsequent local
|
|
9997
|
+
* transactions map it (with bounded drift).
|
|
9998
|
+
*/
|
|
9999
|
+
#decodeIndex(index, fromVersion) {
|
|
10000
|
+
if (fromVersion > this.#version) {
|
|
10001
|
+
return null;
|
|
10002
|
+
}
|
|
10003
|
+
if (fromVersion < this.#version) {
|
|
10004
|
+
const oldest = _optionalChain([this, 'access', _238 => _238.#acceptedOps, 'access', _239 => _239[0], 'optionalAccess', _240 => _240.version]);
|
|
10005
|
+
if (oldest === void 0 || oldest > fromVersion + 1) {
|
|
10006
|
+
return null;
|
|
10007
|
+
}
|
|
10008
|
+
}
|
|
10009
|
+
let mapped = index;
|
|
10010
|
+
for (const entry of this.#acceptedOps) {
|
|
10011
|
+
if (entry.version <= fromVersion) continue;
|
|
10012
|
+
if (entry.version > this.#version) break;
|
|
10013
|
+
if (entry.ops.length === 0) continue;
|
|
10014
|
+
mapped = mapTextIndexThroughOperations(mapped, entry.ops);
|
|
10015
|
+
}
|
|
10016
|
+
mapped = mapTextIndexThroughOperations(mapped, this.#inFlightOps);
|
|
10017
|
+
mapped = mapTextIndexThroughOperations(mapped, this.#queuedOps);
|
|
10018
|
+
return Math.max(0, Math.min(mapped, this.length));
|
|
10019
|
+
}
|
|
10020
|
+
/**
|
|
10021
|
+
* Applies or removes inline attributes on a range of text.
|
|
10022
|
+
*
|
|
10023
|
+
* Set an attribute to `null` to remove it from the range.
|
|
10024
|
+
*
|
|
10025
|
+
* @example
|
|
10026
|
+
* const text = new LiveText("Hello world");
|
|
10027
|
+
* text.format(0, 5, { bold: true });
|
|
10028
|
+
* text.format(0, 5, { bold: null });
|
|
10029
|
+
*/
|
|
10030
|
+
format(index, length, attributes) {
|
|
10031
|
+
const clipped = clipRangeToCodePointBoundaries(
|
|
10032
|
+
this.toString(),
|
|
10033
|
+
index,
|
|
10034
|
+
length
|
|
10035
|
+
);
|
|
10036
|
+
if (clipped.length === 0) {
|
|
10037
|
+
return;
|
|
10038
|
+
}
|
|
10039
|
+
this.#dispatch([
|
|
10040
|
+
{
|
|
10041
|
+
type: "format",
|
|
10042
|
+
index: clipped.index,
|
|
10043
|
+
length: clipped.length,
|
|
10044
|
+
attributes
|
|
10045
|
+
}
|
|
10046
|
+
]);
|
|
10047
|
+
}
|
|
10048
|
+
/** Local edits made through the public API. */
|
|
10049
|
+
#dispatch(ops) {
|
|
10050
|
+
if (ops.length === 0) {
|
|
10051
|
+
return;
|
|
10052
|
+
}
|
|
10053
|
+
_optionalChain([this, 'access', _241 => _241._pool, 'optionalAccess', _242 => _242.assertStorageIsWritable, 'call', _243 => _243()]);
|
|
10054
|
+
const attached = this._pool !== void 0 && this._id !== void 0;
|
|
10055
|
+
const reverse = attached ? this.#invertOperations(ops) : [];
|
|
10056
|
+
const changes = this.#applyOperationsLocally(ops);
|
|
10057
|
+
if (!attached) {
|
|
10058
|
+
return;
|
|
10059
|
+
}
|
|
10060
|
+
const pool = nn(this._pool);
|
|
10061
|
+
const id = nn(this._id);
|
|
10062
|
+
const updates = /* @__PURE__ */ new Map([
|
|
10063
|
+
[
|
|
10064
|
+
id,
|
|
10065
|
+
{
|
|
10066
|
+
type: "LiveText",
|
|
10067
|
+
node: this,
|
|
10068
|
+
version: this.#version,
|
|
10069
|
+
updates: changes,
|
|
10070
|
+
source: LOCAL_EDIT
|
|
10071
|
+
}
|
|
10072
|
+
]
|
|
10073
|
+
]);
|
|
10074
|
+
if (this.#inFlightOpId === void 0) {
|
|
10075
|
+
const opId = pool.generateOpId();
|
|
10076
|
+
this.#inFlightOpId = opId;
|
|
10077
|
+
this.#inFlightOps = [...ops];
|
|
10078
|
+
pool.dispatch(
|
|
10079
|
+
[
|
|
10080
|
+
{
|
|
10081
|
+
type: OpCode.UPDATE_TEXT,
|
|
10082
|
+
id,
|
|
10083
|
+
opId,
|
|
10084
|
+
baseVersion: this.#version,
|
|
10085
|
+
ops: [...ops]
|
|
10086
|
+
}
|
|
10087
|
+
],
|
|
10088
|
+
reverse,
|
|
10089
|
+
updates
|
|
10090
|
+
);
|
|
10091
|
+
} else {
|
|
10092
|
+
this.#queuedOps.push(...ops);
|
|
10093
|
+
pool.dispatch([], reverse, updates, { clearRedoStack: true });
|
|
10094
|
+
}
|
|
10095
|
+
}
|
|
10096
|
+
/**
|
|
10097
|
+
* A local replay of an existing wire op: an undo/redo frame, or an
|
|
10098
|
+
* unacknowledged op re-sent after a reconnect.
|
|
10099
|
+
*/
|
|
10100
|
+
#applyLocal(op, source) {
|
|
10101
|
+
const mutableOp = op;
|
|
10102
|
+
if (op.opId !== void 0 && op.opId === this.#inFlightOpId) {
|
|
10103
|
+
this.#inFlightOps = [...this.#inFlightOps, ...this.#queuedOps];
|
|
10104
|
+
this.#queuedOps = [];
|
|
10105
|
+
mutableOp.baseVersion = this.#version;
|
|
10106
|
+
mutableOp.ops = [...this.#inFlightOps];
|
|
10107
|
+
return { modified: false };
|
|
10108
|
+
}
|
|
10109
|
+
let ops = op.ops;
|
|
10110
|
+
for (const entry of this.#acceptedOps) {
|
|
10111
|
+
if (entry.version > op.baseVersion && entry.ops.length > 0) {
|
|
10112
|
+
ops = transformTextOperations(ops, entry.ops, "after");
|
|
10113
|
+
}
|
|
10114
|
+
}
|
|
10115
|
+
const reverse = this.#invertOperations(ops);
|
|
10116
|
+
const changes = this.#applyOperationsLocally(ops);
|
|
10117
|
+
if (this.#inFlightOpId === void 0 && ops.length > 0) {
|
|
10118
|
+
this.#inFlightOpId = nn(op.opId, "Local ops must have an opId");
|
|
10119
|
+
this.#inFlightOps = [...ops];
|
|
10120
|
+
mutableOp.baseVersion = this.#version;
|
|
10121
|
+
mutableOp.ops = [...ops];
|
|
10122
|
+
} else {
|
|
10123
|
+
this.#queuedOps.push(...ops);
|
|
10124
|
+
mutableOp.baseVersion = this.#version;
|
|
10125
|
+
mutableOp.ops = [];
|
|
10126
|
+
}
|
|
10127
|
+
if (changes.length === 0) {
|
|
10128
|
+
return { modified: false };
|
|
10129
|
+
}
|
|
10130
|
+
return {
|
|
10131
|
+
reverse,
|
|
10132
|
+
modified: {
|
|
10133
|
+
type: "LiveText",
|
|
10134
|
+
node: this,
|
|
10135
|
+
version: this.#version,
|
|
10136
|
+
updates: changes,
|
|
10137
|
+
source
|
|
10138
|
+
}
|
|
10139
|
+
};
|
|
10140
|
+
}
|
|
10141
|
+
/** Server acknowledgement of our in-flight op. */
|
|
10142
|
+
#applyAck(op, source) {
|
|
10143
|
+
const ackedVersion = _nullishCoalesce(op.version, () => ( Math.max(this.#version, op.baseVersion + 1)));
|
|
10144
|
+
const predicted = this.#inFlightOps;
|
|
10145
|
+
const opId = this.#inFlightOpId;
|
|
10146
|
+
this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
|
|
10147
|
+
this.#inFlightOpId = void 0;
|
|
10148
|
+
this.#inFlightOps = [];
|
|
10149
|
+
let appliedOps = [];
|
|
10150
|
+
let result = { modified: false };
|
|
10151
|
+
if (!textOperationsEqual(op.ops, predicted)) {
|
|
10152
|
+
error2(
|
|
10153
|
+
"LiveText: acknowledgement did not match the local prediction; resynchronizing"
|
|
10154
|
+
);
|
|
10155
|
+
const rebuilt = this.#rebuildLocalFromConfirmed();
|
|
10156
|
+
appliedOps = rebuilt.appliedOps;
|
|
10157
|
+
if (rebuilt.changes.length > 0) {
|
|
10158
|
+
result = {
|
|
10159
|
+
reverse: [],
|
|
10160
|
+
modified: {
|
|
10161
|
+
type: "LiveText",
|
|
10162
|
+
node: this,
|
|
10163
|
+
version: ackedVersion,
|
|
10164
|
+
updates: rebuilt.changes,
|
|
10165
|
+
source
|
|
10166
|
+
}
|
|
10167
|
+
};
|
|
10168
|
+
}
|
|
10169
|
+
}
|
|
10170
|
+
this.#version = Math.max(this.#version, ackedVersion);
|
|
10171
|
+
this.#recordAccepted(ackedVersion, appliedOps, opId);
|
|
10172
|
+
this.#flushQueued();
|
|
10173
|
+
return result;
|
|
10174
|
+
}
|
|
10175
|
+
/** An accepted op from another client (or a server-fabricated fix op). */
|
|
10176
|
+
#applyRemote(op, source) {
|
|
10177
|
+
const version = _nullishCoalesce(op.version, () => ( this.#version + 1));
|
|
10178
|
+
this.#confirmed = applyTextOperationsToSegments(this.#confirmed, op.ops);
|
|
10179
|
+
const [overInFlight, inFlight] = transformTextOperationsX(
|
|
10180
|
+
op.ops,
|
|
10181
|
+
this.#inFlightOps,
|
|
10182
|
+
"before"
|
|
10183
|
+
);
|
|
10184
|
+
const [applied, queued] = transformTextOperationsX(
|
|
10185
|
+
overInFlight,
|
|
10186
|
+
this.#queuedOps,
|
|
10187
|
+
"before"
|
|
10188
|
+
);
|
|
10189
|
+
this.#inFlightOps = inFlight;
|
|
10190
|
+
this.#queuedOps = queued;
|
|
10191
|
+
this.#recordAccepted(version, applied, op.opId);
|
|
10192
|
+
if (applied.length === 0) {
|
|
10193
|
+
this.#version = Math.max(this.#version, version);
|
|
10194
|
+
return { modified: false };
|
|
10195
|
+
}
|
|
10196
|
+
const reverse = this.#invertOperations(applied);
|
|
10197
|
+
const changes = this.#applyOperationsLocally(applied);
|
|
10198
|
+
this.#version = Math.max(this.#version, version);
|
|
10199
|
+
return {
|
|
10200
|
+
reverse,
|
|
10201
|
+
modified: {
|
|
10202
|
+
type: "LiveText",
|
|
10203
|
+
node: this,
|
|
10204
|
+
version: this.#version,
|
|
10205
|
+
updates: changes,
|
|
10206
|
+
source
|
|
10207
|
+
}
|
|
10208
|
+
};
|
|
10209
|
+
}
|
|
10210
|
+
/** Send the queued ops as the next in-flight op (after an ack). */
|
|
10211
|
+
#flushQueued() {
|
|
10212
|
+
if (this.#queuedOps.length === 0 || this._pool === void 0 || this._id === void 0) {
|
|
10213
|
+
return;
|
|
10214
|
+
}
|
|
10215
|
+
const opId = this._pool.generateOpId();
|
|
10216
|
+
this.#inFlightOpId = opId;
|
|
10217
|
+
this.#inFlightOps = this.#queuedOps;
|
|
10218
|
+
this.#queuedOps = [];
|
|
10219
|
+
this._pool.dispatch(
|
|
10220
|
+
[
|
|
10221
|
+
{
|
|
10222
|
+
type: OpCode.UPDATE_TEXT,
|
|
10223
|
+
id: this._id,
|
|
10224
|
+
opId,
|
|
10225
|
+
baseVersion: this.#version,
|
|
10226
|
+
ops: [...this.#inFlightOps]
|
|
10227
|
+
}
|
|
10228
|
+
],
|
|
10229
|
+
[],
|
|
10230
|
+
/* @__PURE__ */ new Map(),
|
|
10231
|
+
// The local content was already applied (and made undoable) when the
|
|
10232
|
+
// edits happened; this is purely an outbound flush.
|
|
10233
|
+
{ clearRedoStack: false }
|
|
10234
|
+
);
|
|
10235
|
+
}
|
|
10236
|
+
/**
|
|
10237
|
+
* Rebuild the local document as confirmed ⊕ queued ops, returning the
|
|
10238
|
+
* coarse delta that was applied. Only used by defensive recovery paths.
|
|
10239
|
+
*/
|
|
10240
|
+
#rebuildLocalFromConfirmed() {
|
|
10241
|
+
const before2 = this.#segments;
|
|
10242
|
+
const after2 = applyTextOperationsToSegments(this.#confirmed, [
|
|
10243
|
+
...this.#inFlightOps,
|
|
10244
|
+
...this.#queuedOps
|
|
10245
|
+
]);
|
|
10246
|
+
if (stableStringify(segmentsToData(before2)) === stableStringify(segmentsToData(after2))) {
|
|
10247
|
+
this.#segments = after2;
|
|
10248
|
+
return { appliedOps: [], changes: [] };
|
|
10249
|
+
}
|
|
10250
|
+
const beforeText = before2.map((segment) => segment.text).join("");
|
|
10251
|
+
this.#segments = after2;
|
|
10252
|
+
this.invalidate();
|
|
10253
|
+
const appliedOps = [];
|
|
10254
|
+
const changes = [];
|
|
10255
|
+
if (beforeText.length > 0) {
|
|
10256
|
+
appliedOps.push({ type: "delete", index: 0, length: beforeText.length });
|
|
10257
|
+
changes.push({
|
|
10258
|
+
type: "delete",
|
|
10259
|
+
index: 0,
|
|
10260
|
+
length: beforeText.length,
|
|
10261
|
+
deletedText: beforeText
|
|
10262
|
+
});
|
|
10263
|
+
}
|
|
10264
|
+
let index = 0;
|
|
10265
|
+
for (const segment of after2) {
|
|
10266
|
+
appliedOps.push({
|
|
10267
|
+
type: "insert",
|
|
10268
|
+
index,
|
|
10269
|
+
text: segment.text,
|
|
10270
|
+
attributes: segment.attributes
|
|
10271
|
+
});
|
|
10272
|
+
changes.push({
|
|
10273
|
+
type: "insert",
|
|
10274
|
+
index,
|
|
10275
|
+
text: segment.text,
|
|
10276
|
+
attributes: segment.attributes
|
|
10277
|
+
});
|
|
10278
|
+
index += segment.text.length;
|
|
10279
|
+
}
|
|
10280
|
+
return { appliedOps, changes };
|
|
10281
|
+
}
|
|
10282
|
+
/**
|
|
10283
|
+
* Reconcile this node against an authoritative storage snapshot (e.g.
|
|
10284
|
+
* after a reconnect). The confirmed state and version are replaced by the
|
|
10285
|
+
* snapshot's; pending (in-flight + queued) ops are preserved on top and
|
|
10286
|
+
* will be re-sent by the offline-ops replay.
|
|
10287
|
+
*
|
|
10288
|
+
* @internal
|
|
10289
|
+
*/
|
|
10290
|
+
_resyncText(data, version, source) {
|
|
10291
|
+
this.#confirmed = dataToSegments(data);
|
|
10292
|
+
this.#version = version;
|
|
10293
|
+
this.#acceptedOps = [];
|
|
10294
|
+
const rebuilt = this.#rebuildLocalFromConfirmed();
|
|
10295
|
+
if (rebuilt.changes.length === 0) {
|
|
10296
|
+
return void 0;
|
|
10297
|
+
}
|
|
10298
|
+
return {
|
|
10299
|
+
type: "LiveText",
|
|
10300
|
+
node: this,
|
|
10301
|
+
version: this.#version,
|
|
10302
|
+
updates: rebuilt.changes,
|
|
10303
|
+
source
|
|
10304
|
+
};
|
|
10305
|
+
}
|
|
10306
|
+
/**
|
|
10307
|
+
* Called when the server rejected one of our ops. Drops all pending state
|
|
10308
|
+
* for this node (edits queued behind a rejected op cannot be trusted
|
|
10309
|
+
* either); the room follows up with a storage resync.
|
|
10310
|
+
*
|
|
10311
|
+
* @internal
|
|
10312
|
+
*/
|
|
10313
|
+
_rejectPendingOp(opId) {
|
|
10314
|
+
if (opId !== this.#inFlightOpId) {
|
|
10315
|
+
return;
|
|
10316
|
+
}
|
|
10317
|
+
this.#inFlightOpId = void 0;
|
|
10318
|
+
this.#inFlightOps = [];
|
|
10319
|
+
this.#queuedOps = [];
|
|
10320
|
+
}
|
|
10321
|
+
#recordAccepted(version, ops, opId) {
|
|
10322
|
+
if (this.#acceptedOps.some((entry) => entry.version === version)) {
|
|
10323
|
+
return;
|
|
10324
|
+
}
|
|
10325
|
+
this.#acceptedOps.push({ version, opId, ops: [...ops] });
|
|
10326
|
+
this.#acceptedOps.sort((left, right) => left.version - right.version);
|
|
10327
|
+
if (this.#acceptedOps.length > ACCEPTED_OPS_HISTORY_LIMIT) {
|
|
10328
|
+
this.#acceptedOps.splice(
|
|
10329
|
+
0,
|
|
10330
|
+
this.#acceptedOps.length - ACCEPTED_OPS_HISTORY_LIMIT
|
|
10331
|
+
);
|
|
10332
|
+
}
|
|
10333
|
+
}
|
|
10334
|
+
#applyOperationsLocally(ops) {
|
|
10335
|
+
const changes = [];
|
|
10336
|
+
for (const op of ops) {
|
|
10337
|
+
if (op.type === "insert") {
|
|
10338
|
+
this.#segments = applyInsert(
|
|
10339
|
+
this.#segments,
|
|
10340
|
+
op.index,
|
|
10341
|
+
op.text,
|
|
10342
|
+
op.attributes
|
|
10343
|
+
);
|
|
10344
|
+
changes.push({
|
|
10345
|
+
type: "insert",
|
|
10346
|
+
index: op.index,
|
|
10347
|
+
text: op.text,
|
|
10348
|
+
attributes: op.attributes
|
|
10349
|
+
});
|
|
10350
|
+
} else if (op.type === "delete") {
|
|
10351
|
+
const result = applyDelete(this.#segments, op.index, op.length);
|
|
10352
|
+
this.#segments = result.segments;
|
|
10353
|
+
changes.push({
|
|
10354
|
+
type: "delete",
|
|
10355
|
+
index: op.index,
|
|
10356
|
+
length: op.length,
|
|
10357
|
+
deletedText: result.deletedText
|
|
10358
|
+
});
|
|
10359
|
+
} else {
|
|
10360
|
+
this.#segments = applyFormat(
|
|
10361
|
+
this.#segments,
|
|
10362
|
+
op.index,
|
|
10363
|
+
op.length,
|
|
10364
|
+
op.attributes
|
|
10365
|
+
);
|
|
10366
|
+
changes.push({
|
|
10367
|
+
type: "format",
|
|
10368
|
+
index: op.index,
|
|
10369
|
+
length: op.length,
|
|
10370
|
+
attributes: op.attributes
|
|
10371
|
+
});
|
|
10372
|
+
}
|
|
10373
|
+
}
|
|
10374
|
+
this.invalidate();
|
|
10375
|
+
return changes;
|
|
10376
|
+
}
|
|
10377
|
+
#invertOperations(ops) {
|
|
10378
|
+
return [
|
|
10379
|
+
{
|
|
10380
|
+
type: OpCode.UPDATE_TEXT,
|
|
10381
|
+
id: nn(this._id),
|
|
10382
|
+
baseVersion: this.#version,
|
|
10383
|
+
ops: invertTextOperations(this.#segments, ops)
|
|
10384
|
+
}
|
|
10385
|
+
];
|
|
10386
|
+
}
|
|
10387
|
+
/** Returns the plain text content without attributes. Equivalent to joining the text from each segment in {@link LiveText.toJSON}. */
|
|
10388
|
+
toString() {
|
|
10389
|
+
return this.#segments.map((segment) => segment.text).join("");
|
|
10390
|
+
}
|
|
10391
|
+
/**
|
|
10392
|
+
* Returns a JSON-compatible snapshot of the document as a {@link LiveTextData}
|
|
10393
|
+
* array.
|
|
10394
|
+
*
|
|
10395
|
+
* @example
|
|
10396
|
+
* new LiveText([["Hello ", { bold: true }], ["world"]]).toJSON();
|
|
10397
|
+
* // [["Hello ", { bold: true }], ["world"]]
|
|
10398
|
+
*/
|
|
10399
|
+
toJSON() {
|
|
10400
|
+
return super.toJSON();
|
|
10401
|
+
}
|
|
10402
|
+
/** @internal */
|
|
10403
|
+
_toJSON() {
|
|
10404
|
+
return segmentsToData(this.#segments);
|
|
10405
|
+
}
|
|
10406
|
+
/** @internal */
|
|
10407
|
+
toTreeNode(key) {
|
|
10408
|
+
return super.toTreeNode(key);
|
|
10409
|
+
}
|
|
10410
|
+
/** @internal */
|
|
10411
|
+
_toTreeNode(key) {
|
|
10412
|
+
const nodeId = _nullishCoalesce(this._id, () => ( nanoid()));
|
|
10413
|
+
const payload = this.toJSON().map(
|
|
10414
|
+
(segment, index) => ({
|
|
10415
|
+
type: "Json",
|
|
10416
|
+
id: `${nodeId}:${index}`,
|
|
10417
|
+
key: String(index),
|
|
10418
|
+
payload: segment
|
|
10419
|
+
})
|
|
10420
|
+
);
|
|
10421
|
+
payload.push({
|
|
10422
|
+
type: "Json",
|
|
10423
|
+
id: `${nodeId}:version`,
|
|
10424
|
+
key: "version",
|
|
10425
|
+
payload: this.version
|
|
10426
|
+
});
|
|
10427
|
+
return {
|
|
10428
|
+
type: "LiveText",
|
|
10429
|
+
id: nodeId,
|
|
10430
|
+
key,
|
|
10431
|
+
payload
|
|
10432
|
+
};
|
|
10433
|
+
}
|
|
10434
|
+
clone() {
|
|
10435
|
+
return new _LiveText(this.toJSON(), this.#version);
|
|
10436
|
+
}
|
|
10437
|
+
};
|
|
10438
|
+
|
|
10439
|
+
// src/crdts/liveblocks-helpers.ts
|
|
10440
|
+
function creationOpToLiveNode(op) {
|
|
10441
|
+
return lsonToLiveNode(creationOpToLson(op));
|
|
10442
|
+
}
|
|
10443
|
+
function creationOpToLson(op) {
|
|
10444
|
+
switch (op.type) {
|
|
10445
|
+
case OpCode.CREATE_FILE:
|
|
10446
|
+
return new LiveFile(op.data);
|
|
10447
|
+
case OpCode.CREATE_REGISTER:
|
|
10448
|
+
return op.data;
|
|
10449
|
+
case OpCode.CREATE_OBJECT:
|
|
10450
|
+
return new LiveObject(op.data);
|
|
10451
|
+
case OpCode.CREATE_MAP:
|
|
10452
|
+
return new LiveMap();
|
|
10453
|
+
case OpCode.CREATE_LIST:
|
|
10454
|
+
return new LiveList([]);
|
|
10455
|
+
case OpCode.CREATE_TEXT:
|
|
10456
|
+
return new LiveText(op.data, op.version);
|
|
10457
|
+
default:
|
|
10458
|
+
return assertNever(op, "Unknown creation Op");
|
|
10459
|
+
}
|
|
10460
|
+
}
|
|
10461
|
+
function isSameNodeOrChildOf(node, parent) {
|
|
10462
|
+
if (node === parent) {
|
|
10463
|
+
return true;
|
|
10464
|
+
}
|
|
10465
|
+
if (node.parent.type === "HasParent") {
|
|
10466
|
+
return isSameNodeOrChildOf(node.parent.node, parent);
|
|
10467
|
+
}
|
|
10468
|
+
return false;
|
|
10469
|
+
}
|
|
10470
|
+
function liveObjectFromNodeStream(nodes) {
|
|
10471
|
+
const pool = createManagedPool({
|
|
10472
|
+
getCurrentConnectionId: () => {
|
|
10473
|
+
throw new Error(
|
|
10474
|
+
"Cannot mutate a historic storage version: it is a read-only snapshot"
|
|
10475
|
+
);
|
|
10476
|
+
}
|
|
10477
|
+
});
|
|
10478
|
+
return LiveObject._fromItems(nodes, pool);
|
|
10479
|
+
}
|
|
10480
|
+
function deserialize(node, parentToChildren, pool) {
|
|
10481
|
+
if (isObjectStorageNode(node)) {
|
|
10482
|
+
return LiveObject._deserialize(node, parentToChildren, pool);
|
|
10483
|
+
} else if (isListStorageNode(node)) {
|
|
10484
|
+
return LiveList._deserialize(node, parentToChildren, pool);
|
|
10485
|
+
} else if (isMapStorageNode(node)) {
|
|
10486
|
+
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
10487
|
+
} else if (isRegisterStorageNode(node)) {
|
|
10488
|
+
return LiveRegister._deserialize(node, parentToChildren, pool);
|
|
10489
|
+
} else if (isTextStorageNode(node)) {
|
|
10490
|
+
return LiveText._deserialize(node, parentToChildren, pool);
|
|
10491
|
+
} else if (isFileStorageNode(node)) {
|
|
10492
|
+
return LiveFile._deserialize(node, parentToChildren, pool);
|
|
10493
|
+
} else {
|
|
10494
|
+
throw new Error("Unexpected CRDT type");
|
|
10495
|
+
}
|
|
10496
|
+
}
|
|
10497
|
+
function deserializeToLson(node, parentToChildren, pool) {
|
|
10498
|
+
if (isObjectStorageNode(node)) {
|
|
10499
|
+
return LiveObject._deserialize(node, parentToChildren, pool);
|
|
10500
|
+
} else if (isListStorageNode(node)) {
|
|
10501
|
+
return LiveList._deserialize(node, parentToChildren, pool);
|
|
10502
|
+
} else if (isMapStorageNode(node)) {
|
|
10503
|
+
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
10504
|
+
} else if (isRegisterStorageNode(node)) {
|
|
10505
|
+
return node[1].data;
|
|
10506
|
+
} else if (isTextStorageNode(node)) {
|
|
10507
|
+
return LiveText._deserialize(node, parentToChildren, pool);
|
|
10508
|
+
} else if (isFileStorageNode(node)) {
|
|
10509
|
+
return LiveFile._deserialize(node, parentToChildren, pool);
|
|
10510
|
+
} else {
|
|
10511
|
+
throw new Error("Unexpected CRDT type");
|
|
10512
|
+
}
|
|
10513
|
+
}
|
|
10514
|
+
function isLiveStructure(value) {
|
|
10515
|
+
return isLiveList(value) || isLiveMap(value) || isLiveObject(value) || isLiveText(value) || isLiveFile(value);
|
|
10516
|
+
}
|
|
10517
|
+
function isLiveNode(value) {
|
|
10518
|
+
return isLiveStructure(value) || isLiveRegister(value);
|
|
10519
|
+
}
|
|
10520
|
+
function isLiveList(value) {
|
|
10521
|
+
return value instanceof LiveList;
|
|
10522
|
+
}
|
|
10523
|
+
function isLiveMap(value) {
|
|
10524
|
+
return value instanceof LiveMap;
|
|
10525
|
+
}
|
|
10526
|
+
function isLiveObject(value) {
|
|
10527
|
+
return value instanceof LiveObject;
|
|
10528
|
+
}
|
|
10529
|
+
function isLiveText(value) {
|
|
10530
|
+
return value instanceof LiveText;
|
|
10531
|
+
}
|
|
10532
|
+
function isLiveFile(value) {
|
|
10533
|
+
return value instanceof LiveFile;
|
|
10534
|
+
}
|
|
10535
|
+
function isLiveRegister(value) {
|
|
10536
|
+
return value instanceof LiveRegister;
|
|
10537
|
+
}
|
|
10538
|
+
function cloneLson(value) {
|
|
10539
|
+
return value === void 0 ? void 0 : isLiveStructure(value) ? value.clone() : deepClone(value);
|
|
10540
|
+
}
|
|
10541
|
+
function liveNodeToLson(obj) {
|
|
10542
|
+
if (obj instanceof LiveRegister) {
|
|
10543
|
+
return obj.data;
|
|
10544
|
+
} else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject || obj instanceof LiveText || obj instanceof LiveFile) {
|
|
10545
|
+
return obj;
|
|
10546
|
+
} else {
|
|
10547
|
+
return assertNever(obj, "Unknown AbstractCrdt");
|
|
10548
|
+
}
|
|
10549
|
+
}
|
|
10550
|
+
function lsonToLiveNode(value) {
|
|
10551
|
+
if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList || value instanceof LiveText || value instanceof LiveFile) {
|
|
10552
|
+
return value;
|
|
10553
|
+
} else {
|
|
10554
|
+
return new LiveRegister(value);
|
|
10555
|
+
}
|
|
10556
|
+
}
|
|
10557
|
+
function dumpPool(pool) {
|
|
10558
|
+
const rows = Array.from(pool.nodes.values(), (node) => {
|
|
10559
|
+
const parent = node.parent;
|
|
10560
|
+
const parentId = parent.type === "HasParent" ? _nullishCoalesce(parent.node._id, () => ( "?")) : parent.type === "Orphaned" ? "<orphaned>" : "-";
|
|
10561
|
+
let value;
|
|
10562
|
+
if (node instanceof LiveRegister) {
|
|
10563
|
+
value = stringifyOrLog(node.data);
|
|
10564
|
+
} else if (node instanceof LiveList) {
|
|
10565
|
+
value = "<LiveList>";
|
|
10566
|
+
} else if (node instanceof LiveMap) {
|
|
10567
|
+
value = "<LiveMap>";
|
|
10568
|
+
} else if (node instanceof LiveFile) {
|
|
10569
|
+
value = stringifyOrLog(node.data);
|
|
10570
|
+
} else {
|
|
10571
|
+
value = "<LiveObject>";
|
|
10572
|
+
}
|
|
10573
|
+
return { id: nn(node._id), parentId, key: _nullishCoalesce(node._parentKey, () => ( "")), value };
|
|
10574
|
+
});
|
|
10575
|
+
rows.sort((a, b) => {
|
|
10576
|
+
if (a.parentId !== b.parentId) return a.parentId < b.parentId ? -1 : 1;
|
|
10577
|
+
if (a.key !== b.key) return a.key < b.key ? -1 : 1;
|
|
10578
|
+
return 0;
|
|
10579
|
+
});
|
|
10580
|
+
return rows.map(
|
|
10581
|
+
(r) => ` ${r.id} parent=${r.parentId} key=${r.key || "\u2014"} ${r.value}`
|
|
10582
|
+
).join("\n");
|
|
10583
|
+
}
|
|
10584
|
+
function isJsonEq(a, b) {
|
|
10585
|
+
if (a === b) {
|
|
10586
|
+
return true;
|
|
10587
|
+
}
|
|
10588
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
|
10589
|
+
return false;
|
|
10590
|
+
}
|
|
10591
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
10592
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
|
|
10593
|
+
return false;
|
|
10594
|
+
}
|
|
10595
|
+
for (let i = 0; i < a.length; i++) {
|
|
10596
|
+
if (!isJsonEq(a[i], b[i])) {
|
|
10597
|
+
return false;
|
|
10598
|
+
}
|
|
10599
|
+
}
|
|
10600
|
+
return true;
|
|
10601
|
+
}
|
|
10602
|
+
const aKeys = Object.keys(a);
|
|
10603
|
+
if (aKeys.length !== Object.keys(b).length) {
|
|
10604
|
+
return false;
|
|
10605
|
+
}
|
|
10606
|
+
for (const key of aKeys) {
|
|
10607
|
+
if (!isJsonEq(a[key], b[key])) {
|
|
10608
|
+
return false;
|
|
10609
|
+
}
|
|
10610
|
+
}
|
|
10611
|
+
return true;
|
|
10612
|
+
}
|
|
10613
|
+
function liveTextDataToReplaceOps(before2, after2) {
|
|
10614
|
+
const ops = [];
|
|
10615
|
+
const beforeLength = before2.reduce(
|
|
10616
|
+
(length, [text]) => length + text.length,
|
|
10617
|
+
0
|
|
10618
|
+
);
|
|
10619
|
+
if (beforeLength > 0) {
|
|
10620
|
+
ops.push({ type: "delete", index: 0, length: beforeLength });
|
|
10621
|
+
}
|
|
10622
|
+
let index = 0;
|
|
10623
|
+
for (const [text, attributes] of after2) {
|
|
10624
|
+
if (text.length === 0) {
|
|
10625
|
+
continue;
|
|
10626
|
+
}
|
|
10627
|
+
ops.push({ type: "insert", index, text, attributes });
|
|
10628
|
+
index += text.length;
|
|
10629
|
+
}
|
|
10630
|
+
return ops;
|
|
10631
|
+
}
|
|
10632
|
+
function diffNodeMap(prev, next, options) {
|
|
10633
|
+
const ops = [];
|
|
10634
|
+
const idsToRecreate = /* @__PURE__ */ new Set();
|
|
10635
|
+
next.forEach((nextCrdt, id) => {
|
|
10636
|
+
const currentCrdt = prev.get(id);
|
|
10637
|
+
if (currentCrdt === void 0) {
|
|
10638
|
+
return;
|
|
10639
|
+
}
|
|
10640
|
+
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)) {
|
|
10641
|
+
idsToRecreate.add(id);
|
|
9357
10642
|
}
|
|
9358
10643
|
});
|
|
9359
10644
|
let foundDescendant = true;
|
|
@@ -9436,6 +10721,16 @@ function diffNodeMap(prev, next) {
|
|
|
9436
10721
|
parentKey: crdt.parentKey
|
|
9437
10722
|
});
|
|
9438
10723
|
break;
|
|
10724
|
+
case CrdtType.TEXT:
|
|
10725
|
+
ops.push({
|
|
10726
|
+
type: OpCode.CREATE_TEXT,
|
|
10727
|
+
id,
|
|
10728
|
+
parentId: crdt.parentId,
|
|
10729
|
+
parentKey: crdt.parentKey,
|
|
10730
|
+
data: crdt.data,
|
|
10731
|
+
version: crdt.version
|
|
10732
|
+
});
|
|
10733
|
+
break;
|
|
9439
10734
|
}
|
|
9440
10735
|
}
|
|
9441
10736
|
next.forEach((crdt, id) => {
|
|
@@ -9462,6 +10757,17 @@ function diffNodeMap(prev, next) {
|
|
|
9462
10757
|
}
|
|
9463
10758
|
}
|
|
9464
10759
|
}
|
|
10760
|
+
if (_optionalChain([options, 'optionalAccess', _244 => _244.includeLiveTextUpdates]) === true && crdt.type === CrdtType.TEXT && currentCrdt.type === CrdtType.TEXT && !isJsonEq(crdt.data, currentCrdt.data)) {
|
|
10761
|
+
ops.push({
|
|
10762
|
+
type: OpCode.UPDATE_TEXT,
|
|
10763
|
+
id,
|
|
10764
|
+
// A restore is a new edit in the current timeline. The version from
|
|
10765
|
+
// the historic snapshot describes its old timeline and must not move
|
|
10766
|
+
// this node's current version backwards.
|
|
10767
|
+
baseVersion: currentCrdt.version,
|
|
10768
|
+
ops: liveTextDataToReplaceOps(currentCrdt.data, crdt.data)
|
|
10769
|
+
});
|
|
10770
|
+
}
|
|
9465
10771
|
if (crdt.parentKey !== currentCrdt.parentKey) {
|
|
9466
10772
|
ops.push({
|
|
9467
10773
|
type: OpCode.SET_PARENT_KEY,
|
|
@@ -9502,19 +10808,36 @@ function mergeListStorageUpdates(first, second) {
|
|
|
9502
10808
|
updates: updates.concat(second.updates)
|
|
9503
10809
|
};
|
|
9504
10810
|
}
|
|
10811
|
+
function mergeTextStorageUpdates(first, second) {
|
|
10812
|
+
return {
|
|
10813
|
+
...second,
|
|
10814
|
+
updates: first.updates.concat(second.updates)
|
|
10815
|
+
};
|
|
10816
|
+
}
|
|
10817
|
+
function mergeUpdateSources(first, second) {
|
|
10818
|
+
if (first.origin === "remote" || second.origin === "remote") {
|
|
10819
|
+
return REMOTE;
|
|
10820
|
+
}
|
|
10821
|
+
if (second.via !== "edit") return second;
|
|
10822
|
+
if (first.via !== "edit") return first;
|
|
10823
|
+
return LOCAL_EDIT;
|
|
10824
|
+
}
|
|
9505
10825
|
function mergeStorageUpdates(first, second) {
|
|
9506
10826
|
if (first === void 0) {
|
|
9507
10827
|
return second;
|
|
9508
10828
|
}
|
|
10829
|
+
const source = mergeUpdateSources(first.source, second.source);
|
|
9509
10830
|
if (first.type === "LiveObject" && second.type === "LiveObject") {
|
|
9510
|
-
return mergeObjectStorageUpdates(first, second);
|
|
10831
|
+
return { ...mergeObjectStorageUpdates(first, second), source };
|
|
9511
10832
|
} else if (first.type === "LiveMap" && second.type === "LiveMap") {
|
|
9512
|
-
return mergeMapStorageUpdates(first, second);
|
|
10833
|
+
return { ...mergeMapStorageUpdates(first, second), source };
|
|
9513
10834
|
} else if (first.type === "LiveList" && second.type === "LiveList") {
|
|
9514
|
-
return mergeListStorageUpdates(first, second);
|
|
10835
|
+
return { ...mergeListStorageUpdates(first, second), source };
|
|
10836
|
+
} else if (first.type === "LiveText" && second.type === "LiveText") {
|
|
10837
|
+
return { ...mergeTextStorageUpdates(first, second), source };
|
|
9515
10838
|
} else {
|
|
10839
|
+
return { ...second, source };
|
|
9516
10840
|
}
|
|
9517
|
-
return second;
|
|
9518
10841
|
}
|
|
9519
10842
|
|
|
9520
10843
|
// src/devtools/bridge.ts
|
|
@@ -9530,7 +10853,7 @@ function sendToPanel(message, options) {
|
|
|
9530
10853
|
...message,
|
|
9531
10854
|
source: "liveblocks-devtools-client"
|
|
9532
10855
|
};
|
|
9533
|
-
if (!(_optionalChain([options, 'optionalAccess',
|
|
10856
|
+
if (!(_optionalChain([options, 'optionalAccess', _245 => _245.force]) || _bridgeActive)) {
|
|
9534
10857
|
return;
|
|
9535
10858
|
}
|
|
9536
10859
|
window.postMessage(fullMsg, "*");
|
|
@@ -9538,7 +10861,7 @@ function sendToPanel(message, options) {
|
|
|
9538
10861
|
var eventSource = makeEventSource();
|
|
9539
10862
|
if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
|
|
9540
10863
|
window.addEventListener("message", (event) => {
|
|
9541
|
-
if (event.source === window && _optionalChain([event, 'access',
|
|
10864
|
+
if (event.source === window && _optionalChain([event, 'access', _246 => _246.data, 'optionalAccess', _247 => _247.source]) === "liveblocks-devtools-panel") {
|
|
9542
10865
|
eventSource.notify(event.data);
|
|
9543
10866
|
} else {
|
|
9544
10867
|
}
|
|
@@ -9680,7 +11003,7 @@ function fullSync(room) {
|
|
|
9680
11003
|
msg: "room::sync::full",
|
|
9681
11004
|
roomId: room.id,
|
|
9682
11005
|
status: room.getStatus(),
|
|
9683
|
-
storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess',
|
|
11006
|
+
storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _248 => _248.toTreeNode, 'call', _249 => _249("root"), 'access', _250 => _250.payload]), () => ( null)),
|
|
9684
11007
|
me,
|
|
9685
11008
|
others
|
|
9686
11009
|
});
|
|
@@ -10367,15 +11690,15 @@ function installBackgroundTabSpy() {
|
|
|
10367
11690
|
const doc = typeof document !== "undefined" ? document : void 0;
|
|
10368
11691
|
const inBackgroundSince = { current: null };
|
|
10369
11692
|
function onVisibilityChange() {
|
|
10370
|
-
if (_optionalChain([doc, 'optionalAccess',
|
|
11693
|
+
if (_optionalChain([doc, 'optionalAccess', _251 => _251.visibilityState]) === "hidden") {
|
|
10371
11694
|
inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
|
|
10372
11695
|
} else {
|
|
10373
11696
|
inBackgroundSince.current = null;
|
|
10374
11697
|
}
|
|
10375
11698
|
}
|
|
10376
|
-
_optionalChain([doc, 'optionalAccess',
|
|
11699
|
+
_optionalChain([doc, 'optionalAccess', _252 => _252.addEventListener, 'call', _253 => _253("visibilitychange", onVisibilityChange)]);
|
|
10377
11700
|
const unsub = () => {
|
|
10378
|
-
_optionalChain([doc, 'optionalAccess',
|
|
11701
|
+
_optionalChain([doc, 'optionalAccess', _254 => _254.removeEventListener, 'call', _255 => _255("visibilitychange", onVisibilityChange)]);
|
|
10379
11702
|
};
|
|
10380
11703
|
return [inBackgroundSince, unsub];
|
|
10381
11704
|
}
|
|
@@ -10399,7 +11722,7 @@ function makeNodeMapBuffer() {
|
|
|
10399
11722
|
function topLevelKeysOf(nodes) {
|
|
10400
11723
|
const keys2 = /* @__PURE__ */ new Set();
|
|
10401
11724
|
const root = nodes.get("root");
|
|
10402
|
-
for (const key in _optionalChain([root, 'optionalAccess',
|
|
11725
|
+
for (const key in _optionalChain([root, 'optionalAccess', _256 => _256.data])) {
|
|
10403
11726
|
keys2.add(key);
|
|
10404
11727
|
}
|
|
10405
11728
|
for (const node of nodes.values()) {
|
|
@@ -10471,6 +11794,8 @@ function createRoom(options, config) {
|
|
|
10471
11794
|
activeBatch: null,
|
|
10472
11795
|
unacknowledgedOps
|
|
10473
11796
|
};
|
|
11797
|
+
let nextHistoryItemId = 0;
|
|
11798
|
+
let historyDisabled = 0;
|
|
10474
11799
|
const nodeMapBuffer = makeNodeMapBuffer();
|
|
10475
11800
|
const stopwatch = config.enableDebugLogging ? makeStopWatch() : void 0;
|
|
10476
11801
|
let lastTokenKey;
|
|
@@ -10555,7 +11880,7 @@ function createRoom(options, config) {
|
|
|
10555
11880
|
}
|
|
10556
11881
|
}
|
|
10557
11882
|
});
|
|
10558
|
-
function onDispatch(ops, reverse, storageUpdates) {
|
|
11883
|
+
function onDispatch(ops, reverse, storageUpdates, options2) {
|
|
10559
11884
|
if (context.activeBatch) {
|
|
10560
11885
|
for (const op of ops) {
|
|
10561
11886
|
context.activeBatch.ops.push(op);
|
|
@@ -10570,19 +11895,24 @@ function createRoom(options, config) {
|
|
|
10570
11895
|
);
|
|
10571
11896
|
}
|
|
10572
11897
|
context.activeBatch.reverseOps.pushLeft(reverse);
|
|
11898
|
+
if (_optionalChain([options2, 'optionalAccess', _257 => _257.clearRedoStack])) {
|
|
11899
|
+
context.activeBatch.clearRedoStack = true;
|
|
11900
|
+
}
|
|
10573
11901
|
} else {
|
|
10574
11902
|
if (reverse.length > 0) {
|
|
10575
11903
|
addToUndoStack(reverse);
|
|
10576
11904
|
}
|
|
11905
|
+
if (_nullishCoalesce(_optionalChain([options2, 'optionalAccess', _258 => _258.clearRedoStack]), () => ( ops.length > 0))) {
|
|
11906
|
+
clearRedoStack();
|
|
11907
|
+
}
|
|
10577
11908
|
if (ops.length > 0) {
|
|
10578
|
-
context.redoStack.length = 0;
|
|
10579
11909
|
dispatchOps(ops);
|
|
10580
11910
|
}
|
|
10581
11911
|
notify({ storageUpdates });
|
|
10582
11912
|
}
|
|
10583
11913
|
}
|
|
10584
11914
|
function isStorageWritable() {
|
|
10585
|
-
const permissionMatrix = _optionalChain([context, 'access',
|
|
11915
|
+
const permissionMatrix = _optionalChain([context, 'access', _259 => _259.dynamicSessionInfoSig, 'access', _260 => _260.get, 'call', _261 => _261(), 'optionalAccess', _262 => _262.permissionMatrix]);
|
|
10586
11916
|
return permissionMatrix !== void 0 ? hasPermissionAccess(permissionMatrix, "storage", "write") : true;
|
|
10587
11917
|
}
|
|
10588
11918
|
const eventHub = {
|
|
@@ -10595,6 +11925,7 @@ function createRoom(options, config) {
|
|
|
10595
11925
|
others: makeEventSource(),
|
|
10596
11926
|
storageBatch: makeEventSource(),
|
|
10597
11927
|
history: makeEventSource(),
|
|
11928
|
+
privateHistory: makeEventSource(),
|
|
10598
11929
|
storageDidLoad: makeEventSource(),
|
|
10599
11930
|
storageStatus: makeEventSource(),
|
|
10600
11931
|
ydoc: makeEventSource(),
|
|
@@ -10682,12 +12013,12 @@ function createRoom(options, config) {
|
|
|
10682
12013
|
self,
|
|
10683
12014
|
(me) => me !== null ? userToTreeNode("Me", me) : null
|
|
10684
12015
|
);
|
|
10685
|
-
function diffCurrentStorageAgainst(target) {
|
|
12016
|
+
function diffCurrentStorageAgainst(target, options2) {
|
|
10686
12017
|
const current = /* @__PURE__ */ new Map();
|
|
10687
12018
|
for (const [id, crdt] of context.pool.nodes) {
|
|
10688
12019
|
current.set(id, crdt._serialize());
|
|
10689
12020
|
}
|
|
10690
|
-
return diffNodeMap(current, target);
|
|
12021
|
+
return diffNodeMap(current, target, options2);
|
|
10691
12022
|
}
|
|
10692
12023
|
function createOrUpdateRootFromMessage(nodes) {
|
|
10693
12024
|
if (nodes.size === 0) {
|
|
@@ -10695,6 +12026,23 @@ function createRoom(options, config) {
|
|
|
10695
12026
|
}
|
|
10696
12027
|
if (context.root !== void 0) {
|
|
10697
12028
|
const result = applyRemoteOps(diffCurrentStorageAgainst(nodes));
|
|
12029
|
+
for (const [id, crdt] of nodes) {
|
|
12030
|
+
if (crdt.type === CrdtType.TEXT) {
|
|
12031
|
+
const node = context.pool.nodes.get(id);
|
|
12032
|
+
if (node !== void 0 && isLiveText(node)) {
|
|
12033
|
+
const update = node._resyncText(crdt.data, crdt.version, REMOTE);
|
|
12034
|
+
if (update !== void 0) {
|
|
12035
|
+
result.updates.storageUpdates.set(
|
|
12036
|
+
id,
|
|
12037
|
+
mergeStorageUpdates(
|
|
12038
|
+
result.updates.storageUpdates.get(id),
|
|
12039
|
+
update
|
|
12040
|
+
)
|
|
12041
|
+
);
|
|
12042
|
+
}
|
|
12043
|
+
}
|
|
12044
|
+
}
|
|
12045
|
+
}
|
|
10698
12046
|
notify(result.updates);
|
|
10699
12047
|
} else {
|
|
10700
12048
|
context.root = LiveObject._fromItems(
|
|
@@ -10702,7 +12050,7 @@ function createRoom(options, config) {
|
|
|
10702
12050
|
context.pool
|
|
10703
12051
|
);
|
|
10704
12052
|
}
|
|
10705
|
-
const canWrite = _nullishCoalesce(_optionalChain([self, 'access',
|
|
12053
|
+
const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _263 => _263.get, 'call', _264 => _264(), 'optionalAccess', _265 => _265.canWrite]), () => ( true));
|
|
10706
12054
|
const serverTopLevelKeys = topLevelKeysOf(nodes);
|
|
10707
12055
|
const root = context.root;
|
|
10708
12056
|
disableHistory(() => {
|
|
@@ -10719,12 +12067,23 @@ function createRoom(options, config) {
|
|
|
10719
12067
|
}
|
|
10720
12068
|
});
|
|
10721
12069
|
}
|
|
12070
|
+
function notifyPrivateHistory(event) {
|
|
12071
|
+
if (historyDisabled > 0) return;
|
|
12072
|
+
eventHub.privateHistory.notify(event);
|
|
12073
|
+
}
|
|
12074
|
+
function clearRedoStack() {
|
|
12075
|
+
if (context.redoStack.length === 0) return;
|
|
12076
|
+
const ids = context.redoStack.map((item) => item.id);
|
|
12077
|
+
context.redoStack.length = 0;
|
|
12078
|
+
notifyPrivateHistory({ action: "discard", ids });
|
|
12079
|
+
}
|
|
10722
12080
|
function reconcileStorageWithNodes(nodes) {
|
|
10723
12081
|
if (context.root === void 0) {
|
|
10724
12082
|
throw new Error("Cannot reconcile storage before it is loaded");
|
|
10725
12083
|
}
|
|
10726
12084
|
const ops = diffCurrentStorageAgainst(
|
|
10727
|
-
new Map(nodes)
|
|
12085
|
+
new Map(nodes),
|
|
12086
|
+
{ includeLiveTextUpdates: true }
|
|
10728
12087
|
);
|
|
10729
12088
|
if (ops.length === 0) {
|
|
10730
12089
|
return;
|
|
@@ -10743,9 +12102,14 @@ function createRoom(options, config) {
|
|
|
10743
12102
|
}
|
|
10744
12103
|
function _addToRealUndoStack(frames) {
|
|
10745
12104
|
if (context.undoStack.length >= 50) {
|
|
10746
|
-
context.undoStack.shift();
|
|
12105
|
+
const evicted = context.undoStack.shift();
|
|
12106
|
+
if (evicted !== void 0) {
|
|
12107
|
+
notifyPrivateHistory({ action: "discard", ids: [evicted.id] });
|
|
12108
|
+
}
|
|
10747
12109
|
}
|
|
10748
|
-
|
|
12110
|
+
const id = nextHistoryItemId++;
|
|
12111
|
+
context.undoStack.push({ id, frames });
|
|
12112
|
+
notifyPrivateHistory({ action: "push", id });
|
|
10749
12113
|
onHistoryChange();
|
|
10750
12114
|
}
|
|
10751
12115
|
function addToUndoStack(frames) {
|
|
@@ -10769,7 +12133,10 @@ function createRoom(options, config) {
|
|
|
10769
12133
|
eventHub.myPresence.notify(context.myPresence.get());
|
|
10770
12134
|
}
|
|
10771
12135
|
if (storageUpdates !== void 0 && storageUpdates.size > 0) {
|
|
10772
|
-
const updates2 = Array.from(storageUpdates.values())
|
|
12136
|
+
const updates2 = Array.from(storageUpdates.values(), (update) => ({
|
|
12137
|
+
...update,
|
|
12138
|
+
source: toUpdateSource(update.source)
|
|
12139
|
+
}));
|
|
10773
12140
|
eventHub.storageBatch.notify(updates2);
|
|
10774
12141
|
}
|
|
10775
12142
|
notifyStorageStatus();
|
|
@@ -10783,19 +12150,69 @@ function createRoom(options, config) {
|
|
|
10783
12150
|
"Internal. Tried to get connection id but connection was never open"
|
|
10784
12151
|
);
|
|
10785
12152
|
}
|
|
10786
|
-
|
|
12153
|
+
const viaByOpId = /* @__PURE__ */ new Map();
|
|
12154
|
+
function viaOfAckedOp(opId) {
|
|
12155
|
+
const via = viaByOpId.get(opId);
|
|
12156
|
+
if (via === void 0) {
|
|
12157
|
+
return "edit";
|
|
12158
|
+
}
|
|
12159
|
+
viaByOpId.delete(opId);
|
|
12160
|
+
return via;
|
|
12161
|
+
}
|
|
12162
|
+
function applyLocalOps(frames, localSource = LOCAL_EDIT) {
|
|
10787
12163
|
const [pframes, ops] = partition(
|
|
10788
12164
|
frames,
|
|
10789
12165
|
(f) => f.type === "presence"
|
|
10790
12166
|
);
|
|
10791
|
-
const
|
|
12167
|
+
const restoredTextIds = /* @__PURE__ */ new Map();
|
|
12168
|
+
for (const op of ops) {
|
|
12169
|
+
if (op.type === OpCode.CREATE_TEXT && op.opId === void 0 && context.pool.nodes.get(op.id) === void 0 && !restoredTextIds.has(op.id)) {
|
|
12170
|
+
restoredTextIds.set(op.id, context.pool.generateId());
|
|
12171
|
+
}
|
|
12172
|
+
}
|
|
12173
|
+
const remappedOps = restoredTextIds.size === 0 ? ops : ops.map((op) => {
|
|
12174
|
+
if (op.opId !== void 0) {
|
|
12175
|
+
return op;
|
|
12176
|
+
}
|
|
12177
|
+
const id = restoredTextIds.get(op.id);
|
|
12178
|
+
if (isCreateOp(op)) {
|
|
12179
|
+
const parentId = restoredTextIds.get(op.parentId);
|
|
12180
|
+
const deletedId = op.deletedId === void 0 ? void 0 : restoredTextIds.get(op.deletedId);
|
|
12181
|
+
if (id === void 0 && parentId === void 0 && deletedId === void 0) {
|
|
12182
|
+
return op;
|
|
12183
|
+
}
|
|
12184
|
+
if (op.type === OpCode.CREATE_TEXT && id !== void 0) {
|
|
12185
|
+
return {
|
|
12186
|
+
...op,
|
|
12187
|
+
id,
|
|
12188
|
+
version: 0,
|
|
12189
|
+
...parentId === void 0 ? {} : { parentId },
|
|
12190
|
+
...deletedId === void 0 ? {} : { deletedId }
|
|
12191
|
+
};
|
|
12192
|
+
}
|
|
12193
|
+
return {
|
|
12194
|
+
...op,
|
|
12195
|
+
...id === void 0 ? {} : { id },
|
|
12196
|
+
...parentId === void 0 ? {} : { parentId },
|
|
12197
|
+
...deletedId === void 0 ? {} : { deletedId }
|
|
12198
|
+
};
|
|
12199
|
+
}
|
|
12200
|
+
return id === void 0 ? op : { ...op, id };
|
|
12201
|
+
});
|
|
12202
|
+
const opsWithOpIds = remappedOps.map(
|
|
10792
12203
|
(op) => op.opId === void 0 ? { ...op, opId: context.pool.generateOpId() } : op
|
|
10793
12204
|
);
|
|
12205
|
+
if (localSource.via !== "edit") {
|
|
12206
|
+
for (const op of opsWithOpIds) {
|
|
12207
|
+
viaByOpId.set(op.opId, localSource.via);
|
|
12208
|
+
}
|
|
12209
|
+
}
|
|
10794
12210
|
const { reverse, updates } = applyOps(
|
|
10795
12211
|
pframes,
|
|
10796
12212
|
opsWithOpIds,
|
|
10797
12213
|
/* isLocal */
|
|
10798
|
-
true
|
|
12214
|
+
true,
|
|
12215
|
+
localSource
|
|
10799
12216
|
);
|
|
10800
12217
|
return { opsToEmit: opsWithOpIds, reverse, updates };
|
|
10801
12218
|
}
|
|
@@ -10807,7 +12224,7 @@ function createRoom(options, config) {
|
|
|
10807
12224
|
false
|
|
10808
12225
|
);
|
|
10809
12226
|
}
|
|
10810
|
-
function applyOps(pframes, ops, isLocal) {
|
|
12227
|
+
function applyOps(pframes, ops, isLocal, localSource = LOCAL_EDIT) {
|
|
10811
12228
|
const output = {
|
|
10812
12229
|
reverse: new Deque(),
|
|
10813
12230
|
storageUpdates: /* @__PURE__ */ new Map(),
|
|
@@ -10836,12 +12253,16 @@ function createRoom(options, config) {
|
|
|
10836
12253
|
for (const op of ops) {
|
|
10837
12254
|
let source;
|
|
10838
12255
|
if (isLocal) {
|
|
10839
|
-
source =
|
|
12256
|
+
source = { ...localSource, optimistic: true };
|
|
10840
12257
|
} else if (op.opId !== void 0) {
|
|
10841
12258
|
context.unacknowledgedOps.delete(op.opId);
|
|
10842
|
-
source =
|
|
12259
|
+
source = {
|
|
12260
|
+
origin: "local",
|
|
12261
|
+
via: viaOfAckedOp(op.opId),
|
|
12262
|
+
optimistic: false
|
|
12263
|
+
};
|
|
10843
12264
|
} else {
|
|
10844
|
-
source =
|
|
12265
|
+
source = REMOTE;
|
|
10845
12266
|
}
|
|
10846
12267
|
const applyOpResult = applyOp(op, source);
|
|
10847
12268
|
if (applyOpResult.modified) {
|
|
@@ -10856,7 +12277,7 @@ function createRoom(options, config) {
|
|
|
10856
12277
|
);
|
|
10857
12278
|
output.reverse.pushLeft(applyOpResult.reverse);
|
|
10858
12279
|
}
|
|
10859
|
-
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_FILE) {
|
|
12280
|
+
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_TEXT || op.type === OpCode.CREATE_FILE) {
|
|
10860
12281
|
createdNodeIds.add(op.id);
|
|
10861
12282
|
}
|
|
10862
12283
|
}
|
|
@@ -10876,12 +12297,13 @@ function createRoom(options, config) {
|
|
|
10876
12297
|
switch (op.type) {
|
|
10877
12298
|
case OpCode.DELETE_OBJECT_KEY:
|
|
10878
12299
|
case OpCode.UPDATE_OBJECT:
|
|
12300
|
+
case OpCode.UPDATE_TEXT:
|
|
10879
12301
|
case OpCode.DELETE_CRDT: {
|
|
10880
12302
|
const node = context.pool.nodes.get(op.id);
|
|
10881
12303
|
if (node === void 0) {
|
|
10882
12304
|
return { modified: false };
|
|
10883
12305
|
}
|
|
10884
|
-
return node._apply(op, source
|
|
12306
|
+
return node._apply(op, source);
|
|
10885
12307
|
}
|
|
10886
12308
|
case OpCode.SET_PARENT_KEY: {
|
|
10887
12309
|
const node = context.pool.nodes.get(op.id);
|
|
@@ -10900,6 +12322,7 @@ function createRoom(options, config) {
|
|
|
10900
12322
|
case OpCode.CREATE_OBJECT:
|
|
10901
12323
|
case OpCode.CREATE_LIST:
|
|
10902
12324
|
case OpCode.CREATE_MAP:
|
|
12325
|
+
case OpCode.CREATE_TEXT:
|
|
10903
12326
|
case OpCode.CREATE_FILE:
|
|
10904
12327
|
case OpCode.CREATE_REGISTER: {
|
|
10905
12328
|
if (op.parentId === void 0) {
|
|
@@ -10935,7 +12358,7 @@ function createRoom(options, config) {
|
|
|
10935
12358
|
}
|
|
10936
12359
|
context.myPresence.patch(patch);
|
|
10937
12360
|
if (context.activeBatch) {
|
|
10938
|
-
if (_optionalChain([options2, 'optionalAccess',
|
|
12361
|
+
if (_optionalChain([options2, 'optionalAccess', _266 => _266.addToHistory])) {
|
|
10939
12362
|
context.activeBatch.reverseOps.pushLeft({
|
|
10940
12363
|
type: "presence",
|
|
10941
12364
|
data: oldValues
|
|
@@ -10944,7 +12367,7 @@ function createRoom(options, config) {
|
|
|
10944
12367
|
context.activeBatch.updates.presence = true;
|
|
10945
12368
|
} else {
|
|
10946
12369
|
flushNowOrSoon();
|
|
10947
|
-
if (_optionalChain([options2, 'optionalAccess',
|
|
12370
|
+
if (_optionalChain([options2, 'optionalAccess', _267 => _267.addToHistory])) {
|
|
10948
12371
|
addToUndoStack([{ type: "presence", data: oldValues }]);
|
|
10949
12372
|
}
|
|
10950
12373
|
notify({ presence: true });
|
|
@@ -11123,11 +12546,11 @@ function createRoom(options, config) {
|
|
|
11123
12546
|
break;
|
|
11124
12547
|
}
|
|
11125
12548
|
case ServerMsgCode.STORAGE_CHUNK:
|
|
11126
|
-
_optionalChain([stopwatch, 'optionalAccess',
|
|
12549
|
+
_optionalChain([stopwatch, 'optionalAccess', _268 => _268.lap, 'call', _269 => _269()]);
|
|
11127
12550
|
nodeMapBuffer.append(compactNodesToNodeStream(message.nodes));
|
|
11128
12551
|
break;
|
|
11129
12552
|
case ServerMsgCode.STORAGE_STREAM_END: {
|
|
11130
|
-
const timing = _optionalChain([stopwatch, 'optionalAccess',
|
|
12553
|
+
const timing = _optionalChain([stopwatch, 'optionalAccess', _270 => _270.stop, 'call', _271 => _271()]);
|
|
11131
12554
|
if (timing) {
|
|
11132
12555
|
const ms = (v) => `${v.toFixed(1)}ms`;
|
|
11133
12556
|
const rest = timing.laps.slice(1);
|
|
@@ -11154,16 +12577,38 @@ function createRoom(options, config) {
|
|
|
11154
12577
|
}
|
|
11155
12578
|
break;
|
|
11156
12579
|
}
|
|
11157
|
-
// Receiving a RejectedOps message
|
|
11158
|
-
//
|
|
11159
|
-
//
|
|
11160
|
-
//
|
|
12580
|
+
// Receiving a RejectedOps message means the server refused some of
|
|
12581
|
+
// our ops, so our optimistic local state is out of sync with the
|
|
12582
|
+
// server. For LiveText ops this is a normal (if rare) situation —
|
|
12583
|
+
// e.g. a client that was offline long enough to fall outside the
|
|
12584
|
+
// server's retained history window — and we can recover: drop the
|
|
12585
|
+
// rejected pending state and re-fetch the authoritative storage
|
|
12586
|
+
// snapshot. For other ops (e.g. permission rejections), rolling back
|
|
12587
|
+
// particular Ops is hard/impossible, so we keep the old behavior of
|
|
12588
|
+
// accepting the out-of-sync reality and surfacing an error.
|
|
11161
12589
|
case ServerMsgCode.REJECT_STORAGE_OP: {
|
|
11162
12590
|
errorWithTitle(
|
|
11163
12591
|
"Storage mutation rejection error",
|
|
11164
12592
|
message.reason
|
|
11165
12593
|
);
|
|
11166
|
-
|
|
12594
|
+
let needsStorageResync = false;
|
|
12595
|
+
for (const opId of message.opIds) {
|
|
12596
|
+
const rejectedOp = context.unacknowledgedOps.get(opId);
|
|
12597
|
+
context.unacknowledgedOps.delete(opId);
|
|
12598
|
+
context.buffer.storageOperations = context.buffer.storageOperations.filter((op) => op.opId !== opId);
|
|
12599
|
+
viaByOpId.delete(opId);
|
|
12600
|
+
if (rejectedOp !== void 0 && rejectedOp.type === OpCode.UPDATE_TEXT) {
|
|
12601
|
+
const node = context.pool.nodes.get(rejectedOp.id);
|
|
12602
|
+
if (node !== void 0 && isLiveText(node)) {
|
|
12603
|
+
node._rejectPendingOp(opId);
|
|
12604
|
+
needsStorageResync = true;
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
}
|
|
12608
|
+
if (needsStorageResync) {
|
|
12609
|
+
refreshStorage();
|
|
12610
|
+
flushNowOrSoon();
|
|
12611
|
+
} else if (process.env.NODE_ENV !== "production") {
|
|
11167
12612
|
throw new Error(
|
|
11168
12613
|
`Storage mutations rejected by server: ${message.reason}`
|
|
11169
12614
|
);
|
|
@@ -11262,11 +12707,11 @@ function createRoom(options, config) {
|
|
|
11262
12707
|
} else if (pendingFeedsRequests.has(requestId)) {
|
|
11263
12708
|
const pending = pendingFeedsRequests.get(requestId);
|
|
11264
12709
|
pendingFeedsRequests.delete(requestId);
|
|
11265
|
-
_optionalChain([pending, 'optionalAccess',
|
|
12710
|
+
_optionalChain([pending, 'optionalAccess', _272 => _272.reject, 'call', _273 => _273(err)]);
|
|
11266
12711
|
} else if (pendingFeedMessagesRequests.has(requestId)) {
|
|
11267
12712
|
const pending = pendingFeedMessagesRequests.get(requestId);
|
|
11268
12713
|
pendingFeedMessagesRequests.delete(requestId);
|
|
11269
|
-
_optionalChain([pending, 'optionalAccess',
|
|
12714
|
+
_optionalChain([pending, 'optionalAccess', _274 => _274.reject, 'call', _275 => _275(err)]);
|
|
11270
12715
|
}
|
|
11271
12716
|
eventHub.feeds.notify(message);
|
|
11272
12717
|
break;
|
|
@@ -11420,10 +12865,10 @@ function createRoom(options, config) {
|
|
|
11420
12865
|
timeoutId,
|
|
11421
12866
|
kind,
|
|
11422
12867
|
feedId,
|
|
11423
|
-
messageId: _optionalChain([options2, 'optionalAccess',
|
|
11424
|
-
expectedClientMessageId: _optionalChain([options2, 'optionalAccess',
|
|
12868
|
+
messageId: _optionalChain([options2, 'optionalAccess', _276 => _276.messageId]),
|
|
12869
|
+
expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _277 => _277.expectedClientMessageId])
|
|
11425
12870
|
});
|
|
11426
|
-
if (kind === "add-message" && _optionalChain([options2, 'optionalAccess',
|
|
12871
|
+
if (kind === "add-message" && _optionalChain([options2, 'optionalAccess', _278 => _278.expectedClientMessageId]) === void 0) {
|
|
11427
12872
|
const q = _nullishCoalesce(pendingAddMessageFifoByFeed.get(feedId), () => ( []));
|
|
11428
12873
|
q.push(requestId);
|
|
11429
12874
|
pendingAddMessageFifoByFeed.set(feedId, q);
|
|
@@ -11474,10 +12919,10 @@ function createRoom(options, config) {
|
|
|
11474
12919
|
}
|
|
11475
12920
|
if (!matched) {
|
|
11476
12921
|
const q = pendingAddMessageFifoByFeed.get(message.feedId);
|
|
11477
|
-
const headId = _optionalChain([q, 'optionalAccess',
|
|
12922
|
+
const headId = _optionalChain([q, 'optionalAccess', _279 => _279[0]]);
|
|
11478
12923
|
if (headId !== void 0) {
|
|
11479
12924
|
const pending = pendingFeedMutations.get(headId);
|
|
11480
|
-
if (_optionalChain([pending, 'optionalAccess',
|
|
12925
|
+
if (_optionalChain([pending, 'optionalAccess', _280 => _280.kind]) === "add-message" && pending.expectedClientMessageId === void 0) {
|
|
11481
12926
|
settleFeedMutation(headId, "ok");
|
|
11482
12927
|
}
|
|
11483
12928
|
}
|
|
@@ -11513,7 +12958,7 @@ function createRoom(options, config) {
|
|
|
11513
12958
|
const unacknowledgedOps2 = [...context.unacknowledgedOps.values()];
|
|
11514
12959
|
createOrUpdateRootFromMessage(nodes);
|
|
11515
12960
|
applyAndSendOfflineOps(unacknowledgedOps2);
|
|
11516
|
-
_optionalChain([_resolveStoragePromise, 'optionalCall',
|
|
12961
|
+
_optionalChain([_resolveStoragePromise, 'optionalCall', _281 => _281()]);
|
|
11517
12962
|
notifyStorageStatus();
|
|
11518
12963
|
eventHub.storageDidLoad.notify();
|
|
11519
12964
|
}
|
|
@@ -11522,7 +12967,7 @@ function createRoom(options, config) {
|
|
|
11522
12967
|
if (!messages.some((msg) => msg.type === ClientMsgCode.FETCH_STORAGE)) {
|
|
11523
12968
|
messages.push({ type: ClientMsgCode.FETCH_STORAGE });
|
|
11524
12969
|
nodeMapBuffer.take();
|
|
11525
|
-
_optionalChain([stopwatch, 'optionalAccess',
|
|
12970
|
+
_optionalChain([stopwatch, 'optionalAccess', _282 => _282.start, 'call', _283 => _283()]);
|
|
11526
12971
|
}
|
|
11527
12972
|
}
|
|
11528
12973
|
function startLoadingStorage() {
|
|
@@ -11576,10 +13021,10 @@ function createRoom(options, config) {
|
|
|
11576
13021
|
const message = {
|
|
11577
13022
|
type: ClientMsgCode.FETCH_FEEDS,
|
|
11578
13023
|
requestId,
|
|
11579
|
-
cursor: _optionalChain([options2, 'optionalAccess',
|
|
11580
|
-
since: _optionalChain([options2, 'optionalAccess',
|
|
11581
|
-
limit: _optionalChain([options2, 'optionalAccess',
|
|
11582
|
-
metadata: _optionalChain([options2, 'optionalAccess',
|
|
13024
|
+
cursor: _optionalChain([options2, 'optionalAccess', _284 => _284.cursor]),
|
|
13025
|
+
since: _optionalChain([options2, 'optionalAccess', _285 => _285.since]),
|
|
13026
|
+
limit: _optionalChain([options2, 'optionalAccess', _286 => _286.limit]),
|
|
13027
|
+
metadata: _optionalChain([options2, 'optionalAccess', _287 => _287.metadata])
|
|
11583
13028
|
};
|
|
11584
13029
|
context.buffer.messages.push(message);
|
|
11585
13030
|
flushNowOrSoon();
|
|
@@ -11599,9 +13044,9 @@ function createRoom(options, config) {
|
|
|
11599
13044
|
type: ClientMsgCode.FETCH_FEED_MESSAGES,
|
|
11600
13045
|
requestId,
|
|
11601
13046
|
feedId,
|
|
11602
|
-
cursor: _optionalChain([options2, 'optionalAccess',
|
|
11603
|
-
since: _optionalChain([options2, 'optionalAccess',
|
|
11604
|
-
limit: _optionalChain([options2, 'optionalAccess',
|
|
13047
|
+
cursor: _optionalChain([options2, 'optionalAccess', _288 => _288.cursor]),
|
|
13048
|
+
since: _optionalChain([options2, 'optionalAccess', _289 => _289.since]),
|
|
13049
|
+
limit: _optionalChain([options2, 'optionalAccess', _290 => _290.limit])
|
|
11605
13050
|
};
|
|
11606
13051
|
context.buffer.messages.push(message);
|
|
11607
13052
|
flushNowOrSoon();
|
|
@@ -11620,8 +13065,8 @@ function createRoom(options, config) {
|
|
|
11620
13065
|
type: ClientMsgCode.ADD_FEED,
|
|
11621
13066
|
requestId,
|
|
11622
13067
|
feedId,
|
|
11623
|
-
metadata: _optionalChain([options2, 'optionalAccess',
|
|
11624
|
-
createdAt: _optionalChain([options2, 'optionalAccess',
|
|
13068
|
+
metadata: _optionalChain([options2, 'optionalAccess', _291 => _291.metadata]),
|
|
13069
|
+
createdAt: _optionalChain([options2, 'optionalAccess', _292 => _292.createdAt])
|
|
11625
13070
|
};
|
|
11626
13071
|
context.buffer.messages.push(message);
|
|
11627
13072
|
flushNowOrSoon();
|
|
@@ -11655,15 +13100,15 @@ function createRoom(options, config) {
|
|
|
11655
13100
|
function addFeedMessage(feedId, data, options2) {
|
|
11656
13101
|
const requestId = nanoid();
|
|
11657
13102
|
const promise = registerFeedMutation(requestId, "add-message", feedId, {
|
|
11658
|
-
expectedClientMessageId: _optionalChain([options2, 'optionalAccess',
|
|
13103
|
+
expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _293 => _293.id])
|
|
11659
13104
|
});
|
|
11660
13105
|
const message = {
|
|
11661
13106
|
type: ClientMsgCode.ADD_FEED_MESSAGE,
|
|
11662
13107
|
requestId,
|
|
11663
13108
|
feedId,
|
|
11664
13109
|
data,
|
|
11665
|
-
id: _optionalChain([options2, 'optionalAccess',
|
|
11666
|
-
createdAt: _optionalChain([options2, 'optionalAccess',
|
|
13110
|
+
id: _optionalChain([options2, 'optionalAccess', _294 => _294.id]),
|
|
13111
|
+
createdAt: _optionalChain([options2, 'optionalAccess', _295 => _295.createdAt])
|
|
11667
13112
|
};
|
|
11668
13113
|
context.buffer.messages.push(message);
|
|
11669
13114
|
flushNowOrSoon();
|
|
@@ -11680,7 +13125,7 @@ function createRoom(options, config) {
|
|
|
11680
13125
|
feedId,
|
|
11681
13126
|
messageId,
|
|
11682
13127
|
data,
|
|
11683
|
-
updatedAt: _optionalChain([options2, 'optionalAccess',
|
|
13128
|
+
updatedAt: _optionalChain([options2, 'optionalAccess', _296 => _296.updatedAt])
|
|
11684
13129
|
};
|
|
11685
13130
|
context.buffer.messages.push(message);
|
|
11686
13131
|
flushNowOrSoon();
|
|
@@ -11705,14 +13150,15 @@ function createRoom(options, config) {
|
|
|
11705
13150
|
if (context.activeBatch) {
|
|
11706
13151
|
throw new Error("undo is not allowed during a batch");
|
|
11707
13152
|
}
|
|
11708
|
-
const
|
|
11709
|
-
if (
|
|
13153
|
+
const item = context.undoStack.pop();
|
|
13154
|
+
if (item === void 0) {
|
|
11710
13155
|
return;
|
|
11711
13156
|
}
|
|
11712
13157
|
context.pausedHistory = null;
|
|
11713
|
-
const result = applyLocalOps(frames);
|
|
13158
|
+
const result = applyLocalOps(item.frames, LOCAL_UNDO);
|
|
13159
|
+
context.redoStack.push({ id: item.id, frames: result.reverse });
|
|
13160
|
+
notifyPrivateHistory({ action: "undo", id: item.id });
|
|
11714
13161
|
notify(result.updates);
|
|
11715
|
-
context.redoStack.push(result.reverse);
|
|
11716
13162
|
onHistoryChange();
|
|
11717
13163
|
for (const op of result.opsToEmit) {
|
|
11718
13164
|
context.buffer.storageOperations.push(op);
|
|
@@ -11723,14 +13169,15 @@ function createRoom(options, config) {
|
|
|
11723
13169
|
if (context.activeBatch) {
|
|
11724
13170
|
throw new Error("redo is not allowed during a batch");
|
|
11725
13171
|
}
|
|
11726
|
-
const
|
|
11727
|
-
if (
|
|
13172
|
+
const item = context.redoStack.pop();
|
|
13173
|
+
if (item === void 0) {
|
|
11728
13174
|
return;
|
|
11729
13175
|
}
|
|
11730
13176
|
context.pausedHistory = null;
|
|
11731
|
-
const result = applyLocalOps(frames);
|
|
13177
|
+
const result = applyLocalOps(item.frames, LOCAL_REDO);
|
|
13178
|
+
context.undoStack.push({ id: item.id, frames: result.reverse });
|
|
13179
|
+
notifyPrivateHistory({ action: "redo", id: item.id });
|
|
11732
13180
|
notify(result.updates);
|
|
11733
|
-
context.undoStack.push(result.reverse);
|
|
11734
13181
|
onHistoryChange();
|
|
11735
13182
|
for (const op of result.opsToEmit) {
|
|
11736
13183
|
context.buffer.storageOperations.push(op);
|
|
@@ -11740,6 +13187,8 @@ function createRoom(options, config) {
|
|
|
11740
13187
|
function clear() {
|
|
11741
13188
|
context.undoStack.length = 0;
|
|
11742
13189
|
context.redoStack.length = 0;
|
|
13190
|
+
notifyPrivateHistory({ action: "clear" });
|
|
13191
|
+
onHistoryChange();
|
|
11743
13192
|
}
|
|
11744
13193
|
function batch2(callback) {
|
|
11745
13194
|
if (context.activeBatch) {
|
|
@@ -11767,8 +13216,8 @@ function createRoom(options, config) {
|
|
|
11767
13216
|
if (currentBatch.scheduleHistoryResume) {
|
|
11768
13217
|
commitPausedHistoryToUndoStack();
|
|
11769
13218
|
}
|
|
11770
|
-
if (currentBatch.ops.length > 0) {
|
|
11771
|
-
|
|
13219
|
+
if (currentBatch.ops.length > 0 || currentBatch.clearRedoStack) {
|
|
13220
|
+
clearRedoStack();
|
|
11772
13221
|
}
|
|
11773
13222
|
if (currentBatch.ops.length > 0) {
|
|
11774
13223
|
dispatchOps(currentBatch.ops);
|
|
@@ -11797,7 +13246,6 @@ function createRoom(options, config) {
|
|
|
11797
13246
|
}
|
|
11798
13247
|
commitPausedHistoryToUndoStack();
|
|
11799
13248
|
}
|
|
11800
|
-
let historyDisabled = 0;
|
|
11801
13249
|
function disableHistory(fn) {
|
|
11802
13250
|
const origUndo = context.undoStack;
|
|
11803
13251
|
const origRedo = context.redoStack;
|
|
@@ -11887,8 +13335,8 @@ function createRoom(options, config) {
|
|
|
11887
13335
|
async function getThreads(options2) {
|
|
11888
13336
|
return httpClient.getThreads({
|
|
11889
13337
|
roomId,
|
|
11890
|
-
query: _optionalChain([options2, 'optionalAccess',
|
|
11891
|
-
cursor: _optionalChain([options2, 'optionalAccess',
|
|
13338
|
+
query: _optionalChain([options2, 'optionalAccess', _297 => _297.query]),
|
|
13339
|
+
cursor: _optionalChain([options2, 'optionalAccess', _298 => _298.cursor])
|
|
11892
13340
|
});
|
|
11893
13341
|
}
|
|
11894
13342
|
async function getThread(threadId) {
|
|
@@ -12021,7 +13469,7 @@ function createRoom(options, config) {
|
|
|
12021
13469
|
function getSubscriptionSettings(options2) {
|
|
12022
13470
|
return httpClient.getSubscriptionSettings({
|
|
12023
13471
|
roomId,
|
|
12024
|
-
signal: _optionalChain([options2, 'optionalAccess',
|
|
13472
|
+
signal: _optionalChain([options2, 'optionalAccess', _299 => _299.signal])
|
|
12025
13473
|
});
|
|
12026
13474
|
}
|
|
12027
13475
|
function updateSubscriptionSettings(settings) {
|
|
@@ -12043,30 +13491,45 @@ function createRoom(options, config) {
|
|
|
12043
13491
|
{
|
|
12044
13492
|
[kInternal]: {
|
|
12045
13493
|
get presenceBuffer() {
|
|
12046
|
-
return deepClone(_nullishCoalesce(_optionalChain([context, 'access',
|
|
13494
|
+
return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _300 => _300.buffer, 'access', _301 => _301.presenceUpdates, 'optionalAccess', _302 => _302.data]), () => ( null)));
|
|
12047
13495
|
},
|
|
12048
13496
|
// prettier-ignore
|
|
12049
13497
|
get undoStack() {
|
|
12050
|
-
return
|
|
13498
|
+
return structuredClone(
|
|
13499
|
+
context.undoStack.map((item) => ({
|
|
13500
|
+
id: item.id,
|
|
13501
|
+
frames: item.frames
|
|
13502
|
+
}))
|
|
13503
|
+
);
|
|
13504
|
+
},
|
|
13505
|
+
// prettier-ignore
|
|
13506
|
+
get redoStack() {
|
|
13507
|
+
return structuredClone(
|
|
13508
|
+
context.redoStack.map((item) => ({
|
|
13509
|
+
id: item.id,
|
|
13510
|
+
frames: item.frames
|
|
13511
|
+
}))
|
|
13512
|
+
);
|
|
12051
13513
|
},
|
|
12052
13514
|
// prettier-ignore
|
|
12053
13515
|
get nodeCount() {
|
|
12054
13516
|
return context.pool.nodes.size;
|
|
12055
13517
|
},
|
|
12056
13518
|
// prettier-ignore
|
|
13519
|
+
history: eventHub.privateHistory.observable,
|
|
12057
13520
|
getYjsProvider() {
|
|
12058
13521
|
return context.yjsProvider;
|
|
12059
13522
|
},
|
|
12060
13523
|
setYjsProvider(newProvider) {
|
|
12061
|
-
_optionalChain([context, 'access',
|
|
13524
|
+
_optionalChain([context, 'access', _303 => _303.yjsProvider, 'optionalAccess', _304 => _304.off, 'call', _305 => _305("status", yjsStatusDidChange)]);
|
|
12062
13525
|
context.yjsProvider = newProvider;
|
|
12063
|
-
_optionalChain([newProvider, 'optionalAccess',
|
|
13526
|
+
_optionalChain([newProvider, 'optionalAccess', _306 => _306.on, 'call', _307 => _307("status", yjsStatusDidChange)]);
|
|
12064
13527
|
context.yjsProviderDidChange.notify();
|
|
12065
13528
|
},
|
|
12066
13529
|
yjsProviderDidChange: context.yjsProviderDidChange.observable,
|
|
12067
13530
|
// send metadata when using a text editor
|
|
12068
13531
|
reportTextEditor,
|
|
12069
|
-
getPermissionMatrix: () => _optionalChain([context, 'access',
|
|
13532
|
+
getPermissionMatrix: () => _optionalChain([context, 'access', _308 => _308.dynamicSessionInfoSig, 'access', _309 => _309.get, 'call', _310 => _310(), 'optionalAccess', _311 => _311.permissionMatrix]),
|
|
12070
13533
|
// create a text mention when using a text editor
|
|
12071
13534
|
createTextMention,
|
|
12072
13535
|
// delete a text mention when using a text editor
|
|
@@ -12129,7 +13592,7 @@ ${dumpPool(
|
|
|
12129
13592
|
source.dispose();
|
|
12130
13593
|
}
|
|
12131
13594
|
eventHub.roomWillDestroy.notify();
|
|
12132
|
-
_optionalChain([context, 'access',
|
|
13595
|
+
_optionalChain([context, 'access', _312 => _312.yjsProvider, 'optionalAccess', _313 => _313.off, 'call', _314 => _314("status", yjsStatusDidChange)]);
|
|
12133
13596
|
syncSourceForStorage.destroy();
|
|
12134
13597
|
syncSourceForYjs.destroy();
|
|
12135
13598
|
uninstallBgTabSpy();
|
|
@@ -12293,7 +13756,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
|
|
|
12293
13756
|
}
|
|
12294
13757
|
if (isLiveNode(first)) {
|
|
12295
13758
|
const node = first;
|
|
12296
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
13759
|
+
if (_optionalChain([options, 'optionalAccess', _315 => _315.isDeep])) {
|
|
12297
13760
|
const storageCallback = second;
|
|
12298
13761
|
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
12299
13762
|
} else {
|
|
@@ -12383,8 +13846,8 @@ function createClient(options) {
|
|
|
12383
13846
|
const authManager = createAuthManager(options, (token) => {
|
|
12384
13847
|
currentUserId.set(() => token.uid);
|
|
12385
13848
|
});
|
|
12386
|
-
const fetchPolyfill = _optionalChain([clientOptions, 'access',
|
|
12387
|
-
_optionalChain([globalThis, 'access',
|
|
13849
|
+
const fetchPolyfill = _optionalChain([clientOptions, 'access', _316 => _316.polyfills, 'optionalAccess', _317 => _317.fetch]) || /* istanbul ignore next */
|
|
13850
|
+
_optionalChain([globalThis, 'access', _318 => _318.fetch, 'optionalAccess', _319 => _319.bind, 'call', _320 => _320(globalThis)]);
|
|
12388
13851
|
const httpClient = createApiClient({
|
|
12389
13852
|
baseUrl,
|
|
12390
13853
|
fetchPolyfill,
|
|
@@ -12401,7 +13864,7 @@ function createClient(options) {
|
|
|
12401
13864
|
delegates: {
|
|
12402
13865
|
createSocket: makeCreateSocketDelegateForAi(
|
|
12403
13866
|
baseUrl,
|
|
12404
|
-
_optionalChain([clientOptions, 'access',
|
|
13867
|
+
_optionalChain([clientOptions, 'access', _321 => _321.polyfills, 'optionalAccess', _322 => _322.WebSocket])
|
|
12405
13868
|
),
|
|
12406
13869
|
authenticate: async () => {
|
|
12407
13870
|
const resp = await authManager.getAuthValue({
|
|
@@ -12472,7 +13935,7 @@ function createClient(options) {
|
|
|
12472
13935
|
createSocket: makeCreateSocketDelegateForRoom(
|
|
12473
13936
|
roomId,
|
|
12474
13937
|
baseUrl,
|
|
12475
|
-
_optionalChain([clientOptions, 'access',
|
|
13938
|
+
_optionalChain([clientOptions, 'access', _323 => _323.polyfills, 'optionalAccess', _324 => _324.WebSocket])
|
|
12476
13939
|
),
|
|
12477
13940
|
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
12478
13941
|
})),
|
|
@@ -12494,7 +13957,7 @@ function createClient(options) {
|
|
|
12494
13957
|
const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
|
|
12495
13958
|
if (shouldConnect) {
|
|
12496
13959
|
if (typeof atob === "undefined") {
|
|
12497
|
-
if (_optionalChain([clientOptions, 'access',
|
|
13960
|
+
if (_optionalChain([clientOptions, 'access', _325 => _325.polyfills, 'optionalAccess', _326 => _326.atob]) === void 0) {
|
|
12498
13961
|
throw new Error(
|
|
12499
13962
|
"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
13963
|
);
|
|
@@ -12506,7 +13969,7 @@ function createClient(options) {
|
|
|
12506
13969
|
return leaseRoom(newRoomDetails);
|
|
12507
13970
|
}
|
|
12508
13971
|
function getRoom(roomId) {
|
|
12509
|
-
const room = _optionalChain([roomsById, 'access',
|
|
13972
|
+
const room = _optionalChain([roomsById, 'access', _327 => _327.get, 'call', _328 => _328(roomId), 'optionalAccess', _329 => _329.room]);
|
|
12510
13973
|
return room ? room : null;
|
|
12511
13974
|
}
|
|
12512
13975
|
function logout() {
|
|
@@ -12522,7 +13985,7 @@ function createClient(options) {
|
|
|
12522
13985
|
const batchedResolveUsers = new Batch(
|
|
12523
13986
|
async (batchedUserIds) => {
|
|
12524
13987
|
const userIds = batchedUserIds.flat();
|
|
12525
|
-
const users = await _optionalChain([resolveUsers, 'optionalCall',
|
|
13988
|
+
const users = await _optionalChain([resolveUsers, 'optionalCall', _330 => _330({ userIds })]);
|
|
12526
13989
|
warnOnceIf(
|
|
12527
13990
|
!resolveUsers,
|
|
12528
13991
|
"Set the resolveUsers option in createClient to specify user info."
|
|
@@ -12539,7 +14002,7 @@ function createClient(options) {
|
|
|
12539
14002
|
const batchedResolveRoomsInfo = new Batch(
|
|
12540
14003
|
async (batchedRoomIds) => {
|
|
12541
14004
|
const roomIds = batchedRoomIds.flat();
|
|
12542
|
-
const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall',
|
|
14005
|
+
const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _331 => _331({ roomIds })]);
|
|
12543
14006
|
warnOnceIf(
|
|
12544
14007
|
!resolveRoomsInfo,
|
|
12545
14008
|
"Set the resolveRoomsInfo option in createClient to specify room info."
|
|
@@ -12556,7 +14019,7 @@ function createClient(options) {
|
|
|
12556
14019
|
const batchedResolveGroupsInfo = new Batch(
|
|
12557
14020
|
async (batchedGroupIds) => {
|
|
12558
14021
|
const groupIds = batchedGroupIds.flat();
|
|
12559
|
-
const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall',
|
|
14022
|
+
const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _332 => _332({ groupIds })]);
|
|
12560
14023
|
warnOnceIf(
|
|
12561
14024
|
!resolveGroupsInfo,
|
|
12562
14025
|
"Set the resolveGroupsInfo option in createClient to specify group info."
|
|
@@ -12615,7 +14078,7 @@ function createClient(options) {
|
|
|
12615
14078
|
}
|
|
12616
14079
|
};
|
|
12617
14080
|
const win = typeof window !== "undefined" ? window : void 0;
|
|
12618
|
-
_optionalChain([win, 'optionalAccess',
|
|
14081
|
+
_optionalChain([win, 'optionalAccess', _333 => _333.addEventListener, 'call', _334 => _334("beforeunload", maybePreventClose)]);
|
|
12619
14082
|
}
|
|
12620
14083
|
async function getNotificationSettings(options2) {
|
|
12621
14084
|
const plainSettings = await httpClient.getNotificationSettings(options2);
|
|
@@ -12743,7 +14206,7 @@ var commentBodyElementsTypes = {
|
|
|
12743
14206
|
mention: "inline"
|
|
12744
14207
|
};
|
|
12745
14208
|
function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
12746
|
-
if (!body || !_optionalChain([body, 'optionalAccess',
|
|
14209
|
+
if (!body || !_optionalChain([body, 'optionalAccess', _335 => _335.content])) {
|
|
12747
14210
|
return;
|
|
12748
14211
|
}
|
|
12749
14212
|
const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
|
|
@@ -12753,13 +14216,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
|
12753
14216
|
for (const block of body.content) {
|
|
12754
14217
|
if (type === "all" || type === "block") {
|
|
12755
14218
|
if (guard(block)) {
|
|
12756
|
-
_optionalChain([visitor, 'optionalCall',
|
|
14219
|
+
_optionalChain([visitor, 'optionalCall', _336 => _336(block)]);
|
|
12757
14220
|
}
|
|
12758
14221
|
}
|
|
12759
14222
|
if (type === "all" || type === "inline") {
|
|
12760
14223
|
for (const inline of block.children) {
|
|
12761
14224
|
if (guard(inline)) {
|
|
12762
|
-
_optionalChain([visitor, 'optionalCall',
|
|
14225
|
+
_optionalChain([visitor, 'optionalCall', _337 => _337(inline)]);
|
|
12763
14226
|
}
|
|
12764
14227
|
}
|
|
12765
14228
|
}
|
|
@@ -12929,7 +14392,7 @@ var stringifyCommentBodyPlainElements = {
|
|
|
12929
14392
|
text: ({ element }) => element.text,
|
|
12930
14393
|
link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
|
|
12931
14394
|
mention: ({ element, user, group }) => {
|
|
12932
|
-
return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
14395
|
+
return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _338 => _338.name]), () => ( _optionalChain([group, 'optionalAccess', _339 => _339.name]))), () => ( element.id))}`;
|
|
12933
14396
|
}
|
|
12934
14397
|
};
|
|
12935
14398
|
var stringifyCommentBodyHtmlElements = {
|
|
@@ -12959,7 +14422,7 @@ var stringifyCommentBodyHtmlElements = {
|
|
|
12959
14422
|
return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
|
|
12960
14423
|
},
|
|
12961
14424
|
mention: ({ element, user, group }) => {
|
|
12962
|
-
return html`<span data-mention>@${_optionalChain([user, 'optionalAccess',
|
|
14425
|
+
return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _340 => _340.name]) ? html`${_optionalChain([user, 'optionalAccess', _341 => _341.name])}` : _optionalChain([group, 'optionalAccess', _342 => _342.name]) ? html`${_optionalChain([group, 'optionalAccess', _343 => _343.name])}` : element.id}</span>`;
|
|
12963
14426
|
}
|
|
12964
14427
|
};
|
|
12965
14428
|
var stringifyCommentBodyMarkdownElements = {
|
|
@@ -12989,20 +14452,20 @@ var stringifyCommentBodyMarkdownElements = {
|
|
|
12989
14452
|
return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
|
|
12990
14453
|
},
|
|
12991
14454
|
mention: ({ element, user, group }) => {
|
|
12992
|
-
return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess',
|
|
14455
|
+
return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _344 => _344.name]), () => ( _optionalChain([group, 'optionalAccess', _345 => _345.name]))), () => ( element.id))}`;
|
|
12993
14456
|
}
|
|
12994
14457
|
};
|
|
12995
14458
|
async function stringifyCommentBody(body, options) {
|
|
12996
|
-
const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
12997
|
-
const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
14459
|
+
const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _346 => _346.format]), () => ( "plain"));
|
|
14460
|
+
const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _347 => _347.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
|
|
12998
14461
|
const elements = {
|
|
12999
14462
|
...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
|
|
13000
|
-
..._optionalChain([options, 'optionalAccess',
|
|
14463
|
+
..._optionalChain([options, 'optionalAccess', _348 => _348.elements])
|
|
13001
14464
|
};
|
|
13002
14465
|
const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
|
|
13003
14466
|
body,
|
|
13004
|
-
_optionalChain([options, 'optionalAccess',
|
|
13005
|
-
_optionalChain([options, 'optionalAccess',
|
|
14467
|
+
_optionalChain([options, 'optionalAccess', _349 => _349.resolveUsers]),
|
|
14468
|
+
_optionalChain([options, 'optionalAccess', _350 => _350.resolveGroupsInfo])
|
|
13006
14469
|
);
|
|
13007
14470
|
const blocks = body.content.flatMap((block, blockIndex) => {
|
|
13008
14471
|
switch (block.type) {
|
|
@@ -13084,6 +14547,12 @@ function toPlainLson(lson) {
|
|
|
13084
14547
|
liveblocksType: "LiveList",
|
|
13085
14548
|
data: [...lson].map((item) => toPlainLson(item))
|
|
13086
14549
|
};
|
|
14550
|
+
} else if (lson instanceof LiveText) {
|
|
14551
|
+
return {
|
|
14552
|
+
liveblocksType: "LiveText",
|
|
14553
|
+
data: lson.toJSON(),
|
|
14554
|
+
version: lson.version
|
|
14555
|
+
};
|
|
13087
14556
|
} else if (lson instanceof LiveFile) {
|
|
13088
14557
|
return {
|
|
13089
14558
|
liveblocksType: "LiveFile",
|
|
@@ -13142,9 +14611,9 @@ function makePoller(callback, intervalMs, options) {
|
|
|
13142
14611
|
const startTime = performance.now();
|
|
13143
14612
|
const doc = typeof document !== "undefined" ? document : void 0;
|
|
13144
14613
|
const win = typeof window !== "undefined" ? window : void 0;
|
|
13145
|
-
const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
14614
|
+
const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _351 => _351.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
|
|
13146
14615
|
const context = {
|
|
13147
|
-
inForeground: _optionalChain([doc, 'optionalAccess',
|
|
14616
|
+
inForeground: _optionalChain([doc, 'optionalAccess', _352 => _352.visibilityState]) !== "hidden",
|
|
13148
14617
|
lastSuccessfulPollAt: startTime,
|
|
13149
14618
|
count: 0,
|
|
13150
14619
|
backoff: 0
|
|
@@ -13225,11 +14694,11 @@ function makePoller(callback, intervalMs, options) {
|
|
|
13225
14694
|
pollNowIfStale();
|
|
13226
14695
|
}
|
|
13227
14696
|
function onVisibilityChange() {
|
|
13228
|
-
setInForeground(_optionalChain([doc, 'optionalAccess',
|
|
14697
|
+
setInForeground(_optionalChain([doc, 'optionalAccess', _353 => _353.visibilityState]) !== "hidden");
|
|
13229
14698
|
}
|
|
13230
|
-
_optionalChain([doc, 'optionalAccess',
|
|
13231
|
-
_optionalChain([win, 'optionalAccess',
|
|
13232
|
-
_optionalChain([win, 'optionalAccess',
|
|
14699
|
+
_optionalChain([doc, 'optionalAccess', _354 => _354.addEventListener, 'call', _355 => _355("visibilitychange", onVisibilityChange)]);
|
|
14700
|
+
_optionalChain([win, 'optionalAccess', _356 => _356.addEventListener, 'call', _357 => _357("online", onVisibilityChange)]);
|
|
14701
|
+
_optionalChain([win, 'optionalAccess', _358 => _358.addEventListener, 'call', _359 => _359("focus", pollNowIfStale)]);
|
|
13233
14702
|
fsm.start();
|
|
13234
14703
|
return {
|
|
13235
14704
|
inc,
|
|
@@ -13378,5 +14847,9 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
|
13378
14847
|
|
|
13379
14848
|
|
|
13380
14849
|
|
|
13381
|
-
|
|
14850
|
+
|
|
14851
|
+
|
|
14852
|
+
|
|
14853
|
+
|
|
14854
|
+
exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.Deque = Deque; exports.DerivedSignal = DerivedSignal; exports.FeedRequestErrorCode = FeedRequestErrorCode; exports.HttpError = HttpError; exports.LiveFile = LiveFile; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveText = LiveText; exports.LiveblocksError = LiveblocksError; exports.MENTION_CHARACTER = MENTION_CHARACTER; exports.MutableSignal = MutableSignal; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.applyLiveTextOperations = applyLiveTextOperations; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.checkBounds = checkBounds; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactNodesToNodeStream = compactNodesToNodeStream; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToGroupData = convertToGroupData; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToSubscriptionData = convertToSubscriptionData; exports.convertToThreadData = convertToThreadData; exports.convertToUserSubscriptionData = convertToUserSubscriptionData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createManagedPool = createManagedPool; exports.createNotificationSettings = createNotificationSettings; exports.createStorageFileId = createStorageFileId; exports.createThreadId = createThreadId; exports.deepLiveify = deepLiveify; exports.defineAiTool = defineAiTool; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.entries = entries; exports.errorIf = errorIf; exports.findLastIndex = findLastIndex; exports.freeze = freeze; exports.generateUrl = generateUrl; exports.getLiveFileId = getLiveFileId; exports.getMentionsFromCommentBody = getMentionsFromCommentBody; exports.getSubscriptionKey = getSubscriptionKey; exports.hasPermissionAccess = hasPermissionAccess; exports.html = html; exports.htmlSafe = htmlSafe; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isFileStorageNode = isFileStorageNode; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isListStorageNode = isListStorageNode; exports.isLiveNode = isLiveNode; exports.isMapStorageNode = isMapStorageNode; exports.isNotificationChannelEnabled = isNotificationChannelEnabled; exports.isNumberOperator = isNumberOperator; exports.isObjectStorageNode = isObjectStorageNode; exports.isPlainObject = isPlainObject; exports.isRegisterStorageNode = isRegisterStorageNode; exports.isRootStorageNode = isRootStorageNode; exports.isStartsWithOperator = isStartsWithOperator; exports.isTextStorageNode = isTextStorageNode; exports.isUrl = isUrl; exports.kInternal = kInternal; exports.keys = keys; exports.makeAbortController = makeAbortController; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.mergeRoomPermissionScopes = mergeRoomPermissionScopes; exports.nanoid = nanoid; exports.nn = nn; exports.nodeStreamToCompactNodes = nodeStreamToCompactNodes; exports.normalizeRoomAccesses = normalizeRoomAccesses; exports.normalizeRoomPermissions = normalizeRoomPermissions; exports.normalizeUpdateRoomAccesses = normalizeUpdateRoomAccesses; exports.objectToQuery = objectToQuery; exports.patchNotificationSettings = patchNotificationSettings; exports.permissionMatrixFromScopes = permissionMatrixFromScopes; exports.raise = raise; exports.resolveMentionsInCommentBody = resolveMentionsInCommentBody; exports.sanitizeUrl = sanitizeUrl; exports.shallow = shallow; exports.shallow2 = shallow2; exports.stableStringify = stableStringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.transformTextOperations = transformTextOperations; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.validatePermissionsSet = validatePermissionsSet; exports.wait = wait; exports.warnOnce = warnOnce; exports.warnOnceIf = warnOnceIf; exports.withTimeout = withTimeout;
|
|
13382
14855
|
//# sourceMappingURL=index.cjs.map
|