@liveblocks/server 1.4.0 → 1.4.2-pre1

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
@@ -129,7 +129,9 @@ var feedMetadataRecordForCreate = _decoders.record.call(void 0,
129
129
  (value) => Object.keys(value).length <= MAX_METADATA_COUNT,
130
130
  `Must be at most ${MAX_METADATA_COUNT} items`
131
131
  );
132
- var optionalFeedMetadataDecoder = _decoders.optional.call(void 0, feedMetadataRecordForCreate);
132
+ var optionalFeedMetadataDecoder = _decoders.optional.call(void 0,
133
+ feedMetadataRecordForCreate
134
+ );
133
135
  var feedMetadataUpdateDecoder = _decoders.record.call(void 0,
134
136
  feedMetadataIdDecoder,
135
137
  feedMetadataNullableValueDecoder
@@ -476,6 +478,7 @@ function* iterJson(key, data, parent, state) {
476
478
  case "LiveMap":
477
479
  yield* iterMap(key, data.data, parent, state);
478
480
  return;
481
+ // istanbul ignore next
479
482
  default:
480
483
  _core.assertNever.call(void 0, data, "Unknown `liveblocksType` field");
481
484
  }
@@ -560,7 +563,7 @@ function buildNode2(snapshot2, id) {
560
563
  } else if (node.type === _core.CrdtType.MAP) {
561
564
  return buildMap2(snapshot2, id);
562
565
  } else {
563
- return node.data;
566
+ return _nullishCoalesce(node.data, () => ( null));
564
567
  }
565
568
  }
566
569
  function buildObject2(snapshot2, id, staticData) {
@@ -604,7 +607,7 @@ function* emit2(snapshot2, id) {
604
607
  } else if (node.type === _core.CrdtType.MAP) {
605
608
  yield* emitMap2(snapshot2, id);
606
609
  } else if (node.type === _core.CrdtType.REGISTER) {
607
- yield JSON.stringify(node.data);
610
+ yield JSON.stringify(_nullishCoalesce(node.data, () => ( null)));
608
611
  }
609
612
  }
610
613
  function* emitObject2(snapshot2, id, staticJson) {
@@ -825,7 +828,6 @@ function makeMetadataDB(driver) {
825
828
 
826
829
 
827
830
 
828
-
829
831
  var _asyncmutex = require('async-mutex');
830
832
 
831
833
  var _itertools = require('itertools');
@@ -940,12 +942,10 @@ var Logger = class _Logger {
940
942
  }
941
943
  });
942
944
  this.o = {
943
- /* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
944
945
  debug: minLevel <= 0 /* DEBUG */ ? makeLogFn(0 /* DEBUG */) : void 0,
945
946
  info: minLevel <= 1 /* INFO */ ? makeLogFn(1 /* INFO */) : void 0,
946
947
  warn: minLevel <= 2 /* WARNING */ ? makeLogFn(2 /* WARNING */) : void 0,
947
948
  error: minLevel <= 3 /* ERROR */ ? makeLogFn(3 /* ERROR */) : void 0
948
- /* eslint-enable @typescript-eslint/no-unsafe-enum-comparison */
949
949
  };
950
950
  this.debug = _nullishCoalesce(this.o.debug, () => ( noop));
951
951
  this.info = _nullishCoalesce(this.o.info, () => ( noop));
