@liveblocks/server 1.4.1 → 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
@@ -826,7 +828,6 @@ function makeMetadataDB(driver) {
826
828
 
827
829
 
828
830
 
829
-
830
831
  var _asyncmutex = require('async-mutex');
831
832
 
832
833
  var _itertools = require('itertools');
@@ -967,6 +968,12 @@ var Logger = class _Logger {
967
968
 
968
969
 
969
970
 
971
+
972
+
973
+
974
+
975
+
976
+
970
977
  // src/lib/text.ts
971
978
  function quote(value) {
972
979
  return value !== void 0 ? `'${value}'` : "???";
@@ -1374,6 +1381,17 @@ var InMemoryDriver = class {
1374
1381
  * Yield all nodes as [id, node] pairs. Must always include the root node.
1375
1382
  */
1376
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
+ },
1377
1395
  /**
1378
1396
  * Return true iff a node with the given id exists. Must return true for "root".
1379
1397
  */
@@ -2035,6 +2053,7 @@ function isLeasedSessionExpired(leasedSession) {
2035
2053
  }
2036
2054
 
2037
2055
  // src/Room.ts
2056
+ var MB = 1024 * 1024;
2038
2057
  var messagesDecoder = _decoders.array.call(void 0, clientMsgDecoder);
2039
2058
  var ServerMsgCode2 = { ..._core.ServerMsgCode, ...FeedMsgCode };
2040
2059
  var HIGHEST_PROTOCOL_VERSION = Math.max(
@@ -2048,6 +2067,11 @@ var SERVER_MSG_CODE_NAMES = Object.fromEntries(
2048
2067
  var BLACK_HOLE = new Logger([
2049
2068
  /* No targets, i.e. black hole logger */
2050
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
+ }
2051
2075
  function collectSideEffects() {
2052
2076
  const deferred = [];
2053
2077
  return {
@@ -2181,7 +2205,7 @@ var BackendSession = class extends BrowserSession {
2181
2205
  super(ticket, socket, debug);
2182
2206
  }
2183
2207
  };
2184
- var __debug2, __allowStreaming;
2208
+ var __debug2;
2185
2209
  var Room = class {
2186
2210
  constructor(meta, options) {
2187
2211
  // ^^^^^^^^^^ User-defined Room Metadata, Session Metadata, and Client Metadata
@@ -2203,29 +2227,27 @@ var Room = class {
2203
2227
  __publicField(this, "sessions", new UniqueMap((s) => s.actor));
2204
2228
  __publicField(this, "hooks");
2205
2229
  __privateAdd(this, __debug2);
2206
- __privateAdd(this, __allowStreaming);
2207
2230
  const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.storage]), () => ( makeNewInMemoryDriver()));
2208
2231
  this.meta = meta;
2209
2232
  this.driver = driver;
2210
2233
  this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.logger]), () => ( BLACK_HOLE));
2211
- __privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.allowStreaming]), () => ( true)));
2212
2234
  this.hooks = {
2213
- 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]), () => ( (() => {
2214
2236
  return {
2215
2237
  allowed: true
2216
2238
  };
2217
2239
  }))),
2218
2240
  // YYY .load() isn't called on the RoomServer yet! As soon as it does, these hooks will get called
2219
- onRoomWillLoad: _optionalChain([options, 'optionalAccess', _66 => _66.hooks, 'optionalAccess', _67 => _67.onRoomWillLoad]),
2220
- onRoomDidLoad: _optionalChain([options, 'optionalAccess', _68 => _68.hooks, 'optionalAccess', _69 => _69.onRoomDidLoad]),
2221
- onRoomWillUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomWillUnload]),
2222
- onRoomDidUnload: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onRoomDidUnload]),
2223
- onSessionDidStart: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidStart]),
2224
- onSessionDidEnd: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.onSessionDidEnd]),
2225
- postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _78 => _78.hooks, 'optionalAccess', _79 => _79.postClientMsgStorageDidUpdate]),
2226
- 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])
2227
2249
  };
2228
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.enableDebugLogging]), () => ( false)));
2250
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.enableDebugLogging]), () => ( false)));
2229
2251
  }
2230
2252
  get loadingState() {
2231
2253
  if (this._loadData$ === null) {
@@ -2299,13 +2321,13 @@ var Room = class {
2299
2321
  * room will be reloaded from storage.
2300
2322
  */
2301
2323
  unload(ctx) {
2302
- _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)]);
2303
2325
  if (this._data) {
2304
2326
  this.storage.unload();
2305
2327
  this.yjsStorage.unload();
2306
2328
  }
2307
2329
  this._loadData$ = null;
2308
- _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)]);
2309
2331
  }
2310
2332
  /**
2311
2333
  * Issues a Ticket with a new/unique actor ID
@@ -2319,17 +2341,17 @@ var Room = class {
2319
2341
  * unused Ticket will simply get garbage collected.
2320
2342
  */
2321
2343
  async createTicket(options) {
2322
- const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.actor]), () => ( this.getNextActor()));
2344
+ const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _88 => _88.actor]), () => ( this.getNextActor()));
2323
2345
  const sessionKey = _nanoid.nanoid.call(void 0, );
