@liveblocks/server 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -812,11 +812,11 @@ function makeInMemorySnapshot(values) {
812
812
 
813
813
  // src/MetadataDB.ts
814
814
  function makeMetadataDB(driver) {
815
- async function get(a1, a2) {
815
+ function get(a1, a2) {
816
816
  if (a2 === void 0) {
817
- return await driver.get_meta(a1);
817
+ return driver.get_meta(a1);
818
818
  } else {
819
- return a1.value(await driver.get_meta(a2));
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
- async get_meta(key) {
1073
+ get_meta(key) {
1069
1074
  return this._metadb.get(key);
1070
1075
  }
1071
- async put_meta(key, value) {
1076
+ put_meta(key, value) {
1072
1077
  this._metadb.set(key, value);
1073
1078
  }
1074
- async delete_meta(key) {
1079
+ delete_meta(key) {
1075
1080
  this._metadb.delete(key);
1076
1081
  }
1077
- async list_leased_sessions() {
1082
+ list_leased_sessions() {
1078
1083
  return this._leasedSessions.entries();
1079
1084
  }
1080
- async get_leased_session(sessionId) {
1085
+ get_leased_session(sessionId) {
1081
1086
  return this._leasedSessions.get(sessionId);
1082
1087
  }
1083
- async put_leased_session(session) {
1088
+ put_leased_session(session) {
1084
1089
  this._leasedSessions.set(session.sessionId, session);
1085
1090
  }
1086
- async delete_leased_session(sessionId) {
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
- async list_feeds(options) {
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
- async get_feed(feedId) {
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
- async create_feed(feed) {
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
- async update_feed_metadata(feedId, metadata) {
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
- async delete_feed(feedId) {
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
- async list_feed_messages(feedId, options) {
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
- async add_feed_message(feedId, message) {
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
- async update_feed_message(feedId, messageId, data, timestamp) {
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
- async delete_feed_message(feedId, messageId) {
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
- async iter_y_updates(docId) {
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
- async write_y_updates(docId, key, data) {
1281
+ write_y_updates(docId, key, data) {
1277
1282
  this._ydb.set(`${docId}@|@${key}`, data);
1278
1283
  }
1279
- async delete_y_updates(docId, keys) {
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
- async DANGEROUSLY_wipe_all_y_updates() {
1290
+ DANGEROUSLY_wipe_all_y_updates() {
1286
1291
  this._ydb.clear();
1287
1292
  }
1288
- // Intercept load_nodes_api to add caching layer
1289
- load_nodes_api() {
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
- async function set_child(id, node, allowOverwrite = false) {
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
- async function move_sibling(id, newPos) {
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
- async function set_object_data(id, data, allowOverwrite = false) {
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;
@@ -1506,6 +1563,13 @@ function accept(op2, fix) {
1506
1563
  function ignore(ignoredOp) {
1507
1564
  return { action: "ignored", ignoredOpId: ignoredOp.opId };
1508
1565
  }
1566
+ function rectify(op2, parentKey) {
1567
+ return {
1568
+ action: "rectified",
1569
+ ackOp: { ...op2, parentKey },
1570
+ fix: { type: _core.OpCode.SET_PARENT_KEY, id: op2.id, parentKey }
1571
+ };
1572
+ }
1509
1573
  function nodeFromCreateChildOp(op2) {
1510
1574
  switch (op2.type) {
1511
1575
  case _core.OpCode.CREATE_LIST:
@@ -1540,45 +1604,26 @@ function nodeFromCreateChildOp(op2) {
1540
1604
  }
1541
1605
  }
1542
1606
  var Storage = class {
1543
- constructor(coreDriver) {
1607
+ constructor(driver) {
1544
1608
  // The actual underlying storage API (could be backed by in-memory store,
1545
- // SQLite, Redis, Postgres, Cloudflare Durable Object Storage, etc.)
1546
- __publicField(this, "coreDriver");
1547
- __publicField(this, "_loadedDriver");
1548
- this.coreDriver = coreDriver;
1609
+ // SQLite, Postgres, etc.)
1610
+ __publicField(this, "driver");
1611
+ this.driver = driver;
1549
1612
  }
1550
1613
  // -------------------------------------------------------------------------
1551
1614
  // Public API (for Storage)
1552
1615
  // -------------------------------------------------------------------------
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
1616
  // REFACTOR NOTE: Eventually raw_iter_nodes has to be removed here
1560
1617
  raw_iter_nodes() {
1561
- return this.coreDriver.raw_iter_nodes();
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;
1618
+ return this.driver.raw_iter_nodes();
1574
1619
  }
1575
1620
  /**
1576
1621
  * Applies a batch of Ops.
1577
1622
  */
1578
- async applyOps(ops) {
1623
+ applyOps(ops) {
1579
1624
  const results = [];
1580
1625
  for (const op2 of ops) {
1581
- results.push(await this.applyOp(op2));
1626
+ results.push(this.applyOp(op2));
1582
1627
  }
1583
1628
  return results;
1584
1629
  }
@@ -1588,21 +1633,21 @@ var Storage = class {
1588
1633
  /**
1589
1634
  * Applies a single Op.
1590
1635
  */
1591
- async applyOp(op2) {
1636
+ applyOp(op2) {
1592
1637
  switch (op2.type) {
1593
1638
  case _core.OpCode.CREATE_LIST:
1594
1639
  case _core.OpCode.CREATE_MAP:
1595
1640
  case _core.OpCode.CREATE_REGISTER:
1596
1641
  case _core.OpCode.CREATE_OBJECT:
1597
- return await this.applyCreateOp(op2);
1642
+ return this.applyCreateOp(op2);
1598
1643
  case _core.OpCode.UPDATE_OBJECT:
1599
- return await this.applyUpdateObjectOp(op2);
1644
+ return this.applyUpdateObjectOp(op2);
1600
1645
  case _core.OpCode.SET_PARENT_KEY:
1601
- return await this.applySetParentKeyOp(op2);
1646
+ return this.applySetParentKeyOp(op2);
1602
1647
  case _core.OpCode.DELETE_OBJECT_KEY:
1603
- return await this.applyDeleteObjectKeyOp(op2);
1648
+ return this.applyDeleteObjectKeyOp(op2);
1604
1649
  case _core.OpCode.DELETE_CRDT:
1605
- return await this.applyDeleteCrdtOp(op2);
1650
+ return this.applyDeleteCrdtOp(op2);
1606
1651
  // istanbul ignore next
1607
1652
  default:
1608
1653
  if (process.env.NODE_ENV === "production") {
@@ -1612,12 +1657,18 @@ var Storage = class {
1612
1657
  }
1613
1658
  }
1614
1659
  }
1615
- async applyCreateOp(op2) {
1616
- if (this.loadedDriver.has_node(op2.id)) {
1660
+ applyCreateOp(op2) {
1661
+ if (this.driver.has_node(op2.id)) {
1662
+ if (op2.intent === "push") {
1663
+ const stored = this.driver.get_node(op2.id);
1664
+ if (_optionalChain([stored, 'optionalAccess', _47 => _47.parentId]) !== void 0 && _optionalChain([this, 'access', _48 => _48.driver, 'access', _49 => _49.get_node, 'call', _50 => _50(stored.parentId), 'optionalAccess', _51 => _51.type]) === _core.CrdtType.LIST) {
1665
+ return rectify(op2, stored.parentKey);
1666
+ }
1667
+ }
1617
1668
  return ignore(op2);
1618
1669
  }
1619
1670
  const node = nodeFromCreateChildOp(op2);
1620
- const parent = this.loadedDriver.get_node(node.parentId);
1671
+ const parent = this.driver.get_node(node.parentId);
1621
1672
  if (parent === void 0) {
1622
1673
  return ignore(op2);
1623
1674
  }
@@ -1628,7 +1679,7 @@ var Storage = class {
1628
1679
  }
1629
1680
  // fall through
1630
1681
  case _core.CrdtType.MAP:
1631
- await this.loadedDriver.set_child(op2.id, node, true);
1682
+ this.driver.set_child(op2.id, node, true);
1632
1683
  return accept(op2);
1633
1684
  case _core.CrdtType.LIST:
1634
1685
  return this.createChildAsListItem(op2, node);
@@ -1639,23 +1690,19 @@ var Storage = class {
1639
1690
  return _core.assertNever.call(void 0, parent, "Unhandled CRDT type");
1640
1691
  }
1641
1692
  }
1642
- async createChildAsListItem(op2, node) {
1693
+ createChildAsListItem(op2, node) {
1643
1694
  const intent2 = _nullishCoalesce(op2.intent, () => ( "insert"));
1644
1695
  if (intent2 === "insert") {
1645
- return this.acceptAndFix(
1646
- op2,
1647
- node,
1648
- await this.insertIntoList(op2.id, node)
1649
- );
1696
+ return this.acceptAndFix(op2, node, this.insertIntoList(op2.id, node));
1650
1697
  } else if (intent2 === "push") {
1651
- return this.acceptAndFix(op2, node, await this.appendToList(op2.id, node));
1698
+ return this.acceptAndFix(op2, node, this.appendToList(op2.id, node));
1652
1699
  } else if (intent2 === "set") {
1653
1700
  let fix;
1654
- const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _47 => _47.loadedDriver, 'access', _48 => _48.get_node, 'call', _49 => _49(op2.deletedId), 'optionalAccess', _50 => _50.parentId]) === node.parentId ? op2.deletedId : void 0;
1701
+ const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _52 => _52.driver, 'access', _53 => _53.get_node, 'call', _54 => _54(op2.deletedId), 'optionalAccess', _55 => _55.parentId]) === node.parentId ? op2.deletedId : void 0;
1655
1702
  if (deletedId !== void 0) {
1656
- await this.loadedDriver.delete_node(deletedId);
1703
+ this.driver.delete_node(deletedId);
1657
1704
  }
1658
- const prevItemId = this.loadedDriver.get_child_at(
1705
+ const prevItemId = this.driver.get_child_at(
1659
1706
  node.parentId,
1660
1707
  node.parentKey
1661
1708
  );
@@ -1665,7 +1712,7 @@ var Storage = class {
1665
1712
  id: prevItemId
1666
1713
  };
1667
1714
  }
1668
- await this.loadedDriver.set_child(op2.id, node, true);
1715
+ this.driver.set_child(op2.id, node, true);
1669
1716
  return accept(op2, fix);
1670
1717
  } else {
1671
1718
  return _core.assertNever.call(void 0, intent2, "Invalid intent");
@@ -1685,20 +1732,20 @@ var Storage = class {
1685
1732
  }
1686
1733
  return accept(op2);
1687
1734
  }
1688
- async applyDeleteObjectKeyOp(op2) {
1689
- await this.loadedDriver.delete_child_key(op2.id, op2.key);
1735
+ applyDeleteObjectKeyOp(op2) {
1736
+ this.driver.delete_child_key(op2.id, op2.key);
1690
1737
  return accept(op2);
1691
1738
  }
1692
- async applyUpdateObjectOp(op2) {
1693
- await this.loadedDriver.set_object_data(op2.id, op2.data, true);
1739
+ applyUpdateObjectOp(op2) {
1740
+ this.driver.set_object_data(op2.id, op2.data, true);
1694
1741
  return accept(op2);
1695
1742
  }
1696
- async applyDeleteCrdtOp(op2) {
1697
- await this.loadedDriver.delete_node(op2.id);
1743
+ applyDeleteCrdtOp(op2) {
1744
+ this.driver.delete_node(op2.id);
1698
1745
  return accept(op2);
1699
1746
  }
1700
- async applySetParentKeyOp(op2) {
1701
- const newPosition = await this.moveToPosInList(op2.id, op2.parentKey);
1747
+ applySetParentKeyOp(op2) {
1748
+ const newPosition = this.moveToPosInList(op2.id, op2.parentKey);
1702
1749
  if (newPosition === void 0) {
1703
1750
  return ignore(op2);
1704
1751
  }
@@ -1722,12 +1769,12 @@ var Storage = class {
1722
1769
  *
1723
1770
  * Returns the key that was used for the insertion.
1724
1771
  */
1725
- async insertIntoList(id, node) {
1772
+ insertIntoList(id, node) {
1726
1773
  const key = this.findFreeListPosition(node.parentId, _core.asPos.call(void 0, node.parentKey));
1727
1774
  if (key !== node.parentKey) {
1728
1775
  node = { ...node, parentKey: key };
1729
1776
  }
1730
- await this.loadedDriver.set_child(id, node);
1777
+ this.driver.set_child(id, node);
1731
1778
  return node.parentKey;
1732
1779
  }
1733
1780
  /**
@@ -1740,11 +1787,11 @@ var Storage = class {
1740
1787
  *
1741
1788
  * Returns the final key that was used for the insertion.
1742
1789
  */
1743
- async appendToList(id, node) {
1744
- const lastPos = this.loadedDriver.get_last_sibling(node.parentId);
1790
+ appendToList(id, node) {
1791
+ const lastPos = this.driver.get_last_sibling(node.parentId);
1745
1792
  const preferredPos = _core.asPos.call(void 0, node.parentKey);
1746
1793
  const finalKey = lastPos === void 0 || preferredPos > lastPos ? preferredPos : _core.makePosition.call(void 0, lastPos);
1747
- await this.loadedDriver.set_child(
1794
+ this.driver.set_child(
1748
1795
  id,
1749
1796
  finalKey !== node.parentKey ? { ...node, parentKey: finalKey } : node
1750
1797
  );
@@ -1762,12 +1809,12 @@ var Storage = class {
1762
1809
  * Will return `undefined` if this action could not be interpreted. Will be
1763
1810
  * a no-op for non-list items.
1764
1811
  */
1765
- async moveToPosInList(id, targetKey) {
1766
- const node = this.loadedDriver.get_node(id);
1767
- if (_optionalChain([node, 'optionalAccess', _51 => _51.parentId]) === void 0) {
1812
+ moveToPosInList(id, targetKey) {
1813
+ const node = this.driver.get_node(id);
1814
+ if (_optionalChain([node, 'optionalAccess', _56 => _56.parentId]) === void 0) {
1768
1815
  return;
1769
1816
  }
1770
- if (_optionalChain([this, 'access', _52 => _52.loadedDriver, 'access', _53 => _53.get_node, 'call', _54 => _54(node.parentId), 'optionalAccess', _55 => _55.type]) !== _core.CrdtType.LIST) {
1817
+ if (_optionalChain([this, 'access', _57 => _57.driver, 'access', _58 => _58.get_node, 'call', _59 => _59(node.parentId), 'optionalAccess', _60 => _60.type]) !== _core.CrdtType.LIST) {
1771
1818
  return;
1772
1819
  }
1773
1820
  if (node.parentKey === targetKey) {
@@ -1775,7 +1822,7 @@ var Storage = class {
1775
1822
  }
1776
1823
  const key = this.findFreeListPosition(node.parentId, _core.asPos.call(void 0, targetKey));
1777
1824
  if (key !== node.parentKey) {
1778
- await this.loadedDriver.move_sibling(id, key);
1825
+ this.driver.move_sibling(id, key);
1779
1826
  }
1780
1827
  return key;
1781
1828
  }
@@ -1787,11 +1834,11 @@ var Storage = class {
1787
1834
  * to use as parentKey.
1788
1835
  */
1789
1836
  findFreeListPosition(parentId, parentPos) {
1790
- if (!this.loadedDriver.has_child_at(parentId, parentPos)) {
1837
+ if (!this.driver.has_child_at(parentId, parentPos)) {
1791
1838
  return parentPos;
1792
1839
  }
1793
1840
  const currPos = parentPos;
1794
- const nextPos = this.loadedDriver.get_next_sibling(parentId, currPos);
1841
+ const nextPos = this.driver.get_next_sibling(parentId, currPos);
1795
1842
  if (nextPos !== void 0) {
1796
1843
  return _core.makePosition.call(void 0, currPos, nextPos);
1797
1844
  } else {
@@ -1801,6 +1848,7 @@ var Storage = class {
1801
1848
  };
1802
1849
 
1803
1850
  // src/YjsStorage.ts
1851
+ var _crypto = require('crypto');
1804
1852
  var _jsbase64 = require('js-base64');
1805
1853
 
1806
1854
  var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
@@ -1810,30 +1858,33 @@ var YjsStorage = class {
1810
1858
  constructor(driver, updateCountThreshold = UPDATE_COUNT_THRESHOLD) {
1811
1859
  __publicField(this, "driver");
1812
1860
  __publicField(this, "updateCountThreshold");
1813
- __publicField(this, "doc", new Y.Doc());
1814
- // the root document
1861
+ /**
1862
+ * The root Y.Doc instance, which may not have been hydrated from storage
1863
+ * yet. Use getRootDoc() instead, which lazily hydrates it on first access —
1864
+ * only touch this field directly when the unhydrated instance is fine
1865
+ * (e.g. identity checks, subdoc traversal).
1866
+ */
1867
+ __publicField(this, "rawRootDoc", new Y.Doc());
1815
1868
  __publicField(this, "lastSnapshotById", /* @__PURE__ */ new Map());
1816
- __publicField(this, "initPromisesById", /* @__PURE__ */ new Map());
1869
+ __publicField(this, "docsById", /* @__PURE__ */ new Map());
1817
1870
  __publicField(this, "storedKeysById", /* @__PURE__ */ new Map());
1818
1871
  // compact the updates into a single update and write it to the durable storage
1819
- __publicField(this, "_compactYJSUpdates", async (doc, docId, storedKeys) => {
1872
+ __publicField(this, "_compactYJSUpdates", (doc, docId, storedKeys) => {
1820
1873
  const compactedUpdate = Y.encodeStateAsUpdate(doc);
1821
1874
  const newKey = _nanoid.nanoid.call(void 0, );
1822
- await this.driver.write_y_updates(docId, newKey, compactedUpdate);
1823
- await this.driver.delete_y_updates(docId, storedKeys);
1875
+ this.driver.write_y_updates(docId, newKey, compactedUpdate);
1876
+ this.driver.delete_y_updates(docId, storedKeys);
1824
1877
  this.storedKeysById.set(docId, [newKey]);
1825
1878
  });
1826
- __publicField(this, "_loadYDocFromDurableStorage", async (_logger, doc, docId) => {
1827
- const docUpdates = Object.fromEntries(
1828
- await this.driver.iter_y_updates(docId)
1829
- );
1879
+ __publicField(this, "_loadYDocFromDurableStorage", (doc, docId) => {
1880
+ const docUpdates = Object.fromEntries(this.driver.iter_y_updates(docId));
1830
1881
  const updates = Object.values(docUpdates);
1831
1882
  const beforeSize = updates.reduce((acc, update) => acc + update.length, 0);
1832
1883
  const newupdate = Y.mergeUpdates(updates);
1833
1884
  const storedKeys = Object.keys(docUpdates);
1834
1885
  Y.applyUpdate(doc, newupdate);
1835
1886
  if (this.shouldCompactByKeyCount(storedKeys) || this.shouldCompactBySize(beforeSize, newupdate.length)) {
1836
- await this._compactYJSUpdates(doc, docId, storedKeys);
1887
+ this._compactYJSUpdates(doc, docId, storedKeys);
1837
1888
  } else {
1838
1889
  this.storedKeysById.set(docId, storedKeys);
1839
1890
  }
@@ -1842,7 +1893,7 @@ var YjsStorage = class {
1842
1893
  });
1843
1894
  this.driver = driver;
1844
1895
  this.updateCountThreshold = updateCountThreshold;
1845
- this.doc.on("subdocs", ({ removed }) => {
1896
+ this.rawRootDoc.on("subdocs", ({ removed }) => {
1846
1897
  removed.forEach((subdoc) => {
1847
1898
  subdoc.destroy();
1848
1899
  });
@@ -1851,9 +1902,27 @@ var YjsStorage = class {
1851
1902
  // ------------------------------------------------------------------------------------
1852
1903
  // Public API
1853
1904
  // ------------------------------------------------------------------------------------
1854
- async getYDoc(logger, docId) {
1855
- const doc = await this.loadDocByIdIfNotAlreadyLoaded(logger, docId);
1856
- return doc;
1905
+ getYDoc(logger, docId) {
1906
+ if (docId !== ROOT_YDOC_ID) {
1907
+ this.getRootDoc(logger);
1908
+ }
1909
+ let loaded = this.docsById.get(docId);
1910
+ let doc = docId === ROOT_YDOC_ID ? this.rawRootDoc : this.findYSubdocByGuid(docId);
1911
+ if (!doc) {
1912
+ doc = new Y.Doc();
1913
+ }
1914
+ if (loaded === void 0) {
1915
+ loaded = this._loadYDocFromDurableStorage(doc, docId);
1916
+ this.docsById.set(docId, loaded);
1917
+ }
1918
+ return loaded;
1919
+ }
1920
+ /**
1921
+ * Returns the root Y.Doc, lazily loading it from storage first if it
1922
+ * hasn't been loaded yet during this instance's lifetime.
1923
+ */
1924
+ getRootDoc(logger) {
1925
+ return this.getYDoc(logger, ROOT_YDOC_ID);
1857
1926
  }
1858
1927
  /**
1859
1928
  * If passed a state vector, an update with diff will be returned, if not the entire doc is returned.
@@ -1861,18 +1930,13 @@ var YjsStorage = class {
1861
1930
  * @param stateVector a base64 encoded target state vector created by running Y.encodeStateVector(Doc) on the client
1862
1931
  * @returns a base64 encoded array of YJS updates
1863
1932
  */
1864
- async getYDocUpdate(logger, stateVector = "", guid, isV2 = false) {
1865
- const update = await this.getYDocUpdateBinary(
1866
- logger,
1867
- stateVector,
1868
- guid,
1869
- isV2
1870
- );
1933
+ getYDocUpdate(logger, stateVector = "", guid, isV2 = false) {
1934
+ const update = this.getYDocUpdateBinary(logger, stateVector, guid, isV2);
1871
1935
  if (!update) return null;
1872
1936
  return _jsbase64.Base64.fromUint8Array(update);
1873
1937
  }
1874
- async getYDocUpdateBinary(logger, stateVector = "", guid, isV2 = false) {
1875
- const doc = guid !== void 0 ? await this.getYSubdoc(logger, guid) : this.doc;
1938
+ getYDocUpdateBinary(logger, stateVector = "", guid, isV2 = false) {
1939
+ const doc = guid !== void 0 ? this.getYSubdoc(logger, guid) : this.getRootDoc(logger);
1876
1940
  if (!doc) {
1877
1941
  return null;
1878
1942
  }
@@ -1889,15 +1953,15 @@ var YjsStorage = class {
1889
1953
  }
1890
1954
  return Y.encodeStateAsUpdate(doc, encodedTargetVector);
1891
1955
  }
1892
- async getYStateVector(logger, guid) {
1893
- const doc = guid !== void 0 ? await this.getYSubdoc(logger, guid) : this.doc;
1956
+ getYStateVector(logger, guid) {
1957
+ const doc = guid !== void 0 ? this.getYSubdoc(logger, guid) : this.getRootDoc(logger);
1894
1958
  if (!doc) {
1895
1959
  return null;
1896
1960
  }
1897
1961
  return _jsbase64.Base64.fromUint8Array(Y.encodeStateVector(doc));
1898
1962
  }
1899
- async getSnapshotHash(logger, options) {
1900
- const doc = options.guid !== void 0 ? await this.getYSubdoc(logger, options.guid) : this.doc;
1963
+ getSnapshotHash(logger, options) {
1964
+ const doc = options.guid !== void 0 ? this.getYSubdoc(logger, options.guid) : this.getRootDoc(logger);
1901
1965
  if (!doc) {
1902
1966
  return null;
1903
1967
  }
@@ -1910,8 +1974,8 @@ var YjsStorage = class {
1910
1974
  * isUpdated: true if the update had an effect on the YDoc
1911
1975
  * snapshotHash: the hash of the new snapshot
1912
1976
  */
1913
- async addYDocUpdate(logger, update, guid, isV2) {
1914
- const doc = guid !== void 0 ? await this.getYSubdoc(logger, guid) : this.doc;
1977
+ addYDocUpdate(logger, update, guid, isV2) {
1978
+ const doc = guid !== void 0 ? this.getYSubdoc(logger, guid) : this.getRootDoc(logger);
1915
1979
  if (!doc) {
1916
1980
  throw new Error(`YDoc with guid ${guid} not found`);
1917
1981
  }
@@ -1923,11 +1987,11 @@ var YjsStorage = class {
1923
1987
  const afterSnapshot = this._putLastSnapshot(doc);
1924
1988
  const updated = !Y.equalSnapshots(beforeSnapshot, afterSnapshot);
1925
1989
  if (updated) {
1926
- await this.handleYDocUpdate(doc, updateAsU8, isV2);
1990
+ this.handleYDocUpdate(doc, updateAsU8, isV2);
1927
1991
  }
1928
1992
  return {
1929
1993
  isUpdated: updated,
1930
- snapshotHash: await this.calculateSnapshotHash(afterSnapshot, { isV2 })
1994
+ snapshotHash: this.calculateSnapshotHash(afterSnapshot, { isV2 })
1931
1995
  };
1932
1996
  } catch (e) {
1933
1997
  logger.warn(`Ignored bad YDoc update: ${String(e)}`);
@@ -1936,32 +2000,12 @@ var YjsStorage = class {
1936
2000
  );
1937
2001
  }
1938
2002
  }
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
2003
  // ------------------------------------------------------------------------------------
1960
2004
  // Private APIs
1961
2005
  // ------------------------------------------------------------------------------------
1962
2006
  // NOTE: We could instead store the hash of snapshot instead of the whole snapshot to optimize memory usage.
1963
2007
  _getOrPutLastSnapshot(doc) {
1964
- const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
2008
+ const docId = doc.guid === this.rawRootDoc.guid ? ROOT_YDOC_ID : doc.guid;
1965
2009
  const snapshot2 = this.lastSnapshotById.get(docId);
1966
2010
  if (snapshot2) {
1967
2011
  return snapshot2;
@@ -1970,47 +2014,44 @@ var YjsStorage = class {
1970
2014
  }
1971
2015
  // NOTE: We could instead store the hash of snapshot instead of the whole snapshot to optimize memory usage.
1972
2016
  _putLastSnapshot(doc) {
1973
- const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
2017
+ const docId = doc.guid === this.rawRootDoc.guid ? ROOT_YDOC_ID : doc.guid;
1974
2018
  const snapshot2 = Y.snapshot(doc);
1975
2019
  this.lastSnapshotById.set(docId, snapshot2);
1976
2020
  return snapshot2;
1977
2021
  }
1978
2022
  findYSubdocByGuid(guid) {
1979
- for (const subdoc of this.doc.getSubdocs()) {
2023
+ for (const subdoc of this.rawRootDoc.getSubdocs()) {
1980
2024
  if (subdoc.guid === guid) {
1981
2025
  return subdoc;
1982
2026
  }
1983
2027
  }
1984
2028
  return null;
1985
2029
  }
1986
- async calculateSnapshotHash(snapshot2, { isV2 }) {
2030
+ calculateSnapshotHash(snapshot2, { isV2 }) {
1987
2031
  const encodedSnapshot = isV2 ? Y.encodeSnapshotV2(snapshot2) : Y.encodeSnapshot(snapshot2);
1988
- return _jsbase64.Base64.fromUint8Array(
1989
- new Uint8Array(
1990
- await crypto.subtle.digest("SHA-256", new Uint8Array(encodedSnapshot))
1991
- )
1992
- );
2032
+ return _crypto.createHash.call(void 0, "sha256").update(encodedSnapshot).digest("base64");
1993
2033
  }
1994
2034
  // gets a subdoc, it will be loaded if not already loaded
1995
- async getYSubdoc(logger, guid) {
2035
+ getYSubdoc(logger, guid) {
2036
+ this.getRootDoc(logger);
1996
2037
  const subdoc = this.findYSubdocByGuid(guid);
1997
2038
  if (!subdoc) {
1998
2039
  return null;
1999
2040
  }
2000
- await this.loadDocByIdIfNotAlreadyLoaded(logger, guid);
2041
+ this.getYDoc(logger, guid);
2001
2042
  return subdoc;
2002
2043
  }
2003
2044
  // When the YJS doc changes, update it in durable storage
2004
- async handleYDocUpdate(doc, update, isV2) {
2045
+ handleYDocUpdate(doc, update, isV2) {
2005
2046
  const v1update = isV2 ? Y.convertUpdateFormatV2ToV1(update) : update;
2006
- const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
2047
+ const docId = doc.guid === this.rawRootDoc.guid ? ROOT_YDOC_ID : doc.guid;
2007
2048
  const storedKeys = this.storedKeysById.get(docId);
2008
2049
  if (this.shouldCompactByKeyCount(storedKeys)) {
2009
- await this._compactYJSUpdates(doc, docId, storedKeys || []);
2050
+ this._compactYJSUpdates(doc, docId, storedKeys || []);
2010
2051
  return;
2011
2052
  }
2012
2053
  const newKey = _nanoid.nanoid.call(void 0, );
2013
- await this.driver.write_y_updates(docId, newKey, v1update);
2054
+ this.driver.write_y_updates(docId, newKey, v1update);
2014
2055
  if (!storedKeys) {
2015
2056
  this.storedKeysById.set(docId, [newKey]);
2016
2057
  } else {
@@ -2029,10 +2070,19 @@ var YjsStorage = class {
2029
2070
  };
2030
2071
 
2031
2072
  // src/lib/tryCatch.ts
2032
- async function tryCatch(promise) {
2073
+ function isThenable(value) {
2074
+ return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
2075
+ }
2076
+ function tryCatch(promise) {
2033
2077
  try {
2034
- const data = await (typeof promise === "function" ? promise() : promise);
2035
- return [data, void 0];
2078
+ const result = typeof promise === "function" ? promise() : promise;
2079
+ if (isThenable(result)) {
2080
+ return Promise.resolve(result).then(
2081
+ (data) => [data, void 0],
2082
+ (error) => [void 0, error]
2083
+ );
2084
+ }
2085
+ return [result, void 0];
2036
2086
  } catch (error) {
2037
2087
  return [void 0, error];
2038
2088
  }
@@ -2175,13 +2225,13 @@ var BrowserSession = class {
2175
2225
  this.publicMeta = ticket.publicMeta;
2176
2226
  __privateSet(this, __socket, socket);
2177
2227
  __privateSet(this, __debug, debug);
2178
- const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _56 => _56.getTime, 'call', _57 => _57()]), () => ( Date.now()));
2228
+ const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _61 => _61.getTime, 'call', _62 => _62()]), () => ( Date.now()));
2179
2229
  this.createdAt = now;
2180
2230
  __privateSet(this, __lastActiveAt, now);
2181
2231
  __privateSet(this, __hasNotifiedClientStorageUpdateError, false);
2182
2232
  }
2183
2233
  get lastActiveAt() {
2184
- const lastPing = _optionalChain([__privateGet, 'call', _58 => _58(this, __socket), 'access', _59 => _59.getLastPongTimestamp, 'optionalCall', _60 => _60()]);
2234
+ const lastPing = _optionalChain([__privateGet, 'call', _63 => _63(this, __socket), 'access', _64 => _64.getLastPongTimestamp, 'optionalCall', _65 => _65()]);
2185
2235
  if (lastPing && lastPing.getTime() > __privateGet(this, __lastActiveAt)) {
2186
2236
  return lastPing.getTime();
2187
2237
  } else {
@@ -2258,13 +2308,13 @@ var BackendSession = class extends BrowserSession {
2258
2308
  super(ticket, socket, debug);
2259
2309
  }
2260
2310
  };
2261
- var __debug2;
2311
+ var _logger, __debug2;
2262
2312
  var Room = class {
2263
2313
  constructor(meta, options) {
2264
2314
  // ^^^^^^^^^^ User-defined Room Metadata, Session Metadata, and Client Metadata
2265
2315
  __publicField(this, "meta");
2266
2316
  __publicField(this, "driver");
2267
- __publicField(this, "logger");
2317
+ __privateAdd(this, _logger);
2268
2318
  /**
2269
2319
  * While a room is in "maintenance mode", all WebSocket connections to the
2270
2320
  * room should be rejected until it's pulled out of maintenance mode again.
@@ -2274,61 +2324,49 @@ var Room = class {
2274
2324
  * init-storage, storage-reset, etc.) cannot interfere with one another.
2275
2325
  */
2276
2326
  __publicField(this, "_maintenanceMode", new (0, _asyncmutex.Mutex)());
2277
- __publicField(this, "_loadData$", null);
2278
- __publicField(this, "_data", null);
2327
+ __publicField(this, "_storage");
2328
+ __publicField(this, "_yjsStorage");
2329
+ __publicField(this, "mutex", new (0, _asyncmutex.Mutex)());
2330
+ // prettier-ignore
2279
2331
  __publicField(this, "_qsize", 0);
2280
2332
  __publicField(this, "sessions", new UniqueMap((s) => s.actor));
2281
2333
  __publicField(this, "hooks");
2282
2334
  __privateAdd(this, __debug2);
2283
- const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.storage]), () => ( makeNewInMemoryDriver()));
2335
+ const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _66 => _66.storage]), () => ( makeNewInMemoryDriver()));
2284
2336
  this.meta = meta;
2285
2337
  this.driver = driver;
2286
- this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.logger]), () => ( BLACK_HOLE));
2338
+ this._storage = new Storage(this.driver);
2339
+ this._yjsStorage = new YjsStorage(this.driver);
2340
+ __privateSet(this, _logger, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _67 => _67.logger]), () => ( BLACK_HOLE)));
2287
2341
  this.hooks = {
2288
- isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.hooks, 'optionalAccess', _64 => _64.isClientMsgAllowed]), () => ( (() => {
2342
+ isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _68 => _68.hooks, 'optionalAccess', _69 => _69.isClientMsgAllowed]), () => ( (() => {
2289
2343
  return {
2290
2344
  allowed: true
2291
2345
  };
2292
2346
  }))),
2293
- // YYY .load() isn't called on the RoomServer yet! As soon as it does, these hooks will get called
2294
- onRoomWillLoad: _optionalChain([options, 'optionalAccess', _65 => _65.hooks, 'optionalAccess', _66 => _66.onRoomWillLoad]),
2295
- onRoomDidLoad: _optionalChain([options, 'optionalAccess', _67 => _67.hooks, 'optionalAccess', _68 => _68.onRoomDidLoad]),
2296
- onRoomWillUnload: _optionalChain([options, 'optionalAccess', _69 => _69.hooks, 'optionalAccess', _70 => _70.onRoomWillUnload]),
2297
- onRoomDidUnload: _optionalChain([options, 'optionalAccess', _71 => _71.hooks, 'optionalAccess', _72 => _72.onRoomDidUnload]),
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])
2347
+ onRoomWillUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomWillUnload]),
2348
+ onSessionDidStart: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onSessionDidStart]),
2349
+ onSessionDidEnd: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidEnd]),
2350
+ postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.postClientMsgStorageDidUpdate]),
2351
+ postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _78 => _78.hooks, 'optionalAccess', _79 => _79.postClientMsgYdocDidUpdate])
2302
2352
  };
2303
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.enableDebugLogging]), () => ( false)));
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
- }
2353
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.enableDebugLogging]), () => ( false)));
2313
2354
  }
2314
- get numSessions() {
2315
- return this.sessions.size;
2316
- }
2317
- // prettier-ignore
2318
2355
  get storage() {
2319
- return this.data.storage;
2356
+ return this._storage;
2320
2357
  }
2321
2358
  // prettier-ignore
2322
2359
  get yjsStorage() {
2323
- return this.data.yjsStorage;
2360
+ return this._yjsStorage;
2324
2361
  }
2325
- // prettier-ignore
2326
- get mutex() {
2327
- return this.data.mutex;
2362
+ get logger() {
2363
+ return __privateGet(this, _logger);
2328
2364
  }
2329
- // prettier-ignore
2330
- get data() {
2331
- return _nullishCoalesce(this._data, () => ( _core.raise.call(void 0, "Cannot use room before it's loaded")));
2365
+ addLoggerContext(attrs) {
2366
+ __privateSet(this, _logger, __privateGet(this, _logger).withContext(attrs));
2367
+ }
2368
+ get numSessions() {
2369
+ return this.sessions.size;
2332
2370
  }
2333
2371
  // prettier-ignore
2334
2372
  // ------------------------------------------------------------------------------------
@@ -2353,34 +2391,15 @@ var Room = class {
2353
2391
  // Public API
2354
2392
  // ------------------------------------------------------------------------------------
2355
2393
  /**
2356
- * Initializes the Room, so it's ready to start accepting connections. Safe
2357
- * to call multiple times. After awaiting `room.load()` the Room is ready to
2358
- * be used.
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.
2394
+ * Releases the currently-loaded storage tree and Yjs documents from worker
2395
+ * memory, freeing them up to be garbage collected. The next time the room
2396
+ * is used, fresh instances will lazily be created.
2375
2397
  */
2376
2398
  unload(ctx) {
2377
- _optionalChain([this, 'access', _82 => _82.hooks, 'access', _83 => _83.onRoomWillUnload, 'optionalCall', _84 => _84(ctx)]);
2378
- if (this._data) {
2379
- this.storage.unload();
2380
- this.yjsStorage.unload();
2381
- }
2382
- this._loadData$ = null;
2383
- _optionalChain([this, 'access', _85 => _85.hooks, 'access', _86 => _86.onRoomDidUnload, 'optionalCall', _87 => _87(ctx)]);
2399
+ _optionalChain([this, 'access', _81 => _81.hooks, 'access', _82 => _82.onRoomWillUnload, 'optionalCall', _83 => _83(ctx)]);
2400
+ this.driver.reinitialize();
2401
+ this._storage = new Storage(this.driver);
2402
+ this._yjsStorage = new YjsStorage(this.driver);
2384
2403
  }
2385
2404
  /**
2386
2405
  * Issues a Ticket with a new/unique actor ID
@@ -2393,26 +2412,26 @@ var Room = class {
2393
2412
  * connection is established. If the socket is never established, this
2394
2413
  * unused Ticket will simply get garbage collected.
2395
2414
  */
2396
- async createTicket(options) {
2397
- const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _88 => _88.actor]), () => ( this.getNextActor()));
2415
+ createTicket(options) {
2416
+ const actor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.actor]), () => ( this.getNextActor()));
2398
2417
  const sessionKey = _nanoid.nanoid.call(void 0, );
2399
- const info = _optionalChain([options, 'optionalAccess', _89 => _89.info]);
2418
+ const info = _optionalChain([options, 'optionalAccess', _85 => _85.info]);
2400
2419
  const ticket = {
2401
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _90 => _90.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2402
- actor: await actor$,
2420
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2421
+ actor,
2403
2422
  sessionKey,
2404
- meta: _optionalChain([options, 'optionalAccess', _91 => _91.meta]),
2405
- publicMeta: _optionalChain([options, 'optionalAccess', _92 => _92.publicMeta]),
2406
- user: _optionalChain([options, 'optionalAccess', _93 => _93.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _94 => _94.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
2407
- scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _95 => _95.scopes]), () => ( ["room:write"]))
2423
+ meta: _optionalChain([options, 'optionalAccess', _87 => _87.meta]),
2424
+ publicMeta: _optionalChain([options, 'optionalAccess', _88 => _88.publicMeta]),
2425
+ user: _optionalChain([options, 'optionalAccess', _89 => _89.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _90 => _90.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
2426
+ scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.scopes]), () => ( ["room:write"]))
2408
2427
  };
2409
2428
  if (__privateGet(this, __debug2)) {
2410
2429
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
2411
2430
  }
2412
2431
  return ticket;
2413
2432
  }
2414
- async createBackendSession_experimental() {
2415
- const ticket = await this.createTicket();
2433
+ createBackendSession_experimental() {
2434
+ const ticket = this.createTicket();
2416
2435
  const capturedServerMsgs = [];
2417
2436
  const stub = {
2418
2437
  send: (data) => {
@@ -2453,7 +2472,7 @@ var Room = class {
2453
2472
  newSession.markActive(lastActivity);
2454
2473
  }
2455
2474
  }
2456
- async sendSessionStartMessages(newSession, ticket, ctx, defer = () => {
2475
+ sendSessionStartMessages(newSession, ticket, ctx, defer = () => {
2457
2476
  throw new Error(
2458
2477
  "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
2478
  );
@@ -2466,10 +2485,7 @@ var Room = class {
2466
2485
  scopes: session.scopes
2467
2486
  };
2468
2487
  }
2469
- const leasedSessions = await this.listLeasedSessions(
2470
- ctx,
2471
- defer
2472
- );
2488
+ const leasedSessions = this.listLeasedSessions(ctx, defer);
2473
2489
  for (const leasedSession of leasedSessions) {
2474
2490
  users[leasedSession.actorId] = {
2475
2491
  id: leasedSession.sessionId,
@@ -2505,7 +2521,7 @@ var Room = class {
2505
2521
  * - Sends a ROOM_STATE message to the socket.
2506
2522
  * - Broadcasts a USER_JOINED message to all other sessions in the room.
2507
2523
  */
2508
- async startBrowserSession(ticket, socket, ctx, defer = () => {
2524
+ startBrowserSession(ticket, socket, ctx, defer = () => {
2509
2525
  throw new Error(
2510
2526
  "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
2527
  );
@@ -2519,13 +2535,13 @@ var Room = class {
2519
2535
  ctx,
2520
2536
  defer
2521
2537
  );
2522
- this.logger.warn(
2538
+ __privateGet(this, _logger).warn(
2523
2539
  `Previous session for actor ${ticket.actor} killed in favor of new session`
2524
2540
  );
2525
2541
  }
2526
2542
  const newSession = new BrowserSession(ticket, socket, __privateGet(this, __debug2));
2527
2543
  this.sessions.set(ticket.sessionKey, newSession);
2528
- await this.sendSessionStartMessages(newSession, ticket, ctx, defer);
2544
+ this.sendSessionStartMessages(newSession, ticket, ctx, defer);
2529
2545
  this.sendToOthers(
2530
2546
  ticket.sessionKey,
2531
2547
  {
@@ -2538,7 +2554,7 @@ var Room = class {
2538
2554
  ctx,
2539
2555
  defer
2540
2556
  );
2541
- const p$ = _optionalChain([this, 'access', _96 => _96.hooks, 'access', _97 => _97.onSessionDidStart, 'optionalCall', _98 => _98(newSession, ctx)]);
2557
+ const p$ = _optionalChain([this, 'access', _92 => _92.hooks, 'access', _93 => _93.onSessionDidStart, 'optionalCall', _94 => _94(newSession, ctx)]);
2542
2558
  if (p$) defer(p$);
2543
2559
  }
2544
2560
  /**
@@ -2562,7 +2578,7 @@ var Room = class {
2562
2578
  for (const other of this.otherSessions(key)) {
2563
2579
  other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
2564
2580
  }
2565
- const p$ = _optionalChain([this, 'access', _99 => _99.hooks, 'access', _100 => _100.onSessionDidEnd, 'optionalCall', _101 => _101(session, ctx)]);
2581
+ const p$ = _optionalChain([this, 'access', _95 => _95.hooks, 'access', _96 => _96.onSessionDidEnd, 'optionalCall', _97 => _97(session, ctx)]);
2566
2582
  if (p$) defer(p$);
2567
2583
  }
2568
2584
  }
@@ -2593,7 +2609,7 @@ var Room = class {
2593
2609
  );
2594
2610
  }) {
2595
2611
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2596
- _optionalChain([this, 'access', _102 => _102.sessions, 'access', _103 => _103.get, 'call', _104 => _104(key), 'optionalAccess', _105 => _105.markActive, 'call', _106 => _106()]);
2612
+ _optionalChain([this, 'access', _98 => _98.sessions, 'access', _99 => _99.get, 'call', _100 => _100(key), 'optionalAccess', _101 => _101.markActive, 'call', _102 => _102()]);
2597
2613
  if (text === "ping") {
2598
2614
  await this.handlePing(key, ctx);
2599
2615
  } else {
@@ -2633,7 +2649,6 @@ var Room = class {
2633
2649
  * 2. The ClientMsg payload has been validated to be correct.
2634
2650
  */
2635
2651
  async processClientMsg(key, messages, ctx) {
2636
- await this.load(ctx);
2637
2652
  const { defer, waitAll } = collectSideEffects();
2638
2653
  await this.mutex.runExclusive(
2639
2654
  () => this._processClientMsg_withExclusiveAccess(key, messages, ctx, defer)
@@ -2660,7 +2675,6 @@ var Room = class {
2660
2675
  * a session.
2661
2676
  */
2662
2677
  async processClientMsgFromBackendSession(session, messages, ctx) {
2663
- await this.load(ctx);
2664
2678
  const { defer, waitAll } = collectSideEffects();
2665
2679
  await this.mutex.runExclusive(
2666
2680
  () => this._processClientMsgFromBackendSession_withExclusiveAccess(
@@ -2682,18 +2696,18 @@ var Room = class {
2682
2696
  * Upsert a leased session. Creates a new session if it doesn't exist (or is expired),
2683
2697
  * or updates an existing session with merged presence.
2684
2698
  */
2685
- async upsertLeasedSession(sessionId, presence, ttl, info, ctx, defer = () => {
2699
+ upsertLeasedSession(sessionId, presence, ttl, info, ctx, defer = () => {
2686
2700
  throw new Error(
2687
2701
  "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
2702
  );
2689
2703
  }) {
2690
- const existingSession = await this.driver.get_leased_session(sessionId);
2704
+ const existingSession = this.driver.get_leased_session(sessionId);
2691
2705
  const isExpired = existingSession !== void 0 && isLeasedSessionExpired(existingSession);
2692
2706
  if (isExpired) {
2693
- await this.deleteLeasedSession(existingSession, ctx, defer);
2707
+ this.deleteLeasedSession(existingSession, ctx, defer);
2694
2708
  }
2695
2709
  if (existingSession === void 0 || isExpired) {
2696
- const actorId = await this.getNextActor();
2710
+ const actorId = this.getNextActor();
2697
2711
  const now = Date.now();
2698
2712
  const session = {
2699
2713
  sessionId,
@@ -2703,7 +2717,7 @@ var Room = class {
2703
2717
  ttl,
2704
2718
  actorId
2705
2719
  };
2706
- await this.driver.put_leased_session(session);
2720
+ this.driver.put_leased_session(session);
2707
2721
  this.sendToAll(
2708
2722
  {
2709
2723
  type: ServerMsgCode2.USER_JOINED,
@@ -2737,7 +2751,7 @@ var Room = class {
2737
2751
  updatedAt: Date.now(),
2738
2752
  ttl
2739
2753
  };
2740
- await this.driver.put_leased_session(updatedSession);
2754
+ this.driver.put_leased_session(updatedSession);
2741
2755
  this.sendToAll(
2742
2756
  {
2743
2757
  type: ServerMsgCode2.UPDATE_PRESENCE,
@@ -2754,13 +2768,12 @@ var Room = class {
2754
2768
  /**
2755
2769
  * List all server sessions. As a side effect, it will delete expired sessions.
2756
2770
  */
2757
- async listLeasedSessions(ctx, defer = () => {
2771
+ listLeasedSessions(ctx, defer = () => {
2758
2772
  throw new Error(
2759
2773
  "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
2774
  );
2761
2775
  }) {
2762
- await this.load(ctx);
2763
- const sessions = await this.driver.list_leased_sessions();
2776
+ const sessions = this.driver.list_leased_sessions();
2764
2777
  const validSessions = [];
2765
2778
  const toDelete = [];
2766
2779
  for (const [_, session] of sessions) {
@@ -2771,14 +2784,14 @@ var Room = class {
2771
2784
  }
2772
2785
  }
2773
2786
  for (const session of toDelete) {
2774
- await this.deleteLeasedSession(session, ctx, defer);
2787
+ this.deleteLeasedSession(session, ctx, defer);
2775
2788
  }
2776
2789
  return validSessions;
2777
2790
  }
2778
2791
  /**
2779
2792
  * Delete a server session and broadcast USER_LEFT to all sessions.
2780
2793
  */
2781
- async deleteLeasedSession(session, ctx, defer = () => {
2794
+ deleteLeasedSession(session, ctx, defer = () => {
2782
2795
  throw new Error(
2783
2796
  "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
2797
  );
@@ -2791,20 +2804,19 @@ var Room = class {
2791
2804
  ctx,
2792
2805
  defer
2793
2806
  );
2794
- await this.driver.delete_leased_session(session.sessionId);
2807
+ this.driver.delete_leased_session(session.sessionId);
2795
2808
  }
2796
2809
  /**
2797
2810
  * Delete all server sessions and broadcast USER_LEFT to all sessions.
2798
2811
  */
2799
- async deleteAllLeasedSessions(ctx, defer = () => {
2812
+ deleteAllLeasedSessions(ctx, defer = () => {
2800
2813
  throw new Error(
2801
2814
  "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
2815
  );
2803
2816
  }) {
2804
- await this.load(ctx);
2805
- const sessions = await this.driver.list_leased_sessions();
2817
+ const sessions = this.driver.list_leased_sessions();
2806
2818
  for (const [_, session] of sessions) {
2807
- await this.deleteLeasedSession(session, ctx, defer);
2819
+ this.deleteLeasedSession(session, ctx, defer);
2808
2820
  }
2809
2821
  }
2810
2822
  // ---------------------------------------------------------------------------
@@ -2813,53 +2825,53 @@ var Room = class {
2813
2825
  /**
2814
2826
  * List feeds with pagination and filtering.
2815
2827
  */
2816
- async listFeeds(options) {
2817
- return await this.driver.list_feeds(options);
2828
+ listFeeds(options) {
2829
+ return this.driver.list_feeds(options);
2818
2830
  }
2819
2831
  /**
2820
2832
  * Get a specific feed by feed ID.
2821
2833
  */
2822
- async getFeed(feedId) {
2823
- return await this.driver.get_feed(feedId);
2834
+ getFeed(feedId) {
2835
+ return this.driver.get_feed(feedId);
2824
2836
  }
2825
2837
  /**
2826
2838
  * Create a new feed.
2827
2839
  * If timestamp is not provided, current server time is used.
2828
2840
  */
2829
- async createFeed(feed) {
2841
+ createFeed(feed) {
2830
2842
  const now = _nullishCoalesce(feed.timestamp, () => ( Date.now()));
2831
2843
  const fullFeed = {
2832
2844
  ...feed,
2833
2845
  createdAt: now,
2834
2846
  updatedAt: now
2835
2847
  };
2836
- await this.driver.create_feed(fullFeed);
2848
+ this.driver.create_feed(fullFeed);
2837
2849
  return fullFeed;
2838
2850
  }
2839
2851
  /**
2840
2852
  * Update a feed's metadata.
2841
2853
  */
2842
- async updateFeedMetadata(feedId, metadata) {
2843
- await this.driver.update_feed_metadata(feedId, metadata);
2854
+ updateFeedMetadata(feedId, metadata) {
2855
+ this.driver.update_feed_metadata(feedId, metadata);
2844
2856
  }
2845
2857
  /**
2846
2858
  * Delete a feed.
2847
2859
  */
2848
- async deleteFeed(feedId) {
2849
- await this.driver.delete_feed(feedId);
2860
+ deleteFeed(feedId) {
2861
+ this.driver.delete_feed(feedId);
2850
2862
  }
2851
2863
  /**
2852
2864
  * List feed messages for a feed with pagination.
2853
2865
  */
2854
- async listFeedMessages(feedId, options) {
2855
- return await this.driver.list_feed_messages(feedId, options);
2866
+ listFeedMessages(feedId, options) {
2867
+ return this.driver.list_feed_messages(feedId, options);
2856
2868
  }
2857
2869
  /**
2858
2870
  * Add a message to a feed.
2859
2871
  * If message id is not provided, a unique ID is automatically generated.
2860
2872
  * If timestamp is not provided, current server time is used.
2861
2873
  */
2862
- async addFeedMessage(feedId, message) {
2874
+ addFeedMessage(feedId, message) {
2863
2875
  const now = _nullishCoalesce(message.timestamp, () => ( Date.now()));
2864
2876
  const fullMessage = {
2865
2877
  id: _nullishCoalesce(message.id, () => ( _nanoid.nanoid.call(void 0, ))),
@@ -2867,15 +2879,15 @@ var Room = class {
2867
2879
  updatedAt: now,
2868
2880
  data: message.data
2869
2881
  };
2870
- await this.driver.add_feed_message(feedId, fullMessage);
2882
+ this.driver.add_feed_message(feedId, fullMessage);
2871
2883
  return fullMessage;
2872
2884
  }
2873
2885
  /**
2874
2886
  * Update a feed message's data.
2875
2887
  * Returns the updated message.
2876
2888
  */
2877
- async updateFeedMessage(feedId, messageId, data, timestamp) {
2878
- return await this.driver.update_feed_message(
2889
+ updateFeedMessage(feedId, messageId, data, timestamp) {
2890
+ return this.driver.update_feed_message(
2879
2891
  feedId,
2880
2892
  messageId,
2881
2893
  data,
@@ -2885,8 +2897,8 @@ var Room = class {
2885
2897
  /**
2886
2898
  * Delete a feed message.
2887
2899
  */
2888
- async deleteFeedMessage(feedId, messageId) {
2889
- await this.driver.delete_feed_message(feedId, messageId);
2900
+ deleteFeedMessage(feedId, messageId) {
2901
+ this.driver.delete_feed_message(feedId, messageId);
2890
2902
  }
2891
2903
  /**
2892
2904
  * Will send the given ServerMsg through all Session, except the Session
@@ -2933,37 +2945,15 @@ var Room = class {
2933
2945
  }
2934
2946
  }
2935
2947
  }
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
2948
  /**
2962
2949
  * Returns a new, unique, actor ID.
2963
2950
  */
2964
- async getNextActor() {
2965
- return await this.driver.next_actor();
2951
+ getNextActor() {
2952
+ return this.driver.next_actor();
2966
2953
  }
2954
+ // ------------------------------------------------------------------------------------
2955
+ // Private APIs
2956
+ // ------------------------------------------------------------------------------------
2967
2957
  /**
2968
2958
  * Iterates over all *other* Sessions and their session keys.
2969
2959
  */
@@ -2991,18 +2981,18 @@ var Room = class {
2991
2981
  async handlePing(sessionKey, ctx) {
2992
2982
  const session = this.sessions.get(sessionKey);
2993
2983
  if (session === void 0) {
2994
- this.logger.withContext({ sessionKey }).warn("[probe] in handlePing, no such session exists");
2984
+ __privateGet(this, _logger).withContext({ sessionKey }).warn("[probe] in handlePing, no such session exists");
2995
2985
  return;
2996
2986
  }
2997
2987
  const sent = session.sendPong();
2998
2988
  if (sent !== 0) {
2999
- await _optionalChain([this, 'access', _113 => _113.hooks, 'access', _114 => _114.onDidPong, 'optionalCall', _115 => _115(ctx)]);
2989
+ await _optionalChain([this, 'access', _103 => _103.hooks, 'access', _104 => _104.onDidPong, 'optionalCall', _105 => _105(ctx)]);
3000
2990
  }
3001
2991
  }
3002
- async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
2992
+ _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
3003
2993
  const session = this.sessions.get(sessionKey);
3004
2994
  if (!session) {
3005
- this.logger.withContext({ sessionKey }).warn("[probe] in handleClientMsgs, no such session exists");
2995
+ __privateGet(this, _logger).withContext({ sessionKey }).warn("[probe] in handleClientMsgs, no such session exists");
3006
2996
  return;
3007
2997
  }
3008
2998
  const toFanOut = [];
@@ -3013,7 +3003,7 @@ var Room = class {
3013
3003
  for (const msg of messages) {
3014
3004
  const isMsgAllowed = this.hooks.isClientMsgAllowed(msg, session);
3015
3005
  if (isMsgAllowed.allowed) {
3016
- await this.handleOne(
3006
+ this.handleOne(
3017
3007
  session,
3018
3008
  msg,
3019
3009
  replyImmediately,
@@ -3043,7 +3033,7 @@ var Room = class {
3043
3033
  // TODO It's a bit bothering how much duplication there is between this method
3044
3034
  // and the _processClientMsg_withExclusiveAccess version. A better
3045
3035
  // abstraction is needed.
3046
- async _processClientMsgFromBackendSession_withExclusiveAccess(session, messages, ctx, defer) {
3036
+ _processClientMsgFromBackendSession_withExclusiveAccess(session, messages, ctx, defer) {
3047
3037
  const toFanOut = [];
3048
3038
  const toReplyImmediately = [];
3049
3039
  const toReplyAfter = [];
@@ -3065,7 +3055,7 @@ var Room = class {
3065
3055
  const scheduleFanOut = (msg) => void toFanOut.push(msg);
3066
3056
  const scheduleReply = (msg) => void toReplyAfter.push(msg);
3067
3057
  for (const msg of messages) {
3068
- await this.handleOne(
3058
+ this.handleOne(
3069
3059
  session,
3070
3060
  msg,
3071
3061
  replyImmediately,
@@ -3088,7 +3078,7 @@ var Room = class {
3088
3078
  toReplyAfter.length = 0;
3089
3079
  }
3090
3080
  }
3091
- async handleOne(session, msg, replyImmediately, scheduleFanOut, scheduleReply, ctx, defer) {
3081
+ handleOne(session, msg, replyImmediately, scheduleFanOut, scheduleReply, ctx, defer) {
3092
3082
  if (!this.mutex.isLocked()) {
3093
3083
  throw new Error("Handling messages requires exclusive access");
3094
3084
  }
@@ -3112,7 +3102,7 @@ var Room = class {
3112
3102
  }
3113
3103
  case _core.ClientMsgCode.FETCH_STORAGE: {
3114
3104
  if (session.version >= 8 /* V8 */) {
3115
- const rawStream = this.storage.loadedDriver.iter_nodes_optimized();
3105
+ const rawStream = this.storage.driver.iter_nodes_optimized();
3116
3106
  for (const chunk of groupNodesForWebSocketMessages(rawStream)) {
3117
3107
  const frame = `{"type":${ServerMsgCode2.STORAGE_CHUNK},"nodes":[${chunk.join(",")}]}`;
3118
3108
  replyImmediately(frame);
@@ -3121,28 +3111,32 @@ var Room = class {
3121
3111
  } else {
3122
3112
  replyImmediately({
3123
3113
  type: ServerMsgCode2.STORAGE_STATE_V7,
3124
- items: Array.from(this.storage.loadedDriver.iter_nodes())
3114
+ items: Array.from(this.storage.driver.iter_nodes())
3125
3115
  });
3126
3116
  }
3127
3117
  break;
3128
3118
  }
3129
3119
  case _core.ClientMsgCode.UPDATE_STORAGE: {
3130
- _optionalChain([this, 'access', _116 => _116.driver, 'access', _117 => _117.bump_storage_version, 'optionalCall', _118 => _118()]);
3131
- const result = await this.storage.applyOps(msg.ops);
3120
+ _optionalChain([this, 'access', _106 => _106.driver, 'access', _107 => _107.bump_storage_version, 'optionalCall', _108 => _108()]);
3121
+ const result = this.storage.applyOps(msg.ops);
3132
3122
  const opsToForward = result.flatMap(
3133
3123
  (r) => r.action === "accepted" ? [r.op] : []
3134
3124
  );
3135
- const opsToSendBack = result.flatMap((r) => {
3136
- switch (r.action) {
3137
- case "ignored":
3138
- return r.ignoredOpId !== void 0 ? [ackIgnoredOp(r.ignoredOpId)] : [];
3139
- case "accepted":
3140
- return r.fix !== void 0 ? [r.fix] : [];
3141
- // istanbul ignore next
3142
- default:
3143
- return _core.assertNever.call(void 0, r, "Unhandled case");
3125
+ const opsToSendBack = result.flatMap(
3126
+ (r) => {
3127
+ switch (r.action) {
3128
+ case "ignored":
3129
+ return r.ignoredOpId !== void 0 ? [ackIgnoredOp(r.ignoredOpId)] : [];
3130
+ case "rectified":
3131
+ return [r.ackOp, r.fix];
3132
+ case "accepted":
3133
+ return r.fix !== void 0 ? [r.fix] : [];
3134
+ // istanbul ignore next
3135
+ default:
3136
+ return _core.assertNever.call(void 0, r, "Unhandled case");
3137
+ }
3144
3138
  }
3145
- });
3139
+ );
3146
3140
  if (opsToForward.length > 0) {
3147
3141
  scheduleFanOut({
3148
3142
  type: ServerMsgCode2.UPDATE_STORAGE,
@@ -3160,7 +3154,7 @@ var Room = class {
3160
3154
  });
3161
3155
  }
3162
3156
  if (opsToForward.length > 0) {
3163
- const p$ = _optionalChain([this, 'access', _119 => _119.hooks, 'access', _120 => _120.postClientMsgStorageDidUpdate, 'optionalCall', _121 => _121(ctx)]);
3157
+ const p$ = _optionalChain([this, 'access', _109 => _109.hooks, 'access', _110 => _110.postClientMsgStorageDidUpdate, 'optionalCall', _111 => _111(ctx)]);
3164
3158
  if (p$) defer(p$);
3165
3159
  }
3166
3160
  break;
@@ -3169,11 +3163,17 @@ var Room = class {
3169
3163
  const vector = msg.vector;
3170
3164
  const guid = msg.guid;
3171
3165
  const isV2 = msg.v2;
3172
- const [update, stateVector, snapshotHash] = await Promise.all([
3173
- this.yjsStorage.getYDocUpdate(this.logger, vector, guid, isV2),
3174
- this.yjsStorage.getYStateVector(this.logger, guid),
3175
- this.yjsStorage.getSnapshotHash(this.logger, { guid, isV2 })
3176
- ]);
3166
+ const update = this.yjsStorage.getYDocUpdate(
3167
+ __privateGet(this, _logger),
3168
+ vector,
3169
+ guid,
3170
+ isV2
3171
+ );
3172
+ const stateVector = this.yjsStorage.getYStateVector(__privateGet(this, _logger), guid);
3173
+ const snapshotHash = this.yjsStorage.getSnapshotHash(__privateGet(this, _logger), {
3174
+ guid,
3175
+ isV2
3176
+ });
3177
3177
  if (update !== null && snapshotHash !== null) {
3178
3178
  replyImmediately({
3179
3179
  type: ServerMsgCode2.UPDATE_YDOC,
@@ -3192,8 +3192,8 @@ var Room = class {
3192
3192
  const update = msg.update;
3193
3193
  const guid = msg.guid;
3194
3194
  const isV2 = msg.v2;
3195
- const [result, error] = await tryCatch(
3196
- this.yjsStorage.addYDocUpdate(this.logger, update, guid, isV2)
3195
+ const [result, error] = tryCatch(
3196
+ () => this.yjsStorage.addYDocUpdate(__privateGet(this, _logger), update, guid, isV2)
3197
3197
  );
3198
3198
  if (error)
3199
3199
  break;
@@ -3211,7 +3211,7 @@ var Room = class {
3211
3211
  defer
3212
3212
  );
3213
3213
  if (result.isUpdated) {
3214
- const p$ = _optionalChain([this, 'access', _122 => _122.hooks, 'access', _123 => _123.postClientMsgYdocDidUpdate, 'optionalCall', _124 => _124(ctx, session)]);
3214
+ const p$ = _optionalChain([this, 'access', _112 => _112.hooks, 'access', _113 => _113.postClientMsgYdocDidUpdate, 'optionalCall', _114 => _114(ctx, session)]);
3215
3215
  if (p$) defer(p$);
3216
3216
  }
3217
3217
  break;
@@ -3219,8 +3219,8 @@ var Room = class {
3219
3219
  // Feed messages
3220
3220
  case FeedMsgCode.FETCH_FEEDS: {
3221
3221
  const fetchMsg = msg;
3222
- const [result, err] = await tryCatch(
3223
- this.listFeeds({
3222
+ const [result, err] = tryCatch(
3223
+ () => this.listFeeds({
3224
3224
  cursor: fetchMsg.cursor,
3225
3225
  since: fetchMsg.since,
3226
3226
  limit: fetchMsg.limit,
@@ -3241,8 +3241,8 @@ var Room = class {
3241
3241
  }
3242
3242
  case FeedMsgCode.FETCH_FEED_MESSAGES: {
3243
3243
  const fetchMsg = msg;
3244
- const [result, err] = await tryCatch(
3245
- this.listFeedMessages(fetchMsg.feedId, {
3244
+ const [result, err] = tryCatch(
3245
+ () => this.listFeedMessages(fetchMsg.feedId, {
3246
3246
  cursor: fetchMsg.cursor,
3247
3247
  since: fetchMsg.since,
3248
3248
  limit: fetchMsg.limit
@@ -3263,8 +3263,8 @@ var Room = class {
3263
3263
  }
3264
3264
  case FeedMsgCode.ADD_FEED: {
3265
3265
  const addMsg = msg;
3266
- const [feed, err] = await tryCatch(
3267
- this.createFeed({
3266
+ const [feed, err] = tryCatch(
3267
+ () => this.createFeed({
3268
3268
  feedId: addMsg.feedId,
3269
3269
  metadata: _nullishCoalesce(addMsg.metadata, () => ( {}))
3270
3270
  })
@@ -3283,14 +3283,14 @@ var Room = class {
3283
3283
  }
3284
3284
  case FeedMsgCode.UPDATE_FEED: {
3285
3285
  const updateMsg = msg;
3286
- const [, metaErr] = await tryCatch(
3287
- this.updateFeedMetadata(updateMsg.feedId, updateMsg.metadata)
3286
+ const [, metaErr] = tryCatch(
3287
+ () => this.updateFeedMetadata(updateMsg.feedId, updateMsg.metadata)
3288
3288
  );
3289
3289
  if (metaErr) {
3290
3290
  replyImmediately(feedFailureServerMsg(updateMsg.requestId, metaErr));
3291
3291
  break;
3292
3292
  }
3293
- const feed = await this.getFeed(updateMsg.feedId);
3293
+ const feed = this.getFeed(updateMsg.feedId);
3294
3294
  if (!feed) {
3295
3295
  replyImmediately(
3296
3296
  feedRequestFailed(
@@ -3310,7 +3310,7 @@ var Room = class {
3310
3310
  }
3311
3311
  case FeedMsgCode.DELETE_FEED: {
3312
3312
  const deleteMsg = msg;
3313
- const [, err] = await tryCatch(this.deleteFeed(deleteMsg.feedId));
3313
+ const [, err] = tryCatch(() => this.deleteFeed(deleteMsg.feedId));
3314
3314
  if (err) {
3315
3315
  replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
3316
3316
  break;
@@ -3325,8 +3325,8 @@ var Room = class {
3325
3325
  }
3326
3326
  case FeedMsgCode.ADD_FEED_MESSAGE: {
3327
3327
  const addMsg = msg;
3328
- const [message, err] = await tryCatch(
3329
- this.addFeedMessage(addMsg.feedId, {
3328
+ const [message, err] = tryCatch(
3329
+ () => this.addFeedMessage(addMsg.feedId, {
3330
3330
  data: addMsg.data,
3331
3331
  id: addMsg.id
3332
3332
  })
@@ -3346,8 +3346,8 @@ var Room = class {
3346
3346
  }
3347
3347
  case FeedMsgCode.UPDATE_FEED_MESSAGE: {
3348
3348
  const updateMsg = msg;
3349
- const [message, err] = await tryCatch(
3350
- this.updateFeedMessage(
3349
+ const [message, err] = tryCatch(
3350
+ () => this.updateFeedMessage(
3351
3351
  updateMsg.feedId,
3352
3352
  updateMsg.messageId,
3353
3353
  updateMsg.data
@@ -3368,8 +3368,8 @@ var Room = class {
3368
3368
  }
3369
3369
  case FeedMsgCode.DELETE_FEED_MESSAGE: {
3370
3370
  const deleteMsg = msg;
3371
- const [, err] = await tryCatch(
3372
- this.deleteFeedMessage(deleteMsg.feedId, deleteMsg.messageId)
3371
+ const [, err] = tryCatch(
3372
+ () => this.deleteFeedMessage(deleteMsg.feedId, deleteMsg.messageId)
3373
3373
  );
3374
3374
  if (err) {
3375
3375
  replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
@@ -3393,6 +3393,7 @@ var Room = class {
3393
3393
  }
3394
3394
  }
3395
3395
  };
3396
+ _logger = new WeakMap();
3396
3397
  __debug2 = new WeakMap();
3397
3398
 
3398
3399