@@ -968,6 +968,12 @@ var Logger = class _Logger {
968
968
 
969
969
 
970
970
 
971
+
972
+
973
+
974
+
975
+
976
+
971
977
  // src/lib/text.ts
972
978
  function quote(value) {
973
979
  return value !== void 0 ? `'${value}'` : "???";
@@ -1375,6 +1381,17 @@ var InMemoryDriver = class {
1375
1381
  * Yield all nodes as [id, node] pairs. Must always include the root node.
1376
1382
  */
1377
1383
  iter_nodes: () => nodes,
1384
+ /**
1385
+ * Yield each node as a pre-built CompactNode JSON tuple string.
1386
+ *
1387
+ * This implementation IS the canonical reference for the invariant:
1388
+ * iter_nodes_optimized` ≡ `nodeStreamToCompactNodes(iter_nodes())
1389
+ */
1390
+ *iter_nodes_optimized() {
1391
+ for (const compact of _core.nodeStreamToCompactNodes.call(void 0, nodes)) {
1392
+ yield JSON.stringify(compact);
1393
+ }
1394
+ },
1378
1395
  /**
1379
1396
  * Return true iff a node with the given id exists. Must return true for "root".
1380
1397
  */
@@ -1494,6 +1511,7 @@ function nodeFromCreateChildOp(op2) {
1494
1511
  parentKey: op2.parentKey,
1495
1512
  data: op2.data
1496
1513
  };
1514
+ // istanbul ignore next
1497
1515
  default:
1498
1516
  return _core.assertNever.call(void 0, op2, "Unknown op code");
1499
1517
  }
@@ -1562,6 +1580,7 @@ var Storage = class {
1562
1580
  return await this.applyDeleteObjectKeyOp(op2);
1563
1581
  case _core.OpCode.DELETE_CRDT:
1564
1582
  return await this.applyDeleteCrdtOp(op2);
1583
+ // istanbul ignore next
1565
1584
  default:
1566
1585
  if (process.env.NODE_ENV === "production") {
1567
1586
  return ignore(op2);
@@ -1584,6 +1603,7 @@ var Storage = class {
1584
1603
  if (op2.type === _core.OpCode.CREATE_REGISTER) {
1585
1604
  return ignore(op2);
1586
1605
  }
1606
+ // fall through
1587
1607
  case _core.CrdtType.MAP:
1588
1608
  await this.loadedDriver.set_child(op2.id, node, true);
1589
1609
  return accept(op2);
@@ -1591,6 +1611,7 @@ var Storage = class {
1591
1611
  return this.createChildAsListItem(op2, node);
1592
1612
  case _core.CrdtType.REGISTER:
1593
1613
  return ignore(op2);
1614
+ // istanbul ignore next
1594
1615
  default:
1595
1616
  return _core.assertNever.call(void 0, parent, "Unhandled CRDT type");
1596
1617
  }
@@ -1731,6 +1752,7 @@ var _jsbase64 = require('js-base64');
1731
1752
 
1732
1753
  var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
1733
1754
  var UPDATE_COUNT_THRESHOLD = 1e3;
1755
+ var MERGE_SHRINK_THRESHOLD = 0.8;
1734
1756
  var YjsStorage = class {
1735
1757
  constructor(driver, updateCountThreshold = UPDATE_COUNT_THRESHOLD) {
1736
1758
  __publicField(this, "driver");
@@ -1748,15 +1770,16 @@ var YjsStorage = class {
1748
1770
  await this.driver.delete_y_updates(docId, storedKeys);
1749
1771
  this.storedKeysById.set(docId, [newKey]);
1750
1772
  });
1751
- __publicField(this, "_loadYDocFromDurableStorage", async (doc, docId) => {
1773
+ __publicField(this, "_loadYDocFromDurableStorage", async (_logger, doc, docId) => {
1752
1774
  const docUpdates = Object.fromEntries(
1753
1775
  await this.driver.iter_y_updates(docId)
1754
1776
  );
1755
1777
  const updates = Object.values(docUpdates);
1778
+ const beforeSize = updates.reduce((acc, update) => acc + update.length, 0);
1756
1779
  const newupdate = Y.mergeUpdates(updates);
1757
1780
  const storedKeys = Object.keys(docUpdates);
1758
1781
  Y.applyUpdate(doc, newupdate);
1759
- if (this.shouldCompact(storedKeys)) {
1782
+ if (this.shouldCompactByKeyCount(storedKeys) || this.shouldCompactBySize(beforeSize, newupdate.length)) {
1760
1783
  await this._compactYJSUpdates(doc, docId, storedKeys);
1761
1784
  } else {
1762
1785
  this.storedKeysById.set(docId, storedKeys);
@@ -1775,8 +1798,8 @@ var YjsStorage = class {
1775
1798
  // ------------------------------------------------------------------------------------
1776
1799
  // Public API
1777
1800
  // ------------------------------------------------------------------------------------
1778
- async getYDoc(docId) {
1779
- const doc = await this.loadDocByIdIfNotAlreadyLoaded(docId);
1801
+ async getYDoc(logger, docId) {
1802
+ const doc = await this.loadDocByIdIfNotAlreadyLoaded(logger, docId);
1780
1803
  return doc;
1781
1804
  }
1782
1805
  /**
@@ -1796,7 +1819,7 @@ var YjsStorage = class {
1796
1819
  return _jsbase64.Base64.fromUint8Array(update);
1797
1820
  }
1798
1821
  async getYDocUpdateBinary(logger, stateVector = "", guid, isV2 = false) {
1799
- const doc = guid !== void 0 ? await this.getYSubdoc(guid) : this.doc;
1822
+ const doc = guid !== void 0 ? await this.getYSubdoc(logger, guid) : this.doc;
1800
1823
  if (!doc) {
1801
1824
  return null;
1802
1825
  }
@@ -1813,15 +1836,15 @@ var YjsStorage = class {
1813
1836
  }
1814
1837
  return Y.encodeStateAsUpdate(doc, encodedTargetVector);
1815
1838
  }
1816
- async getYStateVector(guid) {
1817
- const doc = guid !== void 0 ? await this.getYSubdoc(guid) : this.doc;
1839
+ async getYStateVector(logger, guid) {
1840
+ const doc = guid !== void 0 ? await this.getYSubdoc(logger, guid) : this.doc;
1818
1841
  if (!doc) {
1819
1842
  return null;
1820
1843
  }
1821
1844
  return _jsbase64.Base64.fromUint8Array(Y.encodeStateVector(doc));
1822
1845
  }
1823
- async getSnapshotHash(options) {
1824
- const doc = options.guid !== void 0 ? await this.getYSubdoc(options.guid) : this.doc;
1846
+ async getSnapshotHash(logger, options) {
1847
+ const doc = options.guid !== void 0 ? await this.getYSubdoc(logger, options.guid) : this.doc;
1825
1848
  if (!doc) {
1826
1849
  return null;
1827
1850
  }
@@ -1835,7 +1858,7 @@ var YjsStorage = class {
1835
1858
  * snapshotHash: the hash of the new snapshot
1836
1859
  */
1837
1860
  async addYDocUpdate(logger, update, guid, isV2) {
1838
- const doc = guid !== void 0 ? await this.getYSubdoc(guid) : this.doc;
1861
+ const doc = guid !== void 0 ? await this.getYSubdoc(logger, guid) : this.doc;
1839
1862
  if (!doc) {
1840
1863
  throw new Error(`YDoc with guid ${guid} not found`);
1841
1864
  }
@@ -1860,20 +1883,20 @@ var YjsStorage = class {
1860
1883
  );
1861
1884
  }
1862
1885
  }
1863
- loadDocByIdIfNotAlreadyLoaded(docId) {
1886
+ loadDocByIdIfNotAlreadyLoaded(logger, docId) {
1864
1887
  let loaded$ = this.initPromisesById.get(docId);
1865
1888
  let doc = docId === ROOT_YDOC_ID ? this.doc : this.findYSubdocByGuid(docId);
1866
1889
  if (!doc) {
1867
1890
  doc = new Y.Doc();
1868
1891
  }
1869
1892
  if (loaded$ === void 0) {
1870
- loaded$ = this._loadYDocFromDurableStorage(doc, docId);
1893
+ loaded$ = this._loadYDocFromDurableStorage(logger, doc, docId);
1871
1894
  this.initPromisesById.set(docId, loaded$);
1872
1895
  }
1873
1896
  return loaded$;
1874
1897
  }
1875
- async load(_logger) {
1876
- await this.loadDocByIdIfNotAlreadyLoaded(ROOT_YDOC_ID);
1898
+ async load(logger) {
1899
+ await this.loadDocByIdIfNotAlreadyLoaded(logger, ROOT_YDOC_ID);
1877
1900
  }
1878
1901
  /**
1879
1902
  * Unloads the Yjs documents from memory.
@@ -1916,12 +1939,12 @@ var YjsStorage = class {
1916
1939
  );
1917
1940
  }
1918
1941
  // gets a subdoc, it will be loaded if not already loaded
1919
- async getYSubdoc(guid) {
1942
+ async getYSubdoc(logger, guid) {
1920
1943
  const subdoc = this.findYSubdocByGuid(guid);
1921
1944
  if (!subdoc) {
1922
1945
  return null;
1923
1946
  }
1924
- await this.loadDocByIdIfNotAlreadyLoaded(guid);
1947
+ await this.loadDocByIdIfNotAlreadyLoaded(logger, guid);
1925
1948
  return subdoc;
1926
1949
  }
1927
1950
  // When the YJS doc changes, update it in durable storage
@@ -1929,7 +1952,7 @@ var YjsStorage = class {
1929
1952
  const v1update = isV2 ? Y.convertUpdateFormatV2ToV1(update) : update;
1930
1953
  const docId = doc.guid === this.doc.guid ? ROOT_YDOC_ID : doc.guid;
1931
1954
  const storedKeys = this.storedKeysById.get(docId);
1932
- if (this.shouldCompact(storedKeys)) {
1955
+ if (this.shouldCompactByKeyCount(storedKeys)) {
1933
1956
  await this._compactYJSUpdates(doc, docId, storedKeys || []);
1934
1957
  return;
1935
1958
  }
@@ -1941,7 +1964,10 @@ var YjsStorage = class {
1941
1964
  storedKeys.push(newKey);
1942
1965
  }
1943
1966
  }
1944
- shouldCompact(storedKeys) {
1967
+ shouldCompactBySize(beforeSize, afterSize) {
1968
+ return beforeSize * MERGE_SHRINK_THRESHOLD > afterSize;
1969
+ }
1970
+ shouldCompactByKeyCount(storedKeys) {
1945
1971
  if (!storedKeys) {
1946
1972
  return false;
1947
1973
  }
@@ -2027,6 +2053,7 @@ function isLeasedSessionExpired(leasedSession) {
2027
2053
  }
2028
2054
 
2029
2055
  // src/Room.ts
2056
+ var MB = 1024 * 1024;
2030
2057
  var messagesDecoder = _decoders.array.call(void 0, clientMsgDecoder);
2031
2058
  var ServerMsgCode2 = { ..._core.ServerMsgCode, ...FeedMsgCode };
2032
2059
  var HIGHEST_PROTOCOL_VERSION = Math.max(
@@ -2040,6 +2067,11 @@ var SERVER_MSG_CODE_NAMES = Object.fromEntries(
2040
2067
  var BLACK_HOLE = new Logger([
2041
2068
  /* No targets, i.e. black hole logger */
2042
2069
  ]);
2070
+ function groupNodesForWebSocketMessages(input) {
2071
+ const MAX_SIZE = 16 * MB;
2072
+ const idealSize = (chunkIndex) => chunkIndex < 3 ? 1 * MB : Math.min(8, chunkIndex - 1) * MB;
2073
+ return _itertools.chunkedByCost.call(void 0, input, (tup) => tup.length, MAX_SIZE, idealSize);
2074
+ }
2043
2075
  function collectSideEffects() {
2044
2076
  const deferred = [];
2045
2077
  return {
@@ -2173,7 +2205,7 @@ var BackendSession = class extends BrowserSession {
2173
2205
  super(ticket, socket, debug);
2174
2206
  }
2175
2207
  };
2176
- var __debug2, __allowStreaming;
2208
+ var __debug2;
2177
2209
  var Room = class {
2178
2210
  constructor(meta, options) {
2179
2211
  // ^^^^^^^^^^ User-defined Room Metadata, Session Metadata, and Client Metadata
@@ -2195,29 +2227,27 @@ var Room = class {
2195
2227
  __publicField(this, "sessions", new UniqueMap((s) => s.actor));
2196
2228
  __publicField(this, "hooks");
2197
2229
  __privateAdd(this, __debug2);
2198
- __privateAdd(this, __allowStreaming);
2199
2230
  const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.storage]), () => ( makeNewInMemoryDriver()));
2200
2231
  this.meta = meta;
2201
2232
  this.driver = driver;
2202
2233
  this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.logger]), () => ( BLACK_HOLE));
2203
- __privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.allowStreaming]), () => ( true)));
2204
2234
  this.hooks = {
2205
- isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _64 => _64.hooks, 'optionalAccess', _65 => _65.isClientMsgAllowed]), () => ( (() => {
2235
+ isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.hooks, 'optionalAccess', _64 => _64.isClientMsgAllowed]), () => ( (() => {
2206
2236
  return {
2207
2237
  allowed: true
2208
2238
  };
2209
2239
  }))),
2210
2240
  // YYY .load() isn't called on the RoomServer yet! As soon as it does, these hooks will get called
2211
- onRoomWillLoad: _optionalChain([options, 'optionalAccess', _66 => _66.hooks, 'optionalAccess', _67 => _67.onRoomWillLoad]),
2212
- onRoomDidLoad: _optionalChain([options, 'optionalAccess', _68 => _68.hooks, 'optionalAccess', _69 => _69.onRoomDidLoad]),
2213
- onRoomWillUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomWillUnload]),
2214
- onRoomDidUnload: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onRoomDidUnload]),
2215
- onSessionDidStart: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidStart]),
2216
- onSessionDidEnd: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.onSessionDidEnd]),
2217
- postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _78 => _78.hooks, 'optionalAccess', _79 => _79.postClientMsgStorageDidUpdate]),
2218
- postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _80 => _80.hooks, 'optionalAccess', _81 => _81.postClientMsgYdocDidUpdate])
2241
+ onRoomWillLoad: _optionalChain([options, 'optionalAccess', _65 => _65.hooks, 'optionalAccess', _66 => _66.onRoomWillLoad]),
2242
+ onRoomDidLoad: _optionalChain([options, 'optionalAccess', _67 => _67.hooks, 'optionalAccess', _68 => _68.onRoomDidLoad]),
2243
+ onRoomWillUnload: _optionalChain([options, 'optionalAccess', _69 => _69.hooks, 'optionalAccess', _70 => _70.onRoomWillUnload]),
2244
+ onRoomDidUnload: _optionalChain([options, 'optionalAccess', _71 => _71.hooks, 'optionalAccess', _72 => _72.onRoomDidUnload]),
2245
+ onSessionDidStart: _optionalChain([options, 'optionalAccess', _73 => _73.hooks, 'optionalAccess', _74 => _74.onSessionDidStart]),
2246
+ onSessionDidEnd: _optionalChain([options, 'optionalAccess', _75 => _75.hooks, 'optionalAccess', _76 => _76.onSessionDidEnd]),
2247
+ postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _77 => _77.hooks, 'optionalAccess', _78 => _78.postClientMsgStorageDidUpdate]),
2248
+ postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _79 => _79.hooks, 'optionalAccess', _80 => _80.postClientMsgYdocDidUpdate])
2219
2249
  };
