@liveblocks/server 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +332 -348
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +237 -261
- package/dist/index.d.ts +237 -261
- package/dist/index.js +312 -328
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -812,11 +812,11 @@ function makeInMemorySnapshot(values) {
|
|
|
812
812
|
|
|
813
813
|
// src/MetadataDB.ts
|
|
814
814
|
function makeMetadataDB(driver) {
|
|
815
|
-
|
|
815
|
+
function get(a1, a2) {
|
|
816
816
|
if (a2 === void 0) {
|
|
817
|
-
return
|
|
817
|
+
return driver.get_meta(a1);
|
|
818
818
|
} else {
|
|
819
|
-
return a1.value(
|
|
819
|
+
return a1.value(driver.get_meta(a2));
|
|
820
820
|
}
|
|
821
821
|
}
|
|
822
822
|
return {
|
|
@@ -1039,6 +1039,7 @@ var InMemoryDriver = class {
|
|
|
1039
1039
|
constructor(options) {
|
|
1040
1040
|
__publicField(this, "_nextActor");
|
|
1041
1041
|
__publicField(this, "_nodes");
|
|
1042
|
+
__publicField(this, "_nodesApi");
|
|
1042
1043
|
__publicField(this, "_metadb");
|
|
1043
1044
|
__publicField(this, "_ydb");
|
|
1044
1045
|
__publicField(this, "_leasedSessions");
|
|
@@ -1058,32 +1059,36 @@ var InMemoryDriver = class {
|
|
|
1058
1059
|
raw_iter_nodes() {
|
|
1059
1060
|
return this._nodes[Symbol.iterator]();
|
|
1060
1061
|
}
|
|
1062
|
+
reinitialize() {
|
|
1063
|
+
this._nodesApi = void 0;
|
|
1064
|
+
}
|
|
1061
1065
|
/** Deletes all nodes and replaces them with the given document. */
|
|
1062
1066
|
DANGEROUSLY_reset_nodes(doc) {
|
|
1067
|
+
this.reinitialize();
|
|
1063
1068
|
this._nodes.clear();
|
|
1064
1069
|
for (const [id, node] of plainLsonToNodeStream(doc)) {
|
|
1065
1070
|
this._nodes.set(id, node);
|
|
1066
1071
|
}
|
|
1067
1072
|
}
|
|
1068
|
-
|
|
1073
|
+
get_meta(key) {
|
|
1069
1074
|
return this._metadb.get(key);
|
|
1070
1075
|
}
|
|
1071
|
-
|
|
1076
|
+
put_meta(key, value) {
|
|
1072
1077
|
this._metadb.set(key, value);
|
|
1073
1078
|
}
|
|
1074
|
-
|
|
1079
|
+
delete_meta(key) {
|
|
1075
1080
|
this._metadb.delete(key);
|
|
1076
1081
|
}
|
|
1077
|
-
|
|
1082
|
+
list_leased_sessions() {
|
|
1078
1083
|
return this._leasedSessions.entries();
|
|
1079
1084
|
}
|
|
1080
|
-
|
|
1085
|
+
get_leased_session(sessionId) {
|
|
1081
1086
|
return this._leasedSessions.get(sessionId);
|
|
1082
1087
|
}
|
|
1083
|
-
|
|
1088
|
+
put_leased_session(session) {
|
|
1084
1089
|
this._leasedSessions.set(session.sessionId, session);
|
|
1085
1090
|
}
|
|
1086
|
-
|
|
1091
|
+
delete_leased_session(sessionId) {
|
|
1087
1092
|
this._leasedSessions.delete(sessionId);
|
|
1088
1093
|
}
|
|
1089
1094
|
takeRowsWritten() {
|
|
@@ -1092,7 +1097,7 @@ var InMemoryDriver = class {
|
|
|
1092
1097
|
// ---------------------------------------------------------------------------
|
|
1093
1098
|
// Feed APIs
|
|
1094
1099
|
// ---------------------------------------------------------------------------
|
|
1095
|
-
|
|
1100
|
+
list_feeds(options) {
|
|
1096
1101
|
const limit = Math.min(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _37 => _37.limit]), () => ( 20)), 100);
|
|
1097
1102
|
const since = _optionalChain([options, 'optionalAccess', _38 => _38.since]);
|
|
1098
1103
|
const cursor = _optionalChain([options, 'optionalAccess', _39 => _39.cursor]);
|
|
@@ -1148,14 +1153,14 @@ var InMemoryDriver = class {
|
|
|
1148
1153
|
}
|
|
1149
1154
|
return { feeds, nextCursor };
|
|
1150
1155
|
}
|
|
1151
|
-
|
|
1156
|
+
get_feed(feedId) {
|
|
1152
1157
|
const feed = this._feeds.get(feedId);
|
|
1153
1158
|
if (feed === void 0) {
|
|
1154
1159
|
return void 0;
|
|
1155
1160
|
}
|
|
1156
1161
|
return feed;
|
|
1157
1162
|
}
|
|
1158
|
-
|
|
1163
|
+
create_feed(feed) {
|
|
1159
1164
|
if (this._feeds.has(feed.feedId)) {
|
|
1160
1165
|
throw new Error(`Feed ${feed.feedId} already exists`);
|
|
1161
1166
|
}
|
|
@@ -1166,7 +1171,7 @@ var InMemoryDriver = class {
|
|
|
1166
1171
|
updatedAt: feed.updatedAt
|
|
1167
1172
|
});
|
|
1168
1173
|
}
|
|
1169
|
-
|
|
1174
|
+
update_feed_metadata(feedId, metadata) {
|
|
1170
1175
|
const existing = this._feeds.get(feedId);
|
|
1171
1176
|
if (existing === void 0) {
|
|
1172
1177
|
throw new Error(`Feed ${feedId} not found`);
|
|
@@ -1176,7 +1181,7 @@ var InMemoryDriver = class {
|
|
|
1176
1181
|
metadata
|
|
1177
1182
|
});
|
|
1178
1183
|
}
|
|
1179
|
-
|
|
1184
|
+
delete_feed(feedId) {
|
|
1180
1185
|
const messageKeys = [];
|
|
1181
1186
|
for (const [key] of this._feedMessages.entries()) {
|
|
1182
1187
|
if (key.startsWith(`${feedId}:`)) {
|
|
@@ -1188,7 +1193,7 @@ var InMemoryDriver = class {
|
|
|
1188
1193
|
}
|
|
1189
1194
|
this._feeds.delete(feedId);
|
|
1190
1195
|
}
|
|
1191
|
-
|
|
1196
|
+
list_feed_messages(feedId, options) {
|
|
1192
1197
|
const limit = Math.min(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _41 => _41.limit]), () => ( 20)), 100);
|
|
1193
1198
|
const since = _optionalChain([options, 'optionalAccess', _42 => _42.since]);
|
|
1194
1199
|
const cursor = _optionalChain([options, 'optionalAccess', _43 => _43.cursor]);
|
|
@@ -1235,14 +1240,14 @@ var InMemoryDriver = class {
|
|
|
1235
1240
|
}
|
|
1236
1241
|
return { messages, nextCursor };
|
|
1237
1242
|
}
|
|
1238
|
-
|
|
1243
|
+
add_feed_message(feedId, message) {
|
|
1239
1244
|
const feed = this._feeds.get(feedId);
|
|
1240
1245
|
if (feed === void 0) {
|
|
1241
1246
|
throw new Error(`Feed ${feedId} not found`);
|
|
1242
1247
|
}
|
|
1243
1248
|
this._feedMessages.set(`${feedId}:${message.id}`, message);
|
|
1244
1249
|
}
|
|
1245
|
-
|
|
1250
|
+
update_feed_message(feedId, messageId, data, timestamp) {
|
|
1246
1251
|
const key = `${feedId}:${messageId}`;
|
|
1247
1252
|
const message = this._feedMessages.get(key);
|
|
1248
1253
|
if (message === void 0) {
|
|
@@ -1260,33 +1265,85 @@ var InMemoryDriver = class {
|
|
|
1260
1265
|
this._feedMessages.set(key, updatedMessage);
|
|
1261
1266
|
return updatedMessage;
|
|
1262
1267
|
}
|
|
1263
|
-
|
|
1268
|
+
delete_feed_message(feedId, messageId) {
|
|
1264
1269
|
this._feedMessages.delete(`${feedId}:${messageId}`);
|
|
1265
1270
|
}
|
|
1266
1271
|
next_actor() {
|
|
1267
1272
|
return ++this._nextActor;
|
|
1268
1273
|
}
|
|
1269
|
-
|
|
1274
|
+
iter_y_updates(docId) {
|
|
1270
1275
|
const prefix = `${docId}@|@`;
|
|
1271
1276
|
return _itertools.imap.call(void 0,
|
|
1272
1277
|
_itertools.ifilter.call(void 0, this._ydb.entries(), ([k]) => k.startsWith(prefix)),
|
|
1273
1278
|
([k, v]) => [k.slice(prefix.length), v]
|
|
1274
1279
|
);
|
|
1275
1280
|
}
|
|
1276
|
-
|
|
1281
|
+
write_y_updates(docId, key, data) {
|
|
1277
1282
|
this._ydb.set(`${docId}@|@${key}`, data);
|
|
1278
1283
|
}
|
|
1279
|
-
|
|
1284
|
+
delete_y_updates(docId, keys) {
|
|
1280
1285
|
for (const key of keys) {
|
|
1281
1286
|
this._ydb.delete(`${docId}@|@${key}`);
|
|
1282
1287
|
}
|
|
1283
1288
|
}
|
|
1284
1289
|
/** @private Only use this in unit tests, never in production. */
|
|
1285
|
-
|
|
1290
|
+
DANGEROUSLY_wipe_all_y_updates() {
|
|
1286
1291
|
this._ydb.clear();
|
|
1287
1292
|
}
|
|
1288
|
-
//
|
|
1289
|
-
|
|
1293
|
+
// ---------------------------------------------------------------------------
|
|
1294
|
+
// Node APIs
|
|
1295
|
+
// ---------------------------------------------------------------------------
|
|
1296
|
+
/**
|
|
1297
|
+
* The lazily-built node API. Building it ensures the root node exists and
|
|
1298
|
+
* constructs the reverse-lookup index. Invalidated by
|
|
1299
|
+
* DANGEROUSLY_reset_nodes(), after which the next access rebuilds it.
|
|
1300
|
+
*/
|
|
1301
|
+
get loadedApi() {
|
|
1302
|
+
return _nullishCoalesce(this._nodesApi, () => ( (this._nodesApi = this._loadNodesApi())));
|
|
1303
|
+
}
|
|
1304
|
+
get_node(id) {
|
|
1305
|
+
return this.loadedApi.get_node(id);
|
|
1306
|
+
}
|
|
1307
|
+
iter_nodes() {
|
|
1308
|
+
return this.loadedApi.iter_nodes();
|
|
1309
|
+
}
|
|
1310
|
+
iter_nodes_optimized() {
|
|
1311
|
+
return this.loadedApi.iter_nodes_optimized();
|
|
1312
|
+
}
|
|
1313
|
+
has_node(id) {
|
|
1314
|
+
return this.loadedApi.has_node(id);
|
|
1315
|
+
}
|
|
1316
|
+
get_child_at(parentId, parentKey) {
|
|
1317
|
+
return this.loadedApi.get_child_at(parentId, parentKey);
|
|
1318
|
+
}
|
|
1319
|
+
has_child_at(parentId, parentKey) {
|
|
1320
|
+
return this.loadedApi.has_child_at(parentId, parentKey);
|
|
1321
|
+
}
|
|
1322
|
+
get_next_sibling(parentId, pos) {
|
|
1323
|
+
return this.loadedApi.get_next_sibling(parentId, pos);
|
|
1324
|
+
}
|
|
1325
|
+
get_last_sibling(parentId) {
|
|
1326
|
+
return this.loadedApi.get_last_sibling(parentId);
|
|
1327
|
+
}
|
|
1328
|
+
set_child(id, node, allowOverwrite) {
|
|
1329
|
+
this.loadedApi.set_child(id, node, allowOverwrite);
|
|
1330
|
+
}
|
|
1331
|
+
move_sibling(id, newPos) {
|
|
1332
|
+
this.loadedApi.move_sibling(id, newPos);
|
|
1333
|
+
}
|
|
1334
|
+
delete_node(id) {
|
|
1335
|
+
this.loadedApi.delete_node(id);
|
|
1336
|
+
}
|
|
1337
|
+
delete_child_key(id, key) {
|
|
1338
|
+
this.loadedApi.delete_child_key(id, key);
|
|
1339
|
+
}
|
|
1340
|
+
set_object_data(id, data, allowOverwrite) {
|
|
1341
|
+
this.loadedApi.set_object_data(id, data, allowOverwrite);
|
|
1342
|
+
}
|
|
1343
|
+
get_snapshot(lowMemory) {
|
|
1344
|
+
return this.loadedApi.get_snapshot(lowMemory);
|
|
1345
|
+
}
|
|
1346
|
+
_loadNodesApi() {
|
|
1290
1347
|
const nodes = this._nodes;
|
|
1291
1348
|
if (!nodes.has("root")) {
|
|
1292
1349
|
nodes.set("root", { type: _core.CrdtType.OBJECT, data: {} });
|
|
@@ -1312,7 +1369,7 @@ var InMemoryDriver = class {
|
|
|
1312
1369
|
}
|
|
1313
1370
|
return lastPos;
|
|
1314
1371
|
}
|
|
1315
|
-
|
|
1372
|
+
function set_child(id, node, allowOverwrite = false) {
|
|
1316
1373
|
const parentNode = nodes.get(node.parentId);
|
|
1317
1374
|
if (parentNode === void 0) {
|
|
1318
1375
|
throw new Error(`No such parent ${quote(node.parentId)}`);
|
|
@@ -1335,7 +1392,7 @@ var InMemoryDriver = class {
|
|
|
1335
1392
|
}
|
|
1336
1393
|
nodes.set(id, node);
|
|
1337
1394
|
}
|
|
1338
|
-
|
|
1395
|
+
function move_sibling(id, newPos) {
|
|
1339
1396
|
const node = nodes.get(id);
|
|
1340
1397
|
if (_optionalChain([node, 'optionalAccess', _44 => _44.parentId]) === void 0) {
|
|
1341
1398
|
return;
|
|
@@ -1347,7 +1404,7 @@ var InMemoryDriver = class {
|
|
|
1347
1404
|
nodes.set(id, newNode);
|
|
1348
1405
|
revNodes.set(node.parentId, newPos, id);
|
|
1349
1406
|
}
|
|
1350
|
-
|
|
1407
|
+
function set_object_data(id, data, allowOverwrite = false) {
|
|
1351
1408
|
const node = nodes.get(id);
|
|
1352
1409
|
if (_optionalChain([node, 'optionalAccess', _45 => _45.type]) !== _core.CrdtType.OBJECT) {
|
|
1353
1410
|
return;
|
|
@@ -1540,45 +1597,26 @@ function nodeFromCreateChildOp(op2) {
|
|
|
1540
1597
|
}
|
|
1541
1598
|
}
|
|
1542
1599
|
var Storage = class {
|
|
1543
|
-
constructor(
|
|
1600
|
+
constructor(driver) {
|
|
1544
1601
|
// The actual underlying storage API (could be backed by in-memory store,
|
|
1545
|
-
// SQLite,
|
|
1546
|
-
__publicField(this, "
|
|
1547
|
-
|
|
1548
|
-
this.coreDriver = coreDriver;
|
|
1602
|
+
// SQLite, Postgres, etc.)
|
|
1603
|
+
__publicField(this, "driver");
|
|
1604
|
+
this.driver = driver;
|
|
1549
1605
|
}
|
|
1550
1606
|
// -------------------------------------------------------------------------
|
|
1551
1607
|
// Public API (for Storage)
|
|
1552
1608
|
// -------------------------------------------------------------------------
|
|
1553
|
-
get loadedDriver() {
|
|
1554
|
-
if (this._loadedDriver === void 0) {
|
|
1555
|
-
throw new Error("Cannot access tree before it's been loaded");
|
|
1556
|
-
}
|
|
1557
|
-
return this._loadedDriver;
|
|
1558
|
-
}
|
|
1559
1609
|
// REFACTOR NOTE: Eventually raw_iter_nodes has to be removed here
|
|
1560
1610
|
raw_iter_nodes() {
|
|
1561
|
-
return this.
|
|
1562
|
-
}
|
|
1563
|
-
/**
|
|
1564
|
-
* Load the room data from object storage into memory. Persisted room
|
|
1565
|
-
* data consists of the main node map, which represents the Liveblocks
|
|
1566
|
-
* Storage tree, and special keys where we store usage metrics, or room
|
|
1567
|
-
* metadata.
|
|
1568
|
-
*/
|
|
1569
|
-
async load(logger) {
|
|
1570
|
-
this._loadedDriver = await this.coreDriver.load_nodes_api(logger);
|
|
1571
|
-
}
|
|
1572
|
-
unload() {
|
|
1573
|
-
this._loadedDriver = void 0;
|
|
1611
|
+
return this.driver.raw_iter_nodes();
|
|
1574
1612
|
}
|
|
1575
1613
|
/**
|
|
1576
1614
|
* Applies a batch of Ops.
|
|
1577
1615
|
*/
|
|
1578
|
-
|
|
1616
|
+
applyOps(ops) {
|
|
1579
1617
|
const results = [];
|
|
1580
1618
|
for (const op2 of ops) {
|
|
1581
|
-
results.push(
|
|
1619
|
+
results.push(this.applyOp(op2));
|
|
1582
1620
|
}
|
|
1583
1621
|
return results;
|
|
1584
1622
|
}
|
|
@@ -1588,21 +1626,21 @@ var Storage = class {
|
|
|
1588
1626
|
/**
|
|
1589
1627
|
* Applies a single Op.
|
|
1590
1628
|
*/
|
|
1591
|
-
|
|
1629
|
+
applyOp(op2) {
|
|
1592
1630
|
switch (op2.type) {
|
|
1593
1631
|
case _core.OpCode.CREATE_LIST:
|
|
1594
1632
|
case _core.OpCode.CREATE_MAP:
|
|
1595
1633
|
case _core.OpCode.CREATE_REGISTER:
|
|
1596
1634
|
case _core.OpCode.CREATE_OBJECT:
|
|
1597
|
-
return
|
|
1635
|
+
return this.applyCreateOp(op2);
|
|
1598
1636
|
case _core.OpCode.UPDATE_OBJECT:
|
|
1599
|
-
return
|
|
1637
|
+
return this.applyUpdateObjectOp(op2);
|
|
1600
1638
|
case _core.OpCode.SET_PARENT_KEY:
|
|
1601
|
-
return
|
|
1639
|
+
return this.applySetParentKeyOp(op2);
|
|
1602
1640
|
case _core.OpCode.DELETE_OBJECT_KEY:
|
|
1603
|
-
return
|
|
1641
|
+
return this.applyDeleteObjectKeyOp(op2);
|
|
1604
1642
|
case _core.OpCode.DELETE_CRDT:
|
|
1605
|
-
return
|
|
1643
|
+
return this.applyDeleteCrdtOp(op2);
|
|
1606
1644
|
// istanbul ignore next
|
|
1607
1645
|
default:
|
|
1608
1646
|
if (process.env.NODE_ENV === "production") {
|
|
@@ -1612,12 +1650,12 @@ var Storage = class {
|
|
|
1612
1650
|
}
|
|
1613
1651
|
}
|
|
1614
1652
|
}
|
|
1615
|
-
|
|
1616
|
-
if (this.
|
|
1653
|
+
applyCreateOp(op2) {
|
|
1654
|
+
if (this.driver.has_node(op2.id)) {
|
|
1617
1655
|
return ignore(op2);
|
|
1618
1656
|
}
|
|
1619
1657
|
const node = nodeFromCreateChildOp(op2);
|
|
1620
|
-
const parent = this.
|
|
1658
|
+
const parent = this.driver.get_node(node.parentId);
|
|
1621
1659
|
if (parent === void 0) {
|
|
1622
1660
|
return ignore(op2);
|
|
1623
1661
|
}
|
|
@@ -1628,7 +1666,7 @@ var Storage = class {
|
|
|
1628
1666
|
}
|
|
1629
1667
|
// fall through
|
|
1630
1668
|
case _core.CrdtType.MAP:
|
|
1631
|
-
|
|
1669
|
+
this.driver.set_child(op2.id, node, true);
|
|
1632
1670
|
return accept(op2);
|
|
1633
1671
|
case _core.CrdtType.LIST:
|
|
1634
1672
|
return this.createChildAsListItem(op2, node);
|
|
@@ -1639,23 +1677,19 @@ var Storage = class {
|
|
|
1639
1677
|
return _core.assertNever.call(void 0, parent, "Unhandled CRDT type");
|
|
1640
1678
|
}
|
|
1641
1679
|
}
|
|
1642
|
-
|
|
1680
|
+
createChildAsListItem(op2, node) {
|
|
1643
1681
|
const intent2 = _nullishCoalesce(op2.intent, () => ( "insert"));
|
|
1644
1682
|
if (intent2 === "insert") {
|
|
1645
|
-
return this.acceptAndFix(
|
|
1646
|
-
op2,
|
|
1647
|
-
node,
|
|
1648
|
-
await this.insertIntoList(op2.id, node)
|
|
1649
|
-
);
|
|
1683
|
+
return this.acceptAndFix(op2, node, this.insertIntoList(op2.id, node));
|
|
1650
1684
|
} else if (intent2 === "push") {
|
|
1651
|
-
return this.acceptAndFix(op2, node,
|
|
1685
|
+
return this.acceptAndFix(op2, node, this.appendToList(op2.id, node));
|
|
1652
1686
|
} else if (intent2 === "set") {
|
|
1653
1687
|
let fix;
|
|
1654
|
-
const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _47 => _47.
|
|
1688
|
+
const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _47 => _47.driver, 'access', _48 => _48.get_node, 'call', _49 => _49(op2.deletedId), 'optionalAccess', _50 => _50.parentId]) === node.parentId ? op2.deletedId : void 0;
|
|
1655
1689
|
if (deletedId !== void 0) {
|
|
1656
|
-
|
|
1690
|
+
this.driver.delete_node(deletedId);
|
|
1657
1691
|
}
|
|
1658
|
-
const prevItemId = this.
|
|
1692
|
+
const prevItemId = this.driver.get_child_at(
|
|
1659
1693
|
node.parentId,
|
|
1660
1694
|
node.parentKey
|
|
1661
1695
|
);
|
|
@@ -1665,7 +1699,7 @@ var Storage = class {
|
|
|
1665
1699
|
id: prevItemId
|
|
1666
1700
|
};
|
|
1667
1701
|
}
|
|
1668
|
-
|
|
1702
|
+
this.driver.set_child(op2.id, node, true);
|
|
1669
1703
|
return accept(op2, fix);
|
|
1670
1704
|
} else {
|
|
1671
1705
|
return _core.assertNever.call(void 0, intent2, "Invalid intent");
|
|
@@ -1685,20 +1719,20 @@ var Storage = class {
|
|
|
1685
1719
|
}
|
|
1686
1720
|
return accept(op2);
|
|
1687
1721
|
}
|
|
1688
|
-
|
|
1689
|
-
|
|
1722
|
+
applyDeleteObjectKeyOp(op2) {
|
|
1723
|
+
this.driver.delete_child_key(op2.id, op2.key);
|
|
1690
1724
|
return accept(op2);
|
|
1691
1725
|
}
|
|
1692
|
-
|
|
1693
|
-
|
|
1726
|
+
applyUpdateObjectOp(op2) {
|
|
1727
|
+
this.driver.set_object_data(op2.id, op2.data, true);
|
|
1694
1728
|
return accept(op2);
|
|
1695
1729
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1730
|
+
applyDeleteCrdtOp(op2) {
|
|
1731
|
+
this.driver.delete_node(op2.id);
|
|
1698
1732
|
return accept(op2);
|
|
1699
1733
|
}
|
|
1700
|
-
|
|
1701
|
-
const newPosition =
|
|
1734
|
+
applySetParentKeyOp(op2) {
|
|
1735
|
+
const newPosition = this.moveToPosInList(op2.id, op2.parentKey);
|
|
1702
1736
|
if (newPosition === void 0) {
|
|
1703
1737
|
return ignore(op2);
|
|
1704
1738
|
}
|
|
@@ -1722,12 +1756,12 @@ var Storage = class {
|
|
|
1722
1756
|
*
|
|
1723
1757
|
* Returns the key that was used for the insertion.
|
|
1724
1758
|
*/
|
|
1725
|
-
|
|
1759
|
+
insertIntoList(id, node) {
|
|
1726
1760
|
const key = this.findFreeListPosition(node.parentId, _core.asPos.call(void 0, node.parentKey));
|
|
1727
1761
|
if (key !== node.parentKey) {
|
|
1728
1762
|
node = { ...node, parentKey: key };
|
|
1729
1763
|
}
|
|
1730
|
-
|
|
1764
|
+
this.driver.set_child(id, node);
|
|
1731
1765
|
return node.parentKey;
|
|
1732
1766
|
}
|
|
1733
1767
|
/**
|
|
@@ -1740,11 +1774,11 @@ var Storage = class {
|
|
|
1740
1774
|
*
|
|
1741
1775
|
* Returns the final key that was used for the insertion.
|
|
1742
1776
|
*/
|
|
1743
|
-
|
|
1744
|
-
const lastPos = this.
|
|
1777
|
+
appendToList(id, node) {
|
|
1778
|
+
const lastPos = this.driver.get_last_sibling(node.parentId);
|
|
1745
1779
|
const preferredPos = _core.asPos.call(void 0, node.parentKey);
|
|
1746
1780
|
const finalKey = lastPos === void 0 || preferredPos > lastPos ? preferredPos : _core.makePosition.call(void 0, lastPos);
|
|
1747
|
-
|
|
1781
|
+
this.driver.set_child(
|
|
1748
1782
|
id,
|
|
1749
1783
|
finalKey !== node.parentKey ? { ...node, parentKey: finalKey } : node
|
|
1750
1784
|
);
|
|
@@ -1762,12 +1796,12 @@ var Storage = class {
|
|
|
1762
1796
|
* Will return `undefined` if this action could not be interpreted. Will be
|
|
1763
1797
|
* a no-op for non-list items.
|
|
1764
1798
|
*/
|
|
1765
|
-
|
|
1766
|
-
const node = this.
|
|
1799
|
+
moveToPosInList(id, targetKey) {
|
|
1800
|
+
const node = this.driver.get_node(id);
|
|
1767
1801
|
if (_optionalChain([node, 'optionalAccess', _51 => _51.parentId]) === void 0) {
|
|
1768
1802
|
return;
|
|
1769
1803
|
}
|
|
1770
|
-
if (_optionalChain([this, 'access', _52 => _52.
|
|
1804
|
+
if (_optionalChain([this, 'access', _52 => _52.driver, 'access', _53 => _53.get_node, 'call', _54 => _54(node.parentId), 'optionalAccess', _55 => _55.type]) !== _core.CrdtType.LIST) {
|
|
1771
1805
|
return;
|
|
1772
1806
|
}
|
|
1773
1807
|
if (node.parentKey === targetKey) {
|
|
@@ -1775,7 +1809,7 @@ var Storage = class {
|
|
|
1775
1809
|
}
|
|
1776
1810
|
const key = this.findFreeListPosition(node.parentId, _core.asPos.call(void 0, targetKey));
|
|
1777
1811
|
if (key !== node.parentKey) {
|
|
1778
|
-
|
|
1812
|
+
this.driver.move_sibling(id, key);
|
|
1779
1813
|
}
|
|
1780
1814
|
return key;
|
|
1781
1815
|
}
|
|
@@ -1787,11 +1821,11 @@ var Storage = class {
|
|
|
1787
1821
|
* to use as parentKey.
|
|
1788
1822
|
*/
|
|
1789
1823
|
findFreeListPosition(parentId, parentPos) {
|
|
1790
|
-
if (!this.
|
|
1824
|
+
if (!this.driver.has_child_at(parentId, parentPos)) {
|
|
1791
1825
|
return parentPos;
|
|
1792
1826
|
}
|
|
1793
1827
|
const currPos = parentPos;
|
|
1794
|
-
const nextPos = this.
|
|
1828
|
+
const nextPos = this.driver.get_next_sibling(parentId, currPos);
|
|
1795
1829
|
if (nextPos !== void 0) {
|
|
1796
1830
|
return _core.makePosition.call(void 0, currPos, nextPos);
|
|
1797
1831
|
} else {
|
|
@@ -1801,6 +1835,7 @@ var Storage = class {
|
|
|
1801
1835
|
};
|
|
1802
1836
|
|
|
1803
1837
|
// src/YjsStorage.ts
|
|
1838
|
+
var _crypto = require('crypto');
|
|
1804
1839
|
var _jsbase64 = require('js-base64');
|
|
1805
1840
|
|
|
1806
1841
|
var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
|
|
@@ -1810,30 +1845,33 @@ var YjsStorage = class {
|
|
|
1810
1845
|
constructor(driver, updateCountThreshold = UPDATE_COUNT_THRESHOLD) {
|
|
1811
1846
|
__publicField(this, "driver");
|
|
1812
1847
|
__publicField(this, "updateCountThreshold");
|
|
1813
|
-
|
|
1814
|
-
|
|
1848
|
+
/**
|
|
1849
|
+
* The root Y.Doc instance, which may not have been hydrated from storage
|
|
1850
|
+
* yet. Use getRootDoc() instead, which lazily hydrates it on first access —
|
|
1851
|
+
* only touch this field directly when the unhydrated instance is fine
|
|
1852
|
+
* (e.g. identity checks, subdoc traversal).
|
|
1853
|
+
*/
|
|
1854
|
+
__publicField(this, "rawRootDoc", new Y.Doc());
|
|
1815
1855
|
__publicField(this, "lastSnapshotById", /* @__PURE__ */ new Map());
|
|
1816
|
-
__publicField(this, "
|
|
1856
|
+
__publicField(this, "docsById", /* @__PURE__ */ new Map());
|
|
1817
1857
|
__publicField(this, "storedKeysById", /* @__PURE__ */ new Map());
|
|
1818
1858
|
// compact the updates into a single update and write it to the durable storage
|
|
1819
|
-
__publicField(this, "_compactYJSUpdates",
|
|
1859
|
+
__publicField(this, "_compactYJSUpdates", (doc, docId, storedKeys) => {
|
|
1820
1860
|
const compactedUpdate = Y.encodeStateAsUpdate(doc);
|
|
1821
1861
|
const newKey = _nanoid.nanoid.call(void 0, );
|
|
1822
|
-
|
|
1823
|
-
|
|
1862
|
+
this.driver.write_y_updates(docId, newKey, compactedUpdate);
|
|
1863
|
+
this.driver.delete_y_updates(docId, storedKeys);
|
|
1824
1864
|
this.storedKeysById.set(docId, [newKey]);
|
|
1825
1865
|
});
|
|
1826
|
-
__publicField(this, "_loadYDocFromDurableStorage",
|
|
1827
|
-
const docUpdates = Object.fromEntries(
|
|
1828
|
-
await this.driver.iter_y_updates(docId)
|
|
1829
|
-
);
|
|
1866
|
+
__publicField(this, "_loadYDocFromDurableStorage", (doc, docId) => {
|
|
1867
|
+
const docUpdates = Object.fromEntries(this.driver.iter_y_updates(docId));
|
|
1830
1868
|
const updates = Object.values(docUpdates);
|
|
1831
1869
|
const beforeSize = updates.reduce((acc, update) => acc + update.length, 0);
|
|
1832
1870
|
const newupdate = Y.mergeUpdates(updates);
|
|
1833
1871
|
const storedKeys = Object.keys(docUpdates);
|
|
1834
1872
|
Y.applyUpdate(doc, newupdate);
|
|
1835
1873
|
if (this.shouldCompactByKeyCount(storedKeys) || this.shouldCompactBySize(beforeSize, newupdate.length)) {
|
|
1836
|
-
|
|
1874
|
+
this._compactYJSUpdates(doc, docId, storedKeys);
|
|
1837
1875
|
} else {
|
|
1838
1876
|
this.storedKeysById.set(docId, storedKeys);
|
|
1839
1877
|
}
|
|
@@ -1842,7 +1880,7 @@ var YjsStorage = class {
|
|
|
1842
1880
|
});
|
|
1843
1881
|
this.driver = driver;
|
|
1844
1882
|
this.updateCountThreshold = updateCountThreshold;
|
|
1845
|
-
this.
|
|
1883
|
+
this.rawRootDoc.on("subdocs", ({ removed }) => {
|
|
1846
1884
|
removed.forEach((subdoc) => {
|
|
1847
1885
|
subdoc.destroy();
|
|
1848
1886
|
});
|
|
@@ -1851,9 +1889,27 @@ var YjsStorage = class {
|
|
|
1851
1889
|
// ------------------------------------------------------------------------------------
|
|
1852
1890
|
// Public API
|
|
1853
1891
|
// ------------------------------------------------------------------------------------
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1892
|
+
getYDoc(logger, docId) {
|
|
1893
|
+
if (docId !== ROOT_YDOC_ID) {
|
|
1894
|
+
this.getRootDoc(logger);
|
|
1895
|
+
}
|
|
1896
|
+
let loaded = this.docsById.get(docId);
|
|
1897
|
+
let doc = docId === ROOT_YDOC_ID ? this.rawRootDoc : this.findYSubdocByGuid(docId);
|
|
1898
|
+
if (!doc) {
|
|
1899
|
+
doc = new Y.Doc();
|
|
1900
|
+
}
|
|
1901
|
+
if (loaded === void 0) {
|
|
1902
|
+
loaded = this._loadYDocFromDurableStorage(doc, docId);
|
|
1903
|
+
this.docsById.set(docId, loaded);
|
|
1904
|
+
}
|
|
1905
|
+
return loaded;
|
|
1906
|
+
}
|
|
1907
|
+
/**
|
|
1908
|
+
* Returns the root Y.Doc, lazily loading it from storage first if it
|
|
1909
|
+
* hasn't been loaded yet during this instance's lifetime.
|
|
1910
|
+
*/
|
|
1911
|
+
getRootDoc(logger) {
|
|
1912
|
+
return this.getYDoc(logger, ROOT_YDOC_ID);
|
|
1857
1913
|
}
|
|
1858
1914
|
/**
|
|
1859
1915
|
* If passed a state vector, an update with diff will be returned, if not the entire doc is returned.
|
|
@@ -1861,18 +1917,13 @@ var YjsStorage = class {
|
|
|
1861
1917
|
* @param stateVector a base64 encoded target state vector created by running Y.encodeStateVector(Doc) on the client
|
|
1862
1918
|
* @returns a base64 encoded array of YJS updates
|
|
1863
1919
|
*/
|
|
1864
|
-
|
|
1865
|
-
const update =
|
|
1866
|
-
logger,
|
|
1867
|
-
stateVector,
|
|
1868
|
-
guid,
|
|
1869
|
-
isV2
|
|
1870
|
-
);
|
|
1920
|
+
getYDocUpdate(logger, stateVector = "", guid, isV2 = false) {
|
|
1921
|
+
const update = this.getYDocUpdateBinary(logger, stateVector, guid, isV2);
|
|
1871
1922
|
if (!update) return null;
|
|
1872
1923
|
return _jsbase64.Base64.fromUint8Array(update);
|
|
1873
1924
|
}
|
|
1874
|
-
|
|
1875
|
-
const doc = guid !== void 0 ?
|
|
1925
|
+
getYDocUpdateBinary(logger, stateVector = "", guid, isV2 = false) {
|
|
1926
|
+
const doc = guid !== void 0 ? this.getYSubdoc(logger, guid) : this.getRootDoc(logger);
|
|
1876
1927
|
if (!doc) {
|
|
1877
1928
|
return null;
|
|
1878
1929
|
}
|
|
@@ -1889,15 +1940,15 @@ var YjsStorage = class {
|
|
|
1889
1940
|
}
|
|
1890
1941
|
return Y.encodeStateAsUpdate(doc, encodedTargetVector);
|
|
1891
1942
|
}
|
|
1892
|
-
|
|
1893
|
-
const doc = guid !== void 0 ?
|
|
1943
|
+
getYStateVector(logger, guid) {
|
|
1944
|
+
const doc = guid !== void 0 ? this.getYSubdoc(logger, guid) : this.getRootDoc(logger);
|
|
1894
1945
|
if (!doc) {
|
|
1895
1946
|
return null;
|
|
1896
1947
|
}
|
|
1897
1948
|
return _jsbase64.Base64.fromUint8Array(Y.encodeStateVector(doc));
|
|
1898
1949
|
}
|
|
1899
|
-
|
|
1900
|
-
const doc = options.guid !== void 0 ?
|
|
1950
|
+
getSnapshotHash(logger, options) {
|
|
1951
|
+
const doc = options.guid !== void 0 ? this.getYSubdoc(logger, options.guid) : this.getRootDoc(logger);
|
|
1901
1952
|
if (!doc) {
|
|
1902
1953
|
return null;
|
|
1903
1954
|
}
|
|
@@ -1910,8 +1961,8 @@ var YjsStorage = class {
|
|
|
1910
1961
|
* isUpdated: true if the update had an effect on the YDoc
|
|
1911
1962
|
* snapshotHash: the hash of the new snapshot
|
|
1912
1963
|
*/
|
|
1913
|
-
|
|
1914
|
-
const doc = guid !== void 0 ?
|
|
1964
|
+
addYDocUpdate(logger, update, guid, isV2) {
|
|
1965
|
+
const doc = guid !== void 0 ? this.getYSubdoc(logger, guid) : this.getRootDoc(logger);
|
|
1915
1966
|
if (!doc) {
|
|
1916
1967
|
throw new Error(`YDoc with guid ${guid} not found`);
|
|
1917
1968
|
}
|
|
@@ -1923,11 +1974,11 @@ var YjsStorage = class {
|
|
|
1923
1974
|
const afterSnapshot = this._putLastSnapshot(doc);
|
|
1924
1975
|
const updated = !Y.equalSnapshots(beforeSnapshot, afterSnapshot);
|
|
1925
1976
|
if (updated) {
|
|
1926
|
-
|
|
1977
|
+
this.handleYDocUpdate(doc, updateAsU8, isV2);
|
|
1927
1978
|
}
|
|
1928
1979
|
return {
|
|
1929
1980
|
isUpdated: updated,
|
|
1930
|
-
snapshotHash:
|
|
1981
|
+
snapshotHash: this.calculateSnapshotHash(afterSnapshot, { isV2 })
|
|
1931
1982
|
};
|
|
1932
1983
|
} catch (e) {
|
|
1933
1984
|
logger.warn(`Ignored bad YDoc update: ${String(e)}`);
|
|
@@ -1936,32 +1987,12 @@ var YjsStorage = class {
|
|
|
1936
1987
|
);
|
|
1937
1988
|
}
|
|
1938
1989
|
}
|
|
1939
|
-
loadDocByIdIfNotAlreadyLoaded(logger, docId) {
|
|
1940
|
-
let loaded$ = this.initPromisesById.get(docId);
|
|
1941
|
-
let doc = docId === ROOT_YDOC_ID ? this.doc : this.findYSubdocByGuid(docId);
|
|
1942
|
-
if (!doc) {
|
|
1943
|
-
doc = new Y.Doc();
|
|
1944
|
-
}
|
|
1945
|
-
if (loaded$ === void 0) {
|
|
1946
|
-
loaded$ = this._loadYDocFromDurableStorage(logger, doc, docId);
|
|
1947
|
-
this.initPromisesById.set(docId, loaded$);
|
|
1948
|
-
}
|
|
1949
|
-
return loaded$;
|
|
1950
|
-
}
|
|
1951
|
-
async load(logger) {
|
|
1952
|
-
await this.loadDocByIdIfNotAlreadyLoaded(logger, ROOT_YDOC_ID);
|
|
1953
|
-
}
|
|
1954
|
-
/**
|
|
1955
|
-
* Unloads the Yjs documents from memory.
|
|
1956
|
-
*/
|
|
1957
|
-
unload() {
|
|
1958
|
-
}
|
|
1959
1990
|
// ------------------------------------------------------------------------------------
|
|
1960
1991
|
// Private APIs
|
|
1961
1992
|
// ------------------------------------------------------------------------------------
|
|
1962
1993
|
// NOTE: We could instead store the hash of snapshot instead of the whole snapshot to optimize memory usage.
|
|
1963
1994
|
_getOrPutLastSnapshot(doc) {
|
|
1964
|
-
const docId = doc.guid === this.
|
|
1995
|
+
const docId = doc.guid === this.rawRootDoc.guid ? ROOT_YDOC_ID : doc.guid;
|
|
1965
1996
|
const snapshot2 = this.lastSnapshotById.get(docId);
|
|
1966
1997
|
if (snapshot2) {
|
|
1967
1998
|
return snapshot2;
|
|
@@ -1970,47 +2001,44 @@ var YjsStorage = class {
|
|
|
1970
2001
|
}
|
|
1971
2002
|
// NOTE: We could instead store the hash of snapshot instead of the whole snapshot to optimize memory usage.
|
|
1972
2003
|
_putLastSnapshot(doc) {
|
|
1973
|
-
const docId = doc.guid === this.
|
|
2004
|
+
const docId = doc.guid === this.rawRootDoc.guid ? ROOT_YDOC_ID : doc.guid;
|
|
1974
2005
|
const snapshot2 = Y.snapshot(doc);
|
|
1975
2006
|
this.lastSnapshotById.set(docId, snapshot2);
|
|
1976
2007
|
return snapshot2;
|
|
1977
2008
|
}
|
|
1978
2009
|
findYSubdocByGuid(guid) {
|
|
1979
|
-
for (const subdoc of this.
|
|
2010
|
+
for (const subdoc of this.rawRootDoc.getSubdocs()) {
|
|
1980
2011
|
if (subdoc.guid === guid) {
|
|
1981
2012
|
return subdoc;
|
|
1982
2013
|
}
|
|
1983
2014
|
}
|
|
1984
2015
|
return null;
|
|
1985
2016
|
}
|
|
1986
|
-
|
|
2017
|
+
calculateSnapshotHash(snapshot2, { isV2 }) {
|
|
1987
2018
|
const encodedSnapshot = isV2 ? Y.encodeSnapshotV2(snapshot2) : Y.encodeSnapshot(snapshot2);
|
|
1988
|
-
return
|
|
1989
|
-
new Uint8Array(
|
|
1990
|
-
await crypto.subtle.digest("SHA-256", new Uint8Array(encodedSnapshot))
|
|
1991
|
-
)
|
|
1992
|
-
);
|
|
2019
|
+
return _crypto.createHash.call(void 0, "sha256").update(encodedSnapshot).digest("base64");
|
|
1993
2020
|
}
|
|
1994
2021
|
// gets a subdoc, it will be loaded if not already loaded
|
|
1995
|
-
|
|
2022
|
+
getYSubdoc(logger, guid) {
|
|
2023
|
+
this.getRootDoc(logger);
|
|
1996
2024
|
const subdoc = this.findYSubdocByGuid(guid);
|
|
1997
2025
|
if (!subdoc) {
|
|
1998
2026
|
return null;
|
|
1999
2027
|
}
|
|
2000
|
-
|
|
2028
|
+
this.getYDoc(logger, guid);
|
|
2001
2029
|
return subdoc;
|
|
2002
2030
|
}
|
|
2003
2031
|
// When the YJS doc changes, update it in durable storage
|
|
2004
|
-
|
|
2032
|
+
handleYDocUpdate(doc, update, isV2) {
|
|
2005
2033
|
const v1update = isV2 ? Y.convertUpdateFormatV2ToV1(update) : update;
|
|
2006
|
-
const docId = doc.guid === this.
|
|
2034
|
+
const docId = doc.guid === this.rawRootDoc.guid ? ROOT_YDOC_ID : doc.guid;
|
|
2007
2035
|
const storedKeys = this.storedKeysById.get(docId);
|
|
2008
2036
|
if (this.shouldCompactByKeyCount(storedKeys)) {
|
|
2009
|
-
|
|
2037
|
+
this._compactYJSUpdates(doc, docId, storedKeys || []);
|
|
2010
2038
|
return;
|
|
2011
2039
|
}
|
|
2012
2040
|
const newKey = _nanoid.nanoid.call(void 0, );
|
|
2013
|
-
|
|
2041
|
+
this.driver.write_y_updates(docId, newKey, v1update);
|
|
2014
2042
|
if (!storedKeys) {
|
|
2015
2043
|
this.storedKeysById.set(docId, [newKey]);
|
|
2016
2044
|
} else {
|
|
@@ -2029,10 +2057,19 @@ var YjsStorage = class {
|
|
|
2029
2057
|
};
|
|
2030
2058
|
|
|
2031
2059
|
// src/lib/tryCatch.ts
|
|
2032
|
-
|
|
2060
|
+
function isThenable(value) {
|
|
2061
|
+
return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
2062
|
+
}
|
|
2063
|
+
function tryCatch(promise) {
|
|
2033
2064
|
try {
|
|
2034
|
-
const
|
|
2035
|
-
|
|
2065
|
+
const result = typeof promise === "function" ? promise() : promise;
|
|
2066
|
+
if (isThenable(result)) {
|
|
2067
|
+
return Promise.resolve(result).then(
|
|
2068
|
+
(data) => [data, void 0],
|
|
2069
|
+
(error) => [void 0, error]
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
return [result, void 0];
|
|
2036
2073
|
} catch (error) {
|
|
2037
2074
|
return [void 0, error];
|
|
2038
2075
|
}
|
|
@@ -2258,13 +2295,13 @@ var BackendSession = class extends BrowserSession {
|
|
|
2258
2295
|
super(ticket, socket, debug);
|
|
2259
2296
|
}
|
|
2260
2297
|
};
|
|
2261
|
-
var __debug2;
|
|
2298
|
+
var _logger, __debug2;
|
|
2262
2299
|
var Room = class {
|
|
2263
2300
|
constructor(meta, options) {
|
|
2264
2301
|
// ^^^^^^^^^^ User-defined Room Metadata, Session Metadata, and Client Metadata
|
|
2265
2302
|
__publicField(this, "meta");
|
|
2266
2303
|
__publicField(this, "driver");
|
|
2267
|
-
|
|
2304
|
+
__privateAdd(this, _logger);
|
|
2268
2305
|
/**
|
|
2269
2306
|
* While a room is in "maintenance mode", all WebSocket connections to the
|
|
2270
2307
|
* room should be rejected until it's pulled out of maintenance mode again.
|
|
@@ -2274,8 +2311,10 @@ var Room = class {
|
|
|
2274
2311
|
* init-storage, storage-reset, etc.) cannot interfere with one another.
|
|
2275
2312
|
*/
|
|
2276
2313
|
__publicField(this, "_maintenanceMode", new (0, _asyncmutex.Mutex)());
|
|
2277
|
-
__publicField(this, "
|
|
2278
|
-
__publicField(this, "
|
|
2314
|
+
__publicField(this, "_storage");
|
|
2315
|
+
__publicField(this, "_yjsStorage");
|
|
2316
|
+
__publicField(this, "mutex", new (0, _asyncmutex.Mutex)());
|
|
2317
|
+
// prettier-ignore
|
|
2279
2318
|
__publicField(this, "_qsize", 0);
|
|
2280
2319
|
__publicField(this, "sessions", new UniqueMap((s) => s.actor));
|
|
2281
2320
|
__publicField(this, "hooks");
|
|
@@ -2283,52 +2322,38 @@ var Room = class {
|
|
|
2283
2322
|
const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.storage]), () => ( makeNewInMemoryDriver()));
|
|
2284
2323
|
this.meta = meta;
|
|
2285
2324
|
this.driver = driver;
|
|
2286
|
-
this.
|
|
2325
|
+
this._storage = new Storage(this.driver);
|
|
2326
|
+
this._yjsStorage = new YjsStorage(this.driver);
|
|
2327
|
+
__privateSet(this, _logger, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.logger]), () => ( BLACK_HOLE)));
|
|
2287
2328
|
this.hooks = {
|
|
2288
2329
|
isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.hooks, 'optionalAccess', _64 => _64.isClientMsgAllowed]), () => ( (() => {
|
|
2289
2330
|
return {
|
|
2290
2331
|
allowed: true
|
|
2291
2332
|
};
|
|
2292
2333
|
}))),
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
onSessionDidStart: _optionalChain([options, 'optionalAccess', _73 => _73.hooks, 'optionalAccess', _74 => _74.onSessionDidStart]),
|
|
2299
|
-
onSessionDidEnd: _optionalChain([options, 'optionalAccess', _75 => _75.hooks, 'optionalAccess', _76 => _76.onSessionDidEnd]),
|
|
2300
|
-
postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _77 => _77.hooks, 'optionalAccess', _78 => _78.postClientMsgStorageDidUpdate]),
|
|
2301
|
-
postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _79 => _79.hooks, 'optionalAccess', _80 => _80.postClientMsgYdocDidUpdate])
|
|
2334
|
+
onRoomWillUnload: _optionalChain([options, 'optionalAccess', _65 => _65.hooks, 'optionalAccess', _66 => _66.onRoomWillUnload]),
|
|
2335
|
+
onSessionDidStart: _optionalChain([options, 'optionalAccess', _67 => _67.hooks, 'optionalAccess', _68 => _68.onSessionDidStart]),
|
|
2336
|
+
onSessionDidEnd: _optionalChain([options, 'optionalAccess', _69 => _69.hooks, 'optionalAccess', _70 => _70.onSessionDidEnd]),
|
|
2337
|
+
postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _71 => _71.hooks, 'optionalAccess', _72 => _72.postClientMsgStorageDidUpdate]),
|
|
2338
|
+
postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _73 => _73.hooks, 'optionalAccess', _74 => _74.postClientMsgYdocDidUpdate])
|
|
2302
2339
|
};
|
|
2303
|
-
__privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2304
|
-
}
|
|
2305
|
-
get loadingState() {
|
|
2306
|
-
if (this._loadData$ === null) {
|
|
2307
|
-
return "initial";
|
|
2308
|
-
} else if (this._data === null) {
|
|
2309
|
-
return "loading";
|
|
2310
|
-
} else {
|
|
2311
|
-
return "loaded";
|
|
2312
|
-
}
|
|
2340
|
+
__privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _75 => _75.enableDebugLogging]), () => ( false)));
|
|
2313
2341
|
}
|
|
2314
|
-
get numSessions() {
|
|
2315
|
-
return this.sessions.size;
|
|
2316
|
-
}
|
|
2317
|
-
// prettier-ignore
|
|
2318
2342
|
get storage() {
|
|
2319
|
-
return this.
|
|
2343
|
+
return this._storage;
|
|
2320
2344
|
}
|
|
2321
2345
|
// prettier-ignore
|
|
2322
2346
|
get yjsStorage() {
|
|
2323
|
-
return this.
|
|
2347
|
+
return this._yjsStorage;
|
|
2324
2348
|
}
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
return this.data.mutex;
|
|
2349
|
+
get logger() {
|
|
2350
|
+
return __privateGet(this, _logger);
|
|
2328
2351
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2352
|
+
addLoggerContext(attrs) {
|
|
2353
|
+
__privateSet(this, _logger, __privateGet(this, _logger).withContext(attrs));
|
|
2354
|
+
}
|
|
2355
|
+
get numSessions() {
|
|
2356
|
+
return this.sessions.size;
|
|
2332
2357
|
}
|
|
2333
2358
|
// prettier-ignore
|
|
2334
2359
|
// ------------------------------------------------------------------------------------
|
|
@@ -2353,34 +2378,15 @@ var Room = class {
|
|
|
2353
2378
|
// Public API
|
|
2354
2379
|
// ------------------------------------------------------------------------------------
|
|
2355
2380
|
/**
|
|
2356
|
-
*
|
|
2357
|
-
*
|
|
2358
|
-
* be
|
|
2359
|
-
*/
|
|
2360
|
-
async load(ctx) {
|
|
2361
|
-
if (this._loadData$ === null) {
|
|
2362
|
-
this._data = null;
|
|
2363
|
-
this._loadData$ = this._load(ctx).catch((e) => {
|
|
2364
|
-
this._data = null;
|
|
2365
|
-
this._loadData$ = null;
|
|
2366
|
-
throw e;
|
|
2367
|
-
});
|
|
2368
|
-
}
|
|
2369
|
-
return this._loadData$;
|
|
2370
|
-
}
|
|
2371
|
-
/**
|
|
2372
|
-
* Releases the currently-loaded storage tree from worker memory, freeing it
|
|
2373
|
-
* up to be garbage collected. The next time a user will join the room, the
|
|
2374
|
-
* room will be reloaded from storage.
|
|
2381
|
+
* Releases the currently-loaded storage tree and Yjs documents from worker
|
|
2382
|
+
* memory, freeing them up to be garbage collected. The next time the room
|
|
2383
|
+
* is used, fresh instances will lazily be created.
|
|
2375
2384
|
*/
|
|
2376
2385
|
unload(ctx) {
|
|
2377
|
-
_optionalChain([this, 'access',
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
}
|
|
2382
|
-
this._loadData$ = null;
|
|
2383
|
-
_optionalChain([this, 'access', _85 => _85.hooks, 'access', _86 => _86.onRoomDidUnload, 'optionalCall', _87 => _87(ctx)]);
|
|
2386
|
+
_optionalChain([this, 'access', _76 => _76.hooks, 'access', _77 => _77.onRoomWillUnload, 'optionalCall', _78 => _78(ctx)]);
|
|
2387
|
+
this.driver.reinitialize();
|
|
2388
|
+
this._storage = new Storage(this.driver);
|
|
2389
|
+
this._yjsStorage = new YjsStorage(this.driver);
|
|
2384
2390
|
}
|
|
2385
2391
|
/**
|
|
2386
2392
|
* Issues a Ticket with a new/unique actor ID
|
|
@@ -2393,26 +2399,26 @@ var Room = class {
|
|
|
2393
2399
|
* connection is established. If the socket is never established, this
|
|
2394
2400
|
* unused Ticket will simply get garbage collected.
|
|
2395
2401
|
*/
|
|
2396
|
-
|
|
2397
|
-
const actor
|
|
2402
|
+
createTicket(options) {
|
|
2403
|
+
const actor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _79 => _79.actor]), () => ( this.getNextActor()));
|
|
2398
2404
|
const sessionKey = _nanoid.nanoid.call(void 0, );
|
|
2399
|
-
const info = _optionalChain([options, 'optionalAccess',
|
|
2405
|
+
const info = _optionalChain([options, 'optionalAccess', _80 => _80.info]);
|
|
2400
2406
|
const ticket = {
|
|
2401
|
-
version: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2402
|
-
actor
|
|
2407
|
+
version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
|
|
2408
|
+
actor,
|
|
2403
2409
|
sessionKey,
|
|
2404
|
-
meta: _optionalChain([options, 'optionalAccess',
|
|
2405
|
-
publicMeta: _optionalChain([options, 'optionalAccess',
|
|
2406
|
-
user: _optionalChain([options, 'optionalAccess',
|
|
2407
|
-
scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
2410
|
+
meta: _optionalChain([options, 'optionalAccess', _82 => _82.meta]),
|
|
2411
|
+
publicMeta: _optionalChain([options, 'optionalAccess', _83 => _83.publicMeta]),
|
|
2412
|
+
user: _optionalChain([options, 'optionalAccess', _84 => _84.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _85 => _85.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
|
|
2413
|
+
scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.scopes]), () => ( ["room:write"]))
|
|
2408
2414
|
};
|
|
2409
2415
|
if (__privateGet(this, __debug2)) {
|
|
2410
2416
|
console.log(`new ticket created: ${JSON.stringify(ticket)}`);
|
|
2411
2417
|
}
|
|
2412
2418
|
return ticket;
|
|
2413
2419
|
}
|
|
2414
|
-
|
|
2415
|
-
const ticket =
|
|
2420
|
+
createBackendSession_experimental() {
|
|
2421
|
+
const ticket = this.createTicket();
|
|
2416
2422
|
const capturedServerMsgs = [];
|
|
2417
2423
|
const stub = {
|
|
2418
2424
|
send: (data) => {
|
|
@@ -2453,7 +2459,7 @@ var Room = class {
|
|
|
2453
2459
|
newSession.markActive(lastActivity);
|
|
2454
2460
|
}
|
|
2455
2461
|
}
|
|
2456
|
-
|
|
2462
|
+
sendSessionStartMessages(newSession, ticket, ctx, defer = () => {
|
|
2457
2463
|
throw new Error(
|
|
2458
2464
|
"One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to sendSessionStartMessages() to collect async side effects."
|
|
2459
2465
|
);
|
|
@@ -2466,10 +2472,7 @@ var Room = class {
|
|
|
2466
2472
|
scopes: session.scopes
|
|
2467
2473
|
};
|
|
2468
2474
|
}
|
|
2469
|
-
const leasedSessions =
|
|
2470
|
-
ctx,
|
|
2471
|
-
defer
|
|
2472
|
-
);
|
|
2475
|
+
const leasedSessions = this.listLeasedSessions(ctx, defer);
|
|
2473
2476
|
for (const leasedSession of leasedSessions) {
|
|
2474
2477
|
users[leasedSession.actorId] = {
|
|
2475
2478
|
id: leasedSession.sessionId,
|
|
@@ -2505,7 +2508,7 @@ var Room = class {
|
|
|
2505
2508
|
* - Sends a ROOM_STATE message to the socket.
|
|
2506
2509
|
* - Broadcasts a USER_JOINED message to all other sessions in the room.
|
|
2507
2510
|
*/
|
|
2508
|
-
|
|
2511
|
+
startBrowserSession(ticket, socket, ctx, defer = () => {
|
|
2509
2512
|
throw new Error(
|
|
2510
2513
|
"One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to startBrowserSession() to collect async side effects."
|
|
2511
2514
|
);
|
|
@@ -2519,13 +2522,13 @@ var Room = class {
|
|
|
2519
2522
|
ctx,
|
|
2520
2523
|
defer
|
|
2521
2524
|
);
|
|
2522
|
-
this.
|
|
2525
|
+
__privateGet(this, _logger).warn(
|
|
2523
2526
|
`Previous session for actor ${ticket.actor} killed in favor of new session`
|
|
2524
2527
|
);
|
|
2525
2528
|
}
|
|
2526
2529
|
const newSession = new BrowserSession(ticket, socket, __privateGet(this, __debug2));
|
|
2527
2530
|
this.sessions.set(ticket.sessionKey, newSession);
|
|
2528
|
-
|
|
2531
|
+
this.sendSessionStartMessages(newSession, ticket, ctx, defer);
|
|
2529
2532
|
this.sendToOthers(
|
|
2530
2533
|
ticket.sessionKey,
|
|
2531
2534
|
{
|
|
@@ -2538,7 +2541,7 @@ var Room = class {
|
|
|
2538
2541
|
ctx,
|
|
2539
2542
|
defer
|
|
2540
2543
|
);
|
|
2541
|
-
const p$ = _optionalChain([this, 'access',
|
|
2544
|
+
const p$ = _optionalChain([this, 'access', _87 => _87.hooks, 'access', _88 => _88.onSessionDidStart, 'optionalCall', _89 => _89(newSession, ctx)]);
|
|
2542
2545
|
if (p$) defer(p$);
|
|
2543
2546
|
}
|
|
2544
2547
|
/**
|
|
@@ -2562,7 +2565,7 @@ var Room = class {
|
|
|
2562
2565
|
for (const other of this.otherSessions(key)) {
|
|
2563
2566
|
other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
|
|
2564
2567
|
}
|
|
2565
|
-
const p$ = _optionalChain([this, 'access',
|
|
2568
|
+
const p$ = _optionalChain([this, 'access', _90 => _90.hooks, 'access', _91 => _91.onSessionDidEnd, 'optionalCall', _92 => _92(session, ctx)]);
|
|
2566
2569
|
if (p$) defer(p$);
|
|
2567
2570
|
}
|
|
2568
2571
|
}
|
|
@@ -2593,7 +2596,7 @@ var Room = class {
|
|
|
2593
2596
|
);
|
|
2594
2597
|
}) {
|
|
2595
2598
|
const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
|
|
2596
|
-
_optionalChain([this, 'access',
|
|
2599
|
+
_optionalChain([this, 'access', _93 => _93.sessions, 'access', _94 => _94.get, 'call', _95 => _95(key), 'optionalAccess', _96 => _96.markActive, 'call', _97 => _97()]);
|
|
2597
2600
|
if (text === "ping") {
|
|
2598
2601
|
await this.handlePing(key, ctx);
|
|
2599
2602
|
} else {
|
|
@@ -2633,7 +2636,6 @@ var Room = class {
|
|
|
2633
2636
|
* 2. The ClientMsg payload has been validated to be correct.
|
|
2634
2637
|
*/
|
|
2635
2638
|
async processClientMsg(key, messages, ctx) {
|
|
2636
|
-
await this.load(ctx);
|
|
2637
2639
|
const { defer, waitAll } = collectSideEffects();
|
|
2638
2640
|
await this.mutex.runExclusive(
|
|
2639
2641
|
() => this._processClientMsg_withExclusiveAccess(key, messages, ctx, defer)
|
|
@@ -2660,7 +2662,6 @@ var Room = class {
|
|
|
2660
2662
|
* a session.
|
|
2661
2663
|
*/
|
|
2662
2664
|
async processClientMsgFromBackendSession(session, messages, ctx) {
|
|
2663
|
-
await this.load(ctx);
|
|
2664
2665
|
const { defer, waitAll } = collectSideEffects();
|
|
2665
2666
|
await this.mutex.runExclusive(
|
|
2666
2667
|
() => this._processClientMsgFromBackendSession_withExclusiveAccess(
|
|
@@ -2682,18 +2683,18 @@ var Room = class {
|
|
|
2682
2683
|
* Upsert a leased session. Creates a new session if it doesn't exist (or is expired),
|
|
2683
2684
|
* or updates an existing session with merged presence.
|
|
2684
2685
|
*/
|
|
2685
|
-
|
|
2686
|
+
upsertLeasedSession(sessionId, presence, ttl, info, ctx, defer = () => {
|
|
2686
2687
|
throw new Error(
|
|
2687
2688
|
"One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to upsertLeasedSession() to collect async side effects."
|
|
2688
2689
|
);
|
|
2689
2690
|
}) {
|
|
2690
|
-
const existingSession =
|
|
2691
|
+
const existingSession = this.driver.get_leased_session(sessionId);
|
|
2691
2692
|
const isExpired = existingSession !== void 0 && isLeasedSessionExpired(existingSession);
|
|
2692
2693
|
if (isExpired) {
|
|
2693
|
-
|
|
2694
|
+
this.deleteLeasedSession(existingSession, ctx, defer);
|
|
2694
2695
|
}
|
|
2695
2696
|
if (existingSession === void 0 || isExpired) {
|
|
2696
|
-
const actorId =
|
|
2697
|
+
const actorId = this.getNextActor();
|
|
2697
2698
|
const now = Date.now();
|
|
2698
2699
|
const session = {
|
|
2699
2700
|
sessionId,
|
|
@@ -2703,7 +2704,7 @@ var Room = class {
|
|
|
2703
2704
|
ttl,
|
|
2704
2705
|
actorId
|
|
2705
2706
|
};
|
|
2706
|
-
|
|
2707
|
+
this.driver.put_leased_session(session);
|
|
2707
2708
|
this.sendToAll(
|
|
2708
2709
|
{
|
|
2709
2710
|
type: ServerMsgCode2.USER_JOINED,
|
|
@@ -2737,7 +2738,7 @@ var Room = class {
|
|
|
2737
2738
|
updatedAt: Date.now(),
|
|
2738
2739
|
ttl
|
|
2739
2740
|
};
|
|
2740
|
-
|
|
2741
|
+
this.driver.put_leased_session(updatedSession);
|
|
2741
2742
|
this.sendToAll(
|
|
2742
2743
|
{
|
|
2743
2744
|
type: ServerMsgCode2.UPDATE_PRESENCE,
|
|
@@ -2754,13 +2755,12 @@ var Room = class {
|
|
|
2754
2755
|
/**
|
|
2755
2756
|
* List all server sessions. As a side effect, it will delete expired sessions.
|
|
2756
2757
|
*/
|
|
2757
|
-
|
|
2758
|
+
listLeasedSessions(ctx, defer = () => {
|
|
2758
2759
|
throw new Error(
|
|
2759
2760
|
"One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to listLeasedSessions() to collect async side effects."
|
|
2760
2761
|
);
|
|
2761
2762
|
}) {
|
|
2762
|
-
|
|
2763
|
-
const sessions = await this.driver.list_leased_sessions();
|
|
2763
|
+
const sessions = this.driver.list_leased_sessions();
|
|
2764
2764
|
const validSessions = [];
|
|
2765
2765
|
const toDelete = [];
|
|
2766
2766
|
for (const [_, session] of sessions) {
|
|
@@ -2771,14 +2771,14 @@ var Room = class {
|
|
|
2771
2771
|
}
|
|
2772
2772
|
}
|
|
2773
2773
|
for (const session of toDelete) {
|
|
2774
|
-
|
|
2774
|
+
this.deleteLeasedSession(session, ctx, defer);
|
|
2775
2775
|
}
|
|
2776
2776
|
return validSessions;
|
|
2777
2777
|
}
|
|
2778
2778
|
/**
|
|
2779
2779
|
* Delete a server session and broadcast USER_LEFT to all sessions.
|
|
2780
2780
|
*/
|
|
2781
|
-
|
|
2781
|
+
deleteLeasedSession(session, ctx, defer = () => {
|
|
2782
2782
|
throw new Error(
|
|
2783
2783
|
"One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to deleteLeasedSession() to collect async side effects."
|
|
2784
2784
|
);
|
|
@@ -2791,20 +2791,19 @@ var Room = class {
|
|
|
2791
2791
|
ctx,
|
|
2792
2792
|
defer
|
|
2793
2793
|
);
|
|
2794
|
-
|
|
2794
|
+
this.driver.delete_leased_session(session.sessionId);
|
|
2795
2795
|
}
|
|
2796
2796
|
/**
|
|
2797
2797
|
* Delete all server sessions and broadcast USER_LEFT to all sessions.
|
|
2798
2798
|
*/
|
|
2799
|
-
|
|
2799
|
+
deleteAllLeasedSessions(ctx, defer = () => {
|
|
2800
2800
|
throw new Error(
|
|
2801
2801
|
"One of your hook handlers returned a promise, but no side effect collector was provided. Pass a `defer` callback to deleteAllLeasedSessions() to collect async side effects."
|
|
2802
2802
|
);
|
|
2803
2803
|
}) {
|
|
2804
|
-
|
|
2805
|
-
const sessions = await this.driver.list_leased_sessions();
|
|
2804
|
+
const sessions = this.driver.list_leased_sessions();
|
|
2806
2805
|
for (const [_, session] of sessions) {
|
|
2807
|
-
|
|
2806
|
+
this.deleteLeasedSession(session, ctx, defer);
|
|
2808
2807
|
}
|
|
2809
2808
|
}
|
|
2810
2809
|
// ---------------------------------------------------------------------------
|
|
@@ -2813,53 +2812,53 @@ var Room = class {
|
|
|
2813
2812
|
/**
|
|
2814
2813
|
* List feeds with pagination and filtering.
|
|
2815
2814
|
*/
|
|
2816
|
-
|
|
2817
|
-
return
|
|
2815
|
+
listFeeds(options) {
|
|
2816
|
+
return this.driver.list_feeds(options);
|
|
2818
2817
|
}
|
|
2819
2818
|
/**
|
|
2820
2819
|
* Get a specific feed by feed ID.
|
|
2821
2820
|
*/
|
|
2822
|
-
|
|
2823
|
-
return
|
|
2821
|
+
getFeed(feedId) {
|
|
2822
|
+
return this.driver.get_feed(feedId);
|
|
2824
2823
|
}
|
|
2825
2824
|
/**
|
|
2826
2825
|
* Create a new feed.
|
|
2827
2826
|
* If timestamp is not provided, current server time is used.
|
|
2828
2827
|
*/
|
|
2829
|
-
|
|
2828
|
+
createFeed(feed) {
|
|
2830
2829
|
const now = _nullishCoalesce(feed.timestamp, () => ( Date.now()));
|
|
2831
2830
|
const fullFeed = {
|
|
2832
2831
|
...feed,
|
|
2833
2832
|
createdAt: now,
|
|
2834
2833
|
updatedAt: now
|
|
2835
2834
|
};
|
|
2836
|
-
|
|
2835
|
+
this.driver.create_feed(fullFeed);
|
|
2837
2836
|
return fullFeed;
|
|
2838
2837
|
}
|
|
2839
2838
|
/**
|
|
2840
2839
|
* Update a feed's metadata.
|
|
2841
2840
|
*/
|
|
2842
|
-
|
|
2843
|
-
|
|
2841
|
+
updateFeedMetadata(feedId, metadata) {
|
|
2842
|
+
this.driver.update_feed_metadata(feedId, metadata);
|
|
2844
2843
|
}
|
|
2845
2844
|
/**
|
|
2846
2845
|
* Delete a feed.
|
|
2847
2846
|
*/
|
|
2848
|
-
|
|
2849
|
-
|
|
2847
|
+
deleteFeed(feedId) {
|
|
2848
|
+
this.driver.delete_feed(feedId);
|
|
2850
2849
|
}
|
|
2851
2850
|
/**
|
|
2852
2851
|
* List feed messages for a feed with pagination.
|
|
2853
2852
|
*/
|
|
2854
|
-
|
|
2855
|
-
return
|
|
2853
|
+
listFeedMessages(feedId, options) {
|
|
2854
|
+
return this.driver.list_feed_messages(feedId, options);
|
|
2856
2855
|
}
|
|
2857
2856
|
/**
|
|
2858
2857
|
* Add a message to a feed.
|
|
2859
2858
|
* If message id is not provided, a unique ID is automatically generated.
|
|
2860
2859
|
* If timestamp is not provided, current server time is used.
|
|
2861
2860
|
*/
|
|
2862
|
-
|
|
2861
|
+
addFeedMessage(feedId, message) {
|
|
2863
2862
|
const now = _nullishCoalesce(message.timestamp, () => ( Date.now()));
|
|
2864
2863
|
const fullMessage = {
|
|
2865
2864
|
id: _nullishCoalesce(message.id, () => ( _nanoid.nanoid.call(void 0, ))),
|
|
@@ -2867,15 +2866,15 @@ var Room = class {
|
|
|
2867
2866
|
updatedAt: now,
|
|
2868
2867
|
data: message.data
|
|
2869
2868
|
};
|
|
2870
|
-
|
|
2869
|
+
this.driver.add_feed_message(feedId, fullMessage);
|
|
2871
2870
|
return fullMessage;
|
|
2872
2871
|
}
|
|
2873
2872
|
/**
|
|
2874
2873
|
* Update a feed message's data.
|
|
2875
2874
|
* Returns the updated message.
|
|
2876
2875
|
*/
|
|
2877
|
-
|
|
2878
|
-
return
|
|
2876
|
+
updateFeedMessage(feedId, messageId, data, timestamp) {
|
|
2877
|
+
return this.driver.update_feed_message(
|
|
2879
2878
|
feedId,
|
|
2880
2879
|
messageId,
|
|
2881
2880
|
data,
|
|
@@ -2885,8 +2884,8 @@ var Room = class {
|
|
|
2885
2884
|
/**
|
|
2886
2885
|
* Delete a feed message.
|
|
2887
2886
|
*/
|
|
2888
|
-
|
|
2889
|
-
|
|
2887
|
+
deleteFeedMessage(feedId, messageId) {
|
|
2888
|
+
this.driver.delete_feed_message(feedId, messageId);
|
|
2890
2889
|
}
|
|
2891
2890
|
/**
|
|
2892
2891
|
* Will send the given ServerMsg through all Session, except the Session
|
|
@@ -2933,37 +2932,15 @@ var Room = class {
|
|
|
2933
2932
|
}
|
|
2934
2933
|
}
|
|
2935
2934
|
}
|
|
2936
|
-
// ------------------------------------------------------------------------------------
|
|
2937
|
-
// Private APIs
|
|
2938
|
-
// ------------------------------------------------------------------------------------
|
|
2939
|
-
async _loadStorage() {
|
|
2940
|
-
const storage = new Storage(this.driver);
|
|
2941
|
-
await storage.load(this.logger);
|
|
2942
|
-
return storage;
|
|
2943
|
-
}
|
|
2944
|
-
async _loadYjsStorage() {
|
|
2945
|
-
const yjsStorage = new YjsStorage(this.driver);
|
|
2946
|
-
await yjsStorage.load(this.logger);
|
|
2947
|
-
return yjsStorage;
|
|
2948
|
-
}
|
|
2949
|
-
// Don't ever manually call this!
|
|
2950
|
-
async _load(ctx) {
|
|
2951
|
-
await _optionalChain([this, 'access', _107 => _107.hooks, 'access', _108 => _108.onRoomWillLoad, 'optionalCall', _109 => _109(ctx)]);
|
|
2952
|
-
const storage = await this._loadStorage();
|
|
2953
|
-
const yjsStorage = await this._loadYjsStorage();
|
|
2954
|
-
this._data = {
|
|
2955
|
-
mutex: new (0, _asyncmutex.Mutex)(),
|
|
2956
|
-
storage,
|
|
2957
|
-
yjsStorage
|
|
2958
|
-
};
|
|
2959
|
-
await _optionalChain([this, 'access', _110 => _110.hooks, 'access', _111 => _111.onRoomDidLoad, 'optionalCall', _112 => _112(ctx)]);
|
|
2960
|
-
}
|
|
2961
2935
|
/**
|
|
2962
2936
|
* Returns a new, unique, actor ID.
|
|
2963
2937
|
*/
|
|
2964
|
-
|
|
2965
|
-
return
|
|
2938
|
+
getNextActor() {
|
|
2939
|
+
return this.driver.next_actor();
|
|
2966
2940
|
}
|
|
2941
|
+
// ------------------------------------------------------------------------------------
|
|
2942
|
+
// Private APIs
|
|
2943
|
+
// ------------------------------------------------------------------------------------
|
|
2967
2944
|
/**
|
|
2968
2945
|
* Iterates over all *other* Sessions and their session keys.
|
|
2969
2946
|
*/
|
|
@@ -2991,18 +2968,18 @@ var Room = class {
|
|
|
2991
2968
|
async handlePing(sessionKey, ctx) {
|
|
2992
2969
|
const session = this.sessions.get(sessionKey);
|
|
2993
2970
|
if (session === void 0) {
|
|
2994
|
-
this.
|
|
2971
|
+
__privateGet(this, _logger).withContext({ sessionKey }).warn("[probe] in handlePing, no such session exists");
|
|
2995
2972
|
return;
|
|
2996
2973
|
}
|
|
2997
2974
|
const sent = session.sendPong();
|
|
2998
2975
|
if (sent !== 0) {
|
|
2999
|
-
await _optionalChain([this, 'access',
|
|
2976
|
+
await _optionalChain([this, 'access', _98 => _98.hooks, 'access', _99 => _99.onDidPong, 'optionalCall', _100 => _100(ctx)]);
|
|
3000
2977
|
}
|
|
3001
2978
|
}
|
|
3002
|
-
|
|
2979
|
+
_processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
|
|
3003
2980
|
const session = this.sessions.get(sessionKey);
|
|
3004
2981
|
if (!session) {
|
|
3005
|
-
this.
|
|
2982
|
+
__privateGet(this, _logger).withContext({ sessionKey }).warn("[probe] in handleClientMsgs, no such session exists");
|
|
3006
2983
|
return;
|
|
3007
2984
|
}
|
|
3008
2985
|
const toFanOut = [];
|
|
@@ -3013,7 +2990,7 @@ var Room = class {
|
|
|
3013
2990
|
for (const msg of messages) {
|
|
3014
2991
|
const isMsgAllowed = this.hooks.isClientMsgAllowed(msg, session);
|
|
3015
2992
|
if (isMsgAllowed.allowed) {
|
|
3016
|
-
|
|
2993
|
+
this.handleOne(
|
|
3017
2994
|
session,
|
|
3018
2995
|
msg,
|
|
3019
2996
|
replyImmediately,
|
|
@@ -3043,7 +3020,7 @@ var Room = class {
|
|
|
3043
3020
|
// TODO It's a bit bothering how much duplication there is between this method
|
|
3044
3021
|
// and the _processClientMsg_withExclusiveAccess version. A better
|
|
3045
3022
|
// abstraction is needed.
|
|
3046
|
-
|
|
3023
|
+
_processClientMsgFromBackendSession_withExclusiveAccess(session, messages, ctx, defer) {
|
|
3047
3024
|
const toFanOut = [];
|
|
3048
3025
|
const toReplyImmediately = [];
|
|
3049
3026
|
const toReplyAfter = [];
|
|
@@ -3065,7 +3042,7 @@ var Room = class {
|
|
|
3065
3042
|
const scheduleFanOut = (msg) => void toFanOut.push(msg);
|
|
3066
3043
|
const scheduleReply = (msg) => void toReplyAfter.push(msg);
|
|
3067
3044
|
for (const msg of messages) {
|
|
3068
|
-
|
|
3045
|
+
this.handleOne(
|
|
3069
3046
|
session,
|
|
3070
3047
|
msg,
|
|
3071
3048
|
replyImmediately,
|
|
@@ -3088,7 +3065,7 @@ var Room = class {
|
|
|
3088
3065
|
toReplyAfter.length = 0;
|
|
3089
3066
|
}
|
|
3090
3067
|
}
|
|
3091
|
-
|
|
3068
|
+
handleOne(session, msg, replyImmediately, scheduleFanOut, scheduleReply, ctx, defer) {
|
|
3092
3069
|
if (!this.mutex.isLocked()) {
|
|
3093
3070
|
throw new Error("Handling messages requires exclusive access");
|
|
3094
3071
|
}
|
|
@@ -3112,7 +3089,7 @@ var Room = class {
|
|
|
3112
3089
|
}
|
|
3113
3090
|
case _core.ClientMsgCode.FETCH_STORAGE: {
|
|
3114
3091
|
if (session.version >= 8 /* V8 */) {
|
|
3115
|
-
const rawStream = this.storage.
|
|
3092
|
+
const rawStream = this.storage.driver.iter_nodes_optimized();
|
|
3116
3093
|
for (const chunk of groupNodesForWebSocketMessages(rawStream)) {
|
|
3117
3094
|
const frame = `{"type":${ServerMsgCode2.STORAGE_CHUNK},"nodes":[${chunk.join(",")}]}`;
|
|
3118
3095
|
replyImmediately(frame);
|
|
@@ -3121,14 +3098,14 @@ var Room = class {
|
|
|
3121
3098
|
} else {
|
|
3122
3099
|
replyImmediately({
|
|
3123
3100
|
type: ServerMsgCode2.STORAGE_STATE_V7,
|
|
3124
|
-
items: Array.from(this.storage.
|
|
3101
|
+
items: Array.from(this.storage.driver.iter_nodes())
|
|
3125
3102
|
});
|
|
3126
3103
|
}
|
|
3127
3104
|
break;
|
|
3128
3105
|
}
|
|
3129
3106
|
case _core.ClientMsgCode.UPDATE_STORAGE: {
|
|
3130
|
-
_optionalChain([this, 'access',
|
|
3131
|
-
const result =
|
|
3107
|
+
_optionalChain([this, 'access', _101 => _101.driver, 'access', _102 => _102.bump_storage_version, 'optionalCall', _103 => _103()]);
|
|
3108
|
+
const result = this.storage.applyOps(msg.ops);
|
|
3132
3109
|
const opsToForward = result.flatMap(
|
|
3133
3110
|
(r) => r.action === "accepted" ? [r.op] : []
|
|
3134
3111
|
);
|
|
@@ -3160,7 +3137,7 @@ var Room = class {
|
|
|
3160
3137
|
});
|
|
3161
3138
|
}
|
|
3162
3139
|
if (opsToForward.length > 0) {
|
|
3163
|
-
const p$ = _optionalChain([this, 'access',
|
|
3140
|
+
const p$ = _optionalChain([this, 'access', _104 => _104.hooks, 'access', _105 => _105.postClientMsgStorageDidUpdate, 'optionalCall', _106 => _106(ctx)]);
|
|
3164
3141
|
if (p$) defer(p$);
|
|
3165
3142
|
}
|
|
3166
3143
|
break;
|
|
@@ -3169,11 +3146,17 @@ var Room = class {
|
|
|
3169
3146
|
const vector = msg.vector;
|
|
3170
3147
|
const guid = msg.guid;
|
|
3171
3148
|
const isV2 = msg.v2;
|
|
3172
|
-
const
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3149
|
+
const update = this.yjsStorage.getYDocUpdate(
|
|
3150
|
+
__privateGet(this, _logger),
|
|
3151
|
+
vector,
|
|
3152
|
+
guid,
|
|
3153
|
+
isV2
|
|
3154
|
+
);
|
|
3155
|
+
const stateVector = this.yjsStorage.getYStateVector(__privateGet(this, _logger), guid);
|
|
3156
|
+
const snapshotHash = this.yjsStorage.getSnapshotHash(__privateGet(this, _logger), {
|
|
3157
|
+
guid,
|
|
3158
|
+
isV2
|
|
3159
|
+
});
|
|
3177
3160
|
if (update !== null && snapshotHash !== null) {
|
|
3178
3161
|
replyImmediately({
|
|
3179
3162
|
type: ServerMsgCode2.UPDATE_YDOC,
|
|
@@ -3192,8 +3175,8 @@ var Room = class {
|
|
|
3192
3175
|
const update = msg.update;
|
|
3193
3176
|
const guid = msg.guid;
|
|
3194
3177
|
const isV2 = msg.v2;
|
|
3195
|
-
const [result, error] =
|
|
3196
|
-
this.yjsStorage.addYDocUpdate(this
|
|
3178
|
+
const [result, error] = tryCatch(
|
|
3179
|
+
() => this.yjsStorage.addYDocUpdate(__privateGet(this, _logger), update, guid, isV2)
|
|
3197
3180
|
);
|
|
3198
3181
|
if (error)
|
|
3199
3182
|
break;
|
|
@@ -3211,7 +3194,7 @@ var Room = class {
|
|
|
3211
3194
|
defer
|
|
3212
3195
|
);
|
|
3213
3196
|
if (result.isUpdated) {
|
|
3214
|
-
const p$ = _optionalChain([this, 'access',
|
|
3197
|
+
const p$ = _optionalChain([this, 'access', _107 => _107.hooks, 'access', _108 => _108.postClientMsgYdocDidUpdate, 'optionalCall', _109 => _109(ctx, session)]);
|
|
3215
3198
|
if (p$) defer(p$);
|
|
3216
3199
|
}
|
|
3217
3200
|
break;
|
|
@@ -3219,8 +3202,8 @@ var Room = class {
|
|
|
3219
3202
|
// Feed messages
|
|
3220
3203
|
case FeedMsgCode.FETCH_FEEDS: {
|
|
3221
3204
|
const fetchMsg = msg;
|
|
3222
|
-
const [result, err] =
|
|
3223
|
-
this.listFeeds({
|
|
3205
|
+
const [result, err] = tryCatch(
|
|
3206
|
+
() => this.listFeeds({
|
|
3224
3207
|
cursor: fetchMsg.cursor,
|
|
3225
3208
|
since: fetchMsg.since,
|
|
3226
3209
|
limit: fetchMsg.limit,
|
|
@@ -3241,8 +3224,8 @@ var Room = class {
|
|
|
3241
3224
|
}
|
|
3242
3225
|
case FeedMsgCode.FETCH_FEED_MESSAGES: {
|
|
3243
3226
|
const fetchMsg = msg;
|
|
3244
|
-
const [result, err] =
|
|
3245
|
-
this.listFeedMessages(fetchMsg.feedId, {
|
|
3227
|
+
const [result, err] = tryCatch(
|
|
3228
|
+
() => this.listFeedMessages(fetchMsg.feedId, {
|
|
3246
3229
|
cursor: fetchMsg.cursor,
|
|
3247
3230
|
since: fetchMsg.since,
|
|
3248
3231
|
limit: fetchMsg.limit
|
|
@@ -3263,8 +3246,8 @@ var Room = class {
|
|
|
3263
3246
|
}
|
|
3264
3247
|
case FeedMsgCode.ADD_FEED: {
|
|
3265
3248
|
const addMsg = msg;
|
|
3266
|
-
const [feed, err] =
|
|
3267
|
-
this.createFeed({
|
|
3249
|
+
const [feed, err] = tryCatch(
|
|
3250
|
+
() => this.createFeed({
|
|
3268
3251
|
feedId: addMsg.feedId,
|
|
3269
3252
|
metadata: _nullishCoalesce(addMsg.metadata, () => ( {}))
|
|
3270
3253
|
})
|
|
@@ -3283,14 +3266,14 @@ var Room = class {
|
|
|
3283
3266
|
}
|
|
3284
3267
|
case FeedMsgCode.UPDATE_FEED: {
|
|
3285
3268
|
const updateMsg = msg;
|
|
3286
|
-
const [, metaErr] =
|
|
3287
|
-
this.updateFeedMetadata(updateMsg.feedId, updateMsg.metadata)
|
|
3269
|
+
const [, metaErr] = tryCatch(
|
|
3270
|
+
() => this.updateFeedMetadata(updateMsg.feedId, updateMsg.metadata)
|
|
3288
3271
|
);
|
|
3289
3272
|
if (metaErr) {
|
|
3290
3273
|
replyImmediately(feedFailureServerMsg(updateMsg.requestId, metaErr));
|
|
3291
3274
|
break;
|
|
3292
3275
|
}
|
|
3293
|
-
const feed =
|
|
3276
|
+
const feed = this.getFeed(updateMsg.feedId);
|
|
3294
3277
|
if (!feed) {
|
|
3295
3278
|
replyImmediately(
|
|
3296
3279
|
feedRequestFailed(
|
|
@@ -3310,7 +3293,7 @@ var Room = class {
|
|
|
3310
3293
|
}
|
|
3311
3294
|
case FeedMsgCode.DELETE_FEED: {
|
|
3312
3295
|
const deleteMsg = msg;
|
|
3313
|
-
const [, err] =
|
|
3296
|
+
const [, err] = tryCatch(() => this.deleteFeed(deleteMsg.feedId));
|
|
3314
3297
|
if (err) {
|
|
3315
3298
|
replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
|
|
3316
3299
|
break;
|
|
@@ -3325,8 +3308,8 @@ var Room = class {
|
|
|
3325
3308
|
}
|
|
3326
3309
|
case FeedMsgCode.ADD_FEED_MESSAGE: {
|
|
3327
3310
|
const addMsg = msg;
|
|
3328
|
-
const [message, err] =
|
|
3329
|
-
this.addFeedMessage(addMsg.feedId, {
|
|
3311
|
+
const [message, err] = tryCatch(
|
|
3312
|
+
() => this.addFeedMessage(addMsg.feedId, {
|
|
3330
3313
|
data: addMsg.data,
|
|
3331
3314
|
id: addMsg.id
|
|
3332
3315
|
})
|
|
@@ -3346,8 +3329,8 @@ var Room = class {
|
|
|
3346
3329
|
}
|
|
3347
3330
|
case FeedMsgCode.UPDATE_FEED_MESSAGE: {
|
|
3348
3331
|
const updateMsg = msg;
|
|
3349
|
-
const [message, err] =
|
|
3350
|
-
this.updateFeedMessage(
|
|
3332
|
+
const [message, err] = tryCatch(
|
|
3333
|
+
() => this.updateFeedMessage(
|
|
3351
3334
|
updateMsg.feedId,
|
|
3352
3335
|
updateMsg.messageId,
|
|
3353
3336
|
updateMsg.data
|
|
@@ -3368,8 +3351,8 @@ var Room = class {
|
|
|
3368
3351
|
}
|
|
3369
3352
|
case FeedMsgCode.DELETE_FEED_MESSAGE: {
|
|
3370
3353
|
const deleteMsg = msg;
|
|
3371
|
-
const [, err] =
|
|
3372
|
-
this.deleteFeedMessage(deleteMsg.feedId, deleteMsg.messageId)
|
|
3354
|
+
const [, err] = tryCatch(
|
|
3355
|
+
() => this.deleteFeedMessage(deleteMsg.feedId, deleteMsg.messageId)
|
|
3373
3356
|
);
|
|
3374
3357
|
if (err) {
|
|
3375
3358
|
replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
|
|
@@ -3393,6 +3376,7 @@ var Room = class {
|
|
|
3393
3376
|
}
|
|
3394
3377
|
}
|
|
3395
3378
|
};
|
|
3379
|
+
_logger = new WeakMap();
|
|
3396
3380
|
__debug2 = new WeakMap();
|
|
3397
3381
|
|
|
3398
3382
|
|