2324
- const info = _optionalChain([options, 'optionalAccess', _90 => _90.info]);
2346
+ const info = _optionalChain([options, 'optionalAccess', _89 => _89.info]);
2325
2347
  const ticket = {
2326
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2348
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _90 => _90.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2327
2349
  actor: await actor$,
2328
2350
  sessionKey,
2329
- meta: _optionalChain([options, 'optionalAccess', _92 => _92.meta]),
2330
- publicMeta: _optionalChain([options, 'optionalAccess', _93 => _93.publicMeta]),
2331
- 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 },
2332
- 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"]))
2333
2355
  };
2334
2356
  if (__privateGet(this, __debug2)) {
2335
2357
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
@@ -2463,7 +2485,7 @@ var Room = class {
2463
2485
  ctx,
2464
2486
  defer
2465
2487
  );
2466
- 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)]);
2467
2489
  if (p$) defer(p$);
2468
2490
  }
2469
2491
  /**
@@ -2487,7 +2509,7 @@ var Room = class {
2487
2509
  for (const other of this.otherSessions(key)) {
2488
2510
  other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
2489
2511
  }
2490
- 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)]);
2491
2513
  if (p$) defer(p$);
2492
2514
  }
2493
2515
  }
@@ -2518,7 +2540,7 @@ var Room = class {
2518
2540
  );
2519
2541
  }) {
2520
2542
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2521
- _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()]);
2522
2544
  if (text === "ping") {
2523
2545
  await this.handlePing(key, ctx);
2524
2546
  } else {
@@ -2873,7 +2895,7 @@ var Room = class {
2873
2895
  }
2874
2896
  // Don't ever manually call this!
2875
2897
  async _load(ctx) {
2876
- 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)]);
2877
2899
  const storage = await this._loadStorage();
2878
2900
  const yjsStorage = await this._loadYjsStorage();
2879
2901
  this._data = {
@@ -2881,7 +2903,7 @@ var Room = class {
2881
2903
  storage,
2882
2904
  yjsStorage
2883
2905
  };
2884
- 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)]);
2885
2907
  }
2886
2908
  /**
2887
2909
  * Returns a new, unique, actor ID.
@@ -2921,7 +2943,7 @@ var Room = class {
2921
2943
  }
2922
2944
  const sent = session.sendPong();
2923
2945
  if (sent !== 0) {
2924
- 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)]);
2925
2947
  }
2926
2948
  }
2927
2949
  async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
@@ -2973,7 +2995,13 @@ var Room = class {
2973
2995
  const toReplyImmediately = [];
2974
2996
  const toReplyAfter = [];
2975
2997
  const replyImmediately = (msg) => {
2976
- 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)) {
2977
3005
  for (const m of msg) {
2978
3006
  toReplyImmediately.push(m);
2979
3007
  }
@@ -3031,24 +3059,10 @@ var Room = class {
3031
3059
  }
3032
3060
  case _core.ClientMsgCode.FETCH_STORAGE: {
3033
3061
  if (session.version >= 8 /* V8 */) {
3034
- if (__privateGet(this, __allowStreaming)) {
3035
- const NODES_PER_CHUNK = 250;
3036
- for (const chunk of _itertools.chunked.call(void 0,
3037
- _core.nodeStreamToCompactNodes.call(void 0, this.storage.loadedDriver.iter_nodes()),
3038
- NODES_PER_CHUNK
3039
- )) {
3040
- replyImmediately({
3041
- type: ServerMsgCode2.STORAGE_CHUNK,
3042
- nodes: chunk
3043
- });
3044
- }
3045
- } else {
3046
- replyImmediately({
3047
- type: ServerMsgCode2.STORAGE_CHUNK,
3048
- nodes: Array.from(
3049
- _core.nodeStreamToCompactNodes.call(void 0, this.storage.loadedDriver.iter_nodes())
3050
- )
3051
- });
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);
3052
3066
  }
3053
3067
  replyImmediately({ type: ServerMsgCode2.STORAGE_STREAM_END });
3054
3068
  } else {
@@ -3060,7 +3074,7 @@ var Room = class {
3060
3074
  break;
3061
3075
  }
3062
3076
  case _core.ClientMsgCode.UPDATE_STORAGE: {
3063
- _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()]);
3064
3078
  const result = await this.storage.applyOps(msg.ops);
3065
3079
  const opsToForward = result.flatMap(
3066
3080
  (r) => r.action === "accepted" ? [r.op] : []
@@ -3093,7 +3107,7 @@ var Room = class {
3093
3107
  });
3094
3108
  }
3095
3109
  if (opsToForward.length > 0) {
3096
- 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)]);
3097
3111
  if (p$) defer(p$);
3098
3112
  }
3099
3113
  break;
@@ -3144,7 +3158,7 @@ var Room = class {
3144
3158
  defer
3145
3159
  );
3146
3160
  if (result.isUpdated) {
3147
- 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)]);
3148
3162
  if (p$) defer(p$);
3149
3163
  }
3150
3164
  break;
@@ -3327,7 +3341,6 @@ var Room = class {
3327
3341
  }
3328
3342
  };
3329
3343
  __debug2 = new WeakMap();
3330
- __allowStreaming = new WeakMap();
3331
3344
 
3332
3345
 
3333
3346