2220
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.enableDebugLogging]), () => ( false)));
2250
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.enableDebugLogging]), () => ( false)));
2221
2251
  }
2222
2252
  get loadingState() {
2223
2253
  if (this._loadData$ === null) {
@@ -2291,13 +2321,13 @@ var Room = class {
2291
2321
  * room will be reloaded from storage.
2292
2322
  */
2293
2323
  unload(ctx) {
2294
- _optionalChain([this, 'access', _83 => _83.hooks, 'access', _84 => _84.onRoomWillUnload, 'optionalCall', _85 => _85(ctx)]);
2324
+ _optionalChain([this, 'access', _82 => _82.hooks, 'access', _83 => _83.onRoomWillUnload, 'optionalCall', _84 => _84(ctx)]);
2295
2325
  if (this._data) {
2296
2326
  this.storage.unload();
2297
2327
  this.yjsStorage.unload();
2298
2328
  }
2299
2329
  this._loadData$ = null;
2300
- _optionalChain([this, 'access', _86 => _86.hooks, 'access', _87 => _87.onRoomDidUnload, 'optionalCall', _88 => _88(ctx)]);
2330
+ _optionalChain([this, 'access', _85 => _85.hooks, 'access', _86 => _86.onRoomDidUnload, 'optionalCall', _87 => _87(ctx)]);
2301
2331
  }
2302
2332
  /**
2303
2333
  * Issues a Ticket with a new/unique actor ID
@@ -2311,17 +2341,17 @@ var Room = class {
2311
2341
  * unused Ticket will simply get garbage collected.
2312
2342
  */
2313
2343
  async createTicket(options) {
2314
- const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.actor]), () => ( this.getNextActor()));
2344
+ const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _88 => _88.actor]), () => ( this.getNextActor()));
2315
2345
  const sessionKey = _nanoid.nanoid.call(void 0, );
2316
- const info = _optionalChain([options, 'optionalAccess', _90 => _90.info]);
2346
+ const info = _optionalChain([options, 'optionalAccess', _89 => _89.info]);
2317
2347
  const ticket = {
2318
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2348
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _90 => _90.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2319
2349
  actor: await actor$,
2320
2350
  sessionKey,
2321
- meta: _optionalChain([options, 'optionalAccess', _92 => _92.meta]),
2322
- publicMeta: _optionalChain([options, 'optionalAccess', _93 => _93.publicMeta]),
2323
- user: _optionalChain([options, 'optionalAccess', _94 => _94.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _95 => _95.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
2324
- scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _96 => _96.scopes]), () => ( ["room:write"]))
2351
+ meta: _optionalChain([options, 'optionalAccess', _91 => _91.meta]),
2352
+ publicMeta: _optionalChain([options, 'optionalAccess', _92 => _92.publicMeta]),
2353
+ 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 },
2354
+ scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _95 => _95.scopes]), () => ( ["room:write"]))
2325
2355
  };
2326
2356
  if (__privateGet(this, __debug2)) {
2327
2357
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
@@ -2455,7 +2485,7 @@ var Room = class {
2455
2485
  ctx,
2456
2486
  defer
2457
2487
  );
2458
- const p$ = _optionalChain([this, 'access', _97 => _97.hooks, 'access', _98 => _98.onSessionDidStart, 'optionalCall', _99 => _99(newSession, ctx)]);
2488
+ const p$ = _optionalChain([this, 'access', _96 => _96.hooks, 'access', _97 => _97.onSessionDidStart, 'optionalCall', _98 => _98(newSession, ctx)]);
2459
2489
  if (p$) defer(p$);
2460
2490
  }
2461
2491
  /**
@@ -2479,7 +2509,7 @@ var Room = class {
2479
2509
  for (const other of this.otherSessions(key)) {
2480
2510
  other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
2481
2511
  }
2482
- const p$ = _optionalChain([this, 'access', _100 => _100.hooks, 'access', _101 => _101.onSessionDidEnd, 'optionalCall', _102 => _102(session, ctx)]);
2512
+ const p$ = _optionalChain([this, 'access', _99 => _99.hooks, 'access', _100 => _100.onSessionDidEnd, 'optionalCall', _101 => _101(session, ctx)]);
2483
2513
  if (p$) defer(p$);
2484
2514
  }
2485
2515
  }
@@ -2510,7 +2540,7 @@ var Room = class {
2510
2540
  );
2511
2541
  }) {
2512
2542
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2513
- _optionalChain([this, 'access', _103 => _103.sessions, 'access', _104 => _104.get, 'call', _105 => _105(key), 'optionalAccess', _106 => _106.markActive, 'call', _107 => _107()]);
2543
+ _optionalChain([this, 'access', _102 => _102.sessions, 'access', _103 => _103.get, 'call', _104 => _104(key), 'optionalAccess', _105 => _105.markActive, 'call', _106 => _106()]);
2514
2544
  if (text === "ping") {
2515
2545
  await this.handlePing(key, ctx);
2516
2546
  } else {
@@ -2865,7 +2895,7 @@ var Room = class {
2865
2895
  }
2866
2896
  // Don't ever manually call this!
2867
2897
  async _load(ctx) {
2868
- await _optionalChain([this, 'access', _108 => _108.hooks, 'access', _109 => _109.onRoomWillLoad, 'optionalCall', _110 => _110(ctx)]);
2898
+ await _optionalChain([this, 'access', _107 => _107.hooks, 'access', _108 => _108.onRoomWillLoad, 'optionalCall', _109 => _109(ctx)]);
2869
2899
  const storage = await this._loadStorage();
2870
2900
  const yjsStorage = await this._loadYjsStorage();
2871
2901
  this._data = {
@@ -2873,7 +2903,7 @@ var Room = class {
2873
2903
  storage,
2874
2904
  yjsStorage
2875
2905
  };
2876
- await _optionalChain([this, 'access', _111 => _111.hooks, 'access', _112 => _112.onRoomDidLoad, 'optionalCall', _113 => _113(ctx)]);
2906
+ await _optionalChain([this, 'access', _110 => _110.hooks, 'access', _111 => _111.onRoomDidLoad, 'optionalCall', _112 => _112(ctx)]);
2877
2907
  }
2878
2908
  /**
2879
2909
  * Returns a new, unique, actor ID.
@@ -2905,7 +2935,6 @@ var Room = class {
2905
2935
  * @internal
2906
2936
  * Handles an incoming ping, by sending a pong back.
2907
2937
  */
2908
- // eslint-disable-next-line @typescript-eslint/require-await
2909
2938
  async handlePing(sessionKey, ctx) {
2910
2939
  const session = this.sessions.get(sessionKey);
2911
2940
  if (session === void 0) {
@@ -2914,7 +2943,7 @@ var Room = class {
2914
2943
  }
2915
2944
  const sent = session.sendPong();
2916
2945
  if (sent !== 0) {
2917
- await _optionalChain([this, 'access', _114 => _114.hooks, 'access', _115 => _115.onDidPong, 'optionalCall', _116 => _116(ctx)]);
2946
+ await _optionalChain([this, 'access', _113 => _113.hooks, 'access', _114 => _114.onDidPong, 'optionalCall', _115 => _115(ctx)]);
2918
2947
  }
2919
2948
  }
2920
2949
  async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
@@ -2966,7 +2995,13 @@ var Room = class {
2966
2995
  const toReplyImmediately = [];
2967
2996
  const toReplyAfter = [];
2968
2997
  const replyImmediately = (msg) => {
2969
- if (Array.isArray(msg)) {
2998
+ if (typeof msg === "string") {
2999
+ if (toReplyImmediately.length > 0) {
3000
+ session.send(toReplyImmediately);
3001
+ toReplyImmediately.length = 0;
3002
+ }
3003
+ session.send(msg);
3004
+ } else if (Array.isArray(msg)) {
2970
3005
  for (const m of msg) {
2971
3006
  toReplyImmediately.push(m);
2972
3007
  }
@@ -3024,24 +3059,10 @@ var Room = class {
3024
3059
  }
3025
3060
  case _core.ClientMsgCode.FETCH_STORAGE: {
3026
3061
  if (session.version >= 8 /* V8 */) {
3027
- if (__privateGet(this, __allowStreaming)) {
3028
- const NODES_PER_CHUNK = 250;
3029
- for (const chunk of _itertools.chunked.call(void 0,
3030
- _core.nodeStreamToCompactNodes.call(void 0, this.storage.loadedDriver.iter_nodes()),
3031
- NODES_PER_CHUNK
3032
- )) {
3033
- replyImmediately({
3034
- type: ServerMsgCode2.STORAGE_CHUNK,
3035
- nodes: chunk
3036
- });
3037
- }
3038
- } else {
3039
- replyImmediately({
3040
- type: ServerMsgCode2.STORAGE_CHUNK,
3041
- nodes: Array.from(
3042
- _core.nodeStreamToCompactNodes.call(void 0, this.storage.loadedDriver.iter_nodes())
3043
- )
3044
- });
3062
+ const rawStream = this.storage.loadedDriver.iter_nodes_optimized();
3063
+ for (const chunk of groupNodesForWebSocketMessages(rawStream)) {
3064
+ const frame = `{"type":${ServerMsgCode2.STORAGE_CHUNK},"nodes":[${chunk.join(",")}]}`;
3065
+ replyImmediately(frame);
3045
3066
  }
3046
3067
  replyImmediately({ type: ServerMsgCode2.STORAGE_STREAM_END });
3047
3068
  } else {
@@ -3053,7 +3074,7 @@ var Room = class {
3053
3074
  break;
3054
3075
  }
3055
3076
  case _core.ClientMsgCode.UPDATE_STORAGE: {
3056
- _optionalChain([this, 'access', _117 => _117.driver, 'access', _118 => _118.bump_storage_version, 'optionalCall', _119 => _119()]);
3077
+ _optionalChain([this, 'access', _116 => _116.driver, 'access', _117 => _117.bump_storage_version, 'optionalCall', _118 => _118()]);
3057
3078
  const result = await this.storage.applyOps(msg.ops);
3058
3079
  const opsToForward = result.flatMap(
3059
3080
  (r) => r.action === "accepted" ? [r.op] : []
@@ -3064,6 +3085,7 @@ var Room = class {
3064
3085
  return r.ignoredOpId !== void 0 ? [ackIgnoredOp(r.ignoredOpId)] : [];
3065
3086
  case "accepted":
3066
3087
  return r.fix !== void 0 ? [r.fix] : [];
3088
+ // istanbul ignore next
3067
3089
  default:
3068
3090
  return _core.assertNever.call(void 0, r, "Unhandled case");
3069
3091
  }
@@ -3085,7 +3107,7 @@ var Room = class {
3085
3107
  });
3086
3108
  }
3087
3109
  if (opsToForward.length > 0) {
3088
- const p$ = _optionalChain([this, 'access', _120 => _120.hooks, 'access', _121 => _121.postClientMsgStorageDidUpdate, 'optionalCall', _122 => _122(ctx)]);
3110
+ const p$ = _optionalChain([this, 'access', _119 => _119.hooks, 'access', _120 => _120.postClientMsgStorageDidUpdate, 'optionalCall', _121 => _121(ctx)]);
3089
3111
  if (p$) defer(p$);
3090
3112
  }
3091
3113
  break;
@@ -3096,8 +3118,8 @@ var Room = class {
3096
3118
  const isV2 = msg.v2;
3097
3119
  const [update, stateVector, snapshotHash] = await Promise.all([
3098
3120
  this.yjsStorage.getYDocUpdate(this.logger, vector, guid, isV2),
3099
- this.yjsStorage.getYStateVector(guid),
3100
- this.yjsStorage.getSnapshotHash({ guid, isV2 })
3121
+ this.yjsStorage.getYStateVector(this.logger, guid),
3122
+ this.yjsStorage.getSnapshotHash(this.logger, { guid, isV2 })
3101
3123
  ]);
3102
3124
  if (update !== null && snapshotHash !== null) {
3103
3125
  replyImmediately({
@@ -3136,11 +3158,12 @@ var Room = class {
3136
3158
  defer
3137
3159
  );
3138
3160
  if (result.isUpdated) {
3139
- const p$ = _optionalChain([this, 'access', _123 => _123.hooks, 'access', _124 => _124.postClientMsgYdocDidUpdate, 'optionalCall', _125 => _125(ctx, session)]);
3161
+ const p$ = _optionalChain([this, 'access', _122 => _122.hooks, 'access', _123 => _123.postClientMsgYdocDidUpdate, 'optionalCall', _124 => _124(ctx, session)]);
3140
3162
  if (p$) defer(p$);
3141
3163
  }
3142
3164
  break;
3143
3165
  }
3166
+ // Feed messages
3144
3167
  case FeedMsgCode.FETCH_FEEDS: {
3145
3168
  const fetchMsg = msg;
3146
3169
  const [result, err] = await tryCatch(
@@ -3190,8 +3213,7 @@ var Room = class {
3190
3213
  const [feed, err] = await tryCatch(
3191
3214
  this.createFeed({
3192
3215
  feedId: addMsg.feedId,
3193
- metadata: _nullishCoalesce(addMsg.metadata, () => ( {})),
3194
- timestamp: addMsg.timestamp
3216
+ metadata: _nullishCoalesce(addMsg.metadata, () => ( {}))
3195
3217
  })
3196
3218
  );
3197
3219
  if (err) {
@@ -3253,8 +3275,7 @@ var Room = class {
3253
3275
  const [message, err] = await tryCatch(
3254
3276
  this.addFeedMessage(addMsg.feedId, {
3255
3277
  data: addMsg.data,
3256
- id: addMsg.id,
3257
- timestamp: addMsg.timestamp
3278
+ id: addMsg.id
3258
3279
  })
3259
3280
  );
3260
3281
  if (err) {
@@ -3276,8 +3297,7 @@ var Room = class {
3276
3297
  this.updateFeedMessage(
3277
3298
  updateMsg.feedId,
3278
3299
  updateMsg.messageId,
3279
- updateMsg.data,
3280
- updateMsg.timestamp
3300
+ updateMsg.data
3281
3301
  )
3282
3302
  );
3283
3303
  if (err) {
@@ -3321,7 +3341,6 @@ var Room = class {
3321
3341
  }
3322
3342
  };
3323
3343
  __debug2 = new WeakMap();
3324
- __allowStreaming = new WeakMap();
3325
3344
 
3326
3345
 
3327
3346