@liveblocks/server 1.1.1-pnpmtest1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1448,7 +1448,7 @@ var YjsStorage = class {
1448
1448
  let encodedTargetVector;
1449
1449
  try {
1450
1450
  encodedTargetVector = stateVector.length > 0 ? _jsbase64.Base64.toUint8Array(stateVector) : void 0;
1451
- } catch (e) {
1451
+ } catch (e2) {
1452
1452
  logger.warn(
1453
1453
  "Could not get update from passed vector, returning all updates"
1454
1454
  );
@@ -1722,6 +1722,7 @@ var BrowserSession = class {
1722
1722
  // Metadata sent to client in ROOM_STATE message's "meta" field
1723
1723
  __privateAdd(this, __socket);
1724
1724
  __privateAdd(this, __debug);
1725
+ /** Updated on every incoming message (including pings) via handleData(). Used for idle timeout detection. */
1725
1726
  __privateAdd(this, __lastActiveAt);
1726
1727
  // We keep a status in-memory in the session of whether we already sent a rejected ops message to the client.
1727
1728
  __privateAdd(this, __hasNotifiedClientStorageUpdateError);
@@ -1733,15 +1734,15 @@ var BrowserSession = class {
1733
1734
  this.publicMeta = ticket.publicMeta;
1734
1735
  __privateSet(this, __socket, socket);
1735
1736
  __privateSet(this, __debug, debug);
1736
- const now = _nullishCoalesce(createdAt, () => ( /* @__PURE__ */ new Date()));
1737
+ const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _49 => _49.getTime, 'call', _50 => _50()]), () => ( Date.now()));
1737
1738
  this.createdAt = now;
1738
1739
  __privateSet(this, __lastActiveAt, now);
1739
1740
  __privateSet(this, __hasNotifiedClientStorageUpdateError, false);
1740
1741
  }
1741
1742
  get lastActiveAt() {
1742
- const lastPing = _optionalChain([__privateGet, 'call', _49 => _49(this, __socket), 'access', _50 => _50.getLastPongTimestamp, 'optionalCall', _51 => _51()]);
1743
- if (lastPing && lastPing > __privateGet(this, __lastActiveAt)) {
1744
- return lastPing;
1743
+ const lastPing = _optionalChain([__privateGet, 'call', _51 => _51(this, __socket), 'access', _52 => _52.getLastPongTimestamp, 'optionalCall', _53 => _53()]);
1744
+ if (lastPing && lastPing.getTime() > __privateGet(this, __lastActiveAt)) {
1745
+ return lastPing.getTime();
1745
1746
  } else {
1746
1747
  return __privateGet(this, __lastActiveAt);
1747
1748
  }
@@ -1749,10 +1750,9 @@ var BrowserSession = class {
1749
1750
  get hasNotifiedClientStorageUpdateError() {
1750
1751
  return __privateGet(this, __hasNotifiedClientStorageUpdateError);
1751
1752
  }
1752
- markActive(now = /* @__PURE__ */ new Date()) {
1753
- if (now > __privateGet(this, __lastActiveAt)) {
1754
- __privateSet(this, __lastActiveAt, now);
1755
- }
1753
+ /** @internal - This should have to be called only from Room, never externally */
1754
+ markActive(now) {
1755
+ __privateSet(this, __lastActiveAt, now ? now.getTime() : Date.now());
1756
1756
  }
1757
1757
  setHasNotifiedClientStorageUpdateError() {
1758
1758
  __privateSet(this, __hasNotifiedClientStorageUpdateError, true);
@@ -1824,6 +1824,15 @@ var Room = class {
1824
1824
  __publicField(this, "meta");
1825
1825
  __publicField(this, "driver");
1826
1826
  __publicField(this, "logger");
1827
+ /**
1828
+ * While a room is in "maintenance mode", all WebSocket connections to the
1829
+ * room should be rejected until it's pulled out of maintenance mode again.
1830
+ * Maintenance mode should only last a couple of milliseconds, typically.
1831
+ *
1832
+ * This mutex ensures that concurrent destructive operations (like
1833
+ * init-storage, storage-reset, etc.) cannot interfere with one another.
1834
+ */
1835
+ __publicField(this, "_maintenanceMode", new (0, _asyncmutex.Mutex)());
1827
1836
  __publicField(this, "_loadData$", null);
1828
1837
  __publicField(this, "_data", null);
1829
1838
  __publicField(this, "_qsize", 0);
@@ -1831,28 +1840,28 @@ var Room = class {
1831
1840
  __publicField(this, "hooks");
1832
1841
  __privateAdd(this, __debug2);
1833
1842
  __privateAdd(this, __allowStreaming);
1834
- const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _52 => _52.storage]), () => ( makeNewInMemoryDriver()));
1843
+ const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _54 => _54.storage]), () => ( makeNewInMemoryDriver()));
1835
1844
  this.meta = meta;
1836
1845
  this.driver = driver;
1837
- this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _53 => _53.logger]), () => ( BLACK_HOLE));
1838
- __privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _54 => _54.allowStreaming]), () => ( true)));
1846
+ this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _55 => _55.logger]), () => ( BLACK_HOLE));
1847
+ __privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _56 => _56.allowStreaming]), () => ( true)));
1839
1848
  this.hooks = {
1840
- isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _55 => _55.hooks, 'optionalAccess', _56 => _56.isClientMsgAllowed]), () => ( (() => {
1849
+ isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _57 => _57.hooks, 'optionalAccess', _58 => _58.isClientMsgAllowed]), () => ( (() => {
1841
1850
  return {
1842
1851
  allowed: true
1843
1852
  };
1844
1853
  }))),
1845
1854
  // YYY .load() isn't called on the RoomServer yet! As soon as it does, these hooks will get called
1846
- onRoomWillLoad: _optionalChain([options, 'optionalAccess', _57 => _57.hooks, 'optionalAccess', _58 => _58.onRoomWillLoad]),
1847
- onRoomDidLoad: _optionalChain([options, 'optionalAccess', _59 => _59.hooks, 'optionalAccess', _60 => _60.onRoomDidLoad]),
1848
- onRoomWillUnload: _optionalChain([options, 'optionalAccess', _61 => _61.hooks, 'optionalAccess', _62 => _62.onRoomWillUnload]),
1849
- onRoomDidUnload: _optionalChain([options, 'optionalAccess', _63 => _63.hooks, 'optionalAccess', _64 => _64.onRoomDidUnload]),
1850
- onSessionDidStart: _optionalChain([options, 'optionalAccess', _65 => _65.hooks, 'optionalAccess', _66 => _66.onSessionDidStart]),
1851
- onSessionDidEnd: _optionalChain([options, 'optionalAccess', _67 => _67.hooks, 'optionalAccess', _68 => _68.onSessionDidEnd]),
1852
- postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _69 => _69.hooks, 'optionalAccess', _70 => _70.postClientMsgStorageDidUpdate]),
1853
- postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _71 => _71.hooks, 'optionalAccess', _72 => _72.postClientMsgYdocDidUpdate])
1855
+ onRoomWillLoad: _optionalChain([options, 'optionalAccess', _59 => _59.hooks, 'optionalAccess', _60 => _60.onRoomWillLoad]),
1856
+ onRoomDidLoad: _optionalChain([options, 'optionalAccess', _61 => _61.hooks, 'optionalAccess', _62 => _62.onRoomDidLoad]),
1857
+ onRoomWillUnload: _optionalChain([options, 'optionalAccess', _63 => _63.hooks, 'optionalAccess', _64 => _64.onRoomWillUnload]),
1858
+ onRoomDidUnload: _optionalChain([options, 'optionalAccess', _65 => _65.hooks, 'optionalAccess', _66 => _66.onRoomDidUnload]),
1859
+ onSessionDidStart: _optionalChain([options, 'optionalAccess', _67 => _67.hooks, 'optionalAccess', _68 => _68.onSessionDidStart]),
1860
+ onSessionDidEnd: _optionalChain([options, 'optionalAccess', _69 => _69.hooks, 'optionalAccess', _70 => _70.onSessionDidEnd]),
1861
+ postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _71 => _71.hooks, 'optionalAccess', _72 => _72.postClientMsgStorageDidUpdate]),
1862
+ postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _73 => _73.hooks, 'optionalAccess', _74 => _74.postClientMsgYdocDidUpdate])
1854
1863
  };
1855
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _73 => _73.enableDebugLogging]), () => ( false)));
1864
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _75 => _75.enableDebugLogging]), () => ( false)));
1856
1865
  }
1857
1866
  get loadingState() {
1858
1867
  if (this._loadData$ === null) {
@@ -1884,6 +1893,24 @@ var Room = class {
1884
1893
  }
1885
1894
  // prettier-ignore
1886
1895
  // ------------------------------------------------------------------------------------
1896
+ // Maintenance mode
1897
+ // ------------------------------------------------------------------------------------
1898
+ /**
1899
+ * Returns true if the room is currently in maintenance mode.
1900
+ * When in maintenance mode, callers should refuse new WebSocket connections.
1901
+ */
1902
+ get isInMaintenance() {
1903
+ return this._maintenanceMode.isLocked();
1904
+ }
1905
+ /**
1906
+ * Tries to enter maintenance mode and run the given callback exclusively.
1907
+ * If the room is already in maintenance mode, throws E_ALREADY_LOCKED
1908
+ * immediately instead of queuing the request.
1909
+ */
1910
+ async runInMaintenanceMode(callback) {
1911
+ return _asyncmutex.tryAcquire.call(void 0, this._maintenanceMode).runExclusive(callback);
1912
+ }
1913
+ // ------------------------------------------------------------------------------------
1887
1914
  // Public API
1888
1915
  // ------------------------------------------------------------------------------------
1889
1916
  /**
@@ -1908,13 +1935,13 @@ var Room = class {
1908
1935
  * room will be reloaded from storage.
1909
1936
  */
1910
1937
  unload(ctx) {
1911
- _optionalChain([this, 'access', _74 => _74.hooks, 'access', _75 => _75.onRoomWillUnload, 'optionalCall', _76 => _76(ctx)]);
1938
+ _optionalChain([this, 'access', _76 => _76.hooks, 'access', _77 => _77.onRoomWillUnload, 'optionalCall', _78 => _78(ctx)]);
1912
1939
  if (this._data) {
1913
1940
  this.storage.unload();
1914
1941
  this.yjsStorage.unload();
1915
1942
  }
1916
1943
  this._loadData$ = null;
1917
- _optionalChain([this, 'access', _77 => _77.hooks, 'access', _78 => _78.onRoomDidUnload, 'optionalCall', _79 => _79(ctx)]);
1944
+ _optionalChain([this, 'access', _79 => _79.hooks, 'access', _80 => _80.onRoomDidUnload, 'optionalCall', _81 => _81(ctx)]);
1918
1945
  }
1919
1946
  /**
1920
1947
  * Issues a Ticket with a new/unique actor ID
@@ -1928,17 +1955,17 @@ var Room = class {
1928
1955
  * unused Ticket will simply get garbage collected.
1929
1956
  */
1930
1957
  async createTicket(options) {
1931
- const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.actor]), () => ( this.getNextActor()));
1958
+ const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.actor]), () => ( this.getNextActor()));
1932
1959
  const sessionKey = _nanoid.nanoid.call(void 0, );
1933
- const info = _optionalChain([options, 'optionalAccess', _81 => _81.info]);
1960
+ const info = _optionalChain([options, 'optionalAccess', _83 => _83.info]);
1934
1961
  const ticket = {
1935
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
1962
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
1936
1963
  actor: await actor$,
1937
1964
  sessionKey,
1938
- meta: _optionalChain([options, 'optionalAccess', _83 => _83.meta]),
1939
- publicMeta: _optionalChain([options, 'optionalAccess', _84 => _84.publicMeta]),
1940
- user: _optionalChain([options, 'optionalAccess', _85 => _85.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
1941
- scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _87 => _87.scopes]), () => ( ["room:write"]))
1965
+ meta: _optionalChain([options, 'optionalAccess', _85 => _85.meta]),
1966
+ publicMeta: _optionalChain([options, 'optionalAccess', _86 => _86.publicMeta]),
1967
+ user: _optionalChain([options, 'optionalAccess', _87 => _87.id]) ? { id: options.id, info } : { anonymousId: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _88 => _88.anonymousId]), () => ( _nanoid.nanoid.call(void 0, ))), info },
1968
+ scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.scopes]), () => ( ["room:write"]))
1942
1969
  };
1943
1970
  if (__privateGet(this, __debug2)) {
1944
1971
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
@@ -2072,7 +2099,7 @@ var Room = class {
2072
2099
  ctx,
2073
2100
  defer
2074
2101
  );
2075
- const p$ = _optionalChain([this, 'access', _88 => _88.hooks, 'access', _89 => _89.onSessionDidStart, 'optionalCall', _90 => _90(newSession, ctx)]);
2102
+ const p$ = _optionalChain([this, 'access', _90 => _90.hooks, 'access', _91 => _91.onSessionDidStart, 'optionalCall', _92 => _92(newSession, ctx)]);
2076
2103
  if (p$) defer(p$);
2077
2104
  }
2078
2105
  /**
@@ -2096,7 +2123,7 @@ var Room = class {
2096
2123
  for (const other of this.otherSessions(key)) {
2097
2124
  other.send({ type: _core.ServerMsgCode.USER_LEFT, actor: session.actor });
2098
2125
  }
2099
- const p$ = _optionalChain([this, 'access', _91 => _91.hooks, 'access', _92 => _92.onSessionDidEnd, 'optionalCall', _93 => _93(session, ctx)]);
2126
+ const p$ = _optionalChain([this, 'access', _93 => _93.hooks, 'access', _94 => _94.onSessionDidEnd, 'optionalCall', _95 => _95(session, ctx)]);
2100
2127
  if (p$) defer(p$);
2101
2128
  }
2102
2129
  }
@@ -2127,6 +2154,7 @@ var Room = class {
2127
2154
  );
2128
2155
  }) {
2129
2156
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2157
+ _optionalChain([this, 'access', _96 => _96.sessions, 'access', _97 => _97.get, 'call', _98 => _98(key), 'optionalAccess', _99 => _99.markActive, 'call', _100 => _100()]);
2130
2158
  if (text === "ping") {
2131
2159
  await this.handlePing(key, ctx);
2132
2160
  } else {
@@ -2400,7 +2428,7 @@ var Room = class {
2400
2428
  }
2401
2429
  // Don't ever manually call this!
2402
2430
  async _load(ctx) {
2403
- await _optionalChain([this, 'access', _94 => _94.hooks, 'access', _95 => _95.onRoomWillLoad, 'optionalCall', _96 => _96(ctx)]);
2431
+ await _optionalChain([this, 'access', _101 => _101.hooks, 'access', _102 => _102.onRoomWillLoad, 'optionalCall', _103 => _103(ctx)]);
2404
2432
  const storage = await this._loadStorage();
2405
2433
  const yjsStorage = await this._loadYjsStorage();
2406
2434
  this._data = {
@@ -2408,7 +2436,7 @@ var Room = class {
2408
2436
  storage,
2409
2437
  yjsStorage
2410
2438
  };
2411
- await _optionalChain([this, 'access', _97 => _97.hooks, 'access', _98 => _98.onRoomDidLoad, 'optionalCall', _99 => _99(ctx)]);
2439
+ await _optionalChain([this, 'access', _104 => _104.hooks, 'access', _105 => _105.onRoomDidLoad, 'optionalCall', _106 => _106(ctx)]);
2412
2440
  }
2413
2441
  /**
2414
2442
  * Returns a new, unique, actor ID.
@@ -2449,7 +2477,7 @@ var Room = class {
2449
2477
  }
2450
2478
  const sent = session.sendPong();
2451
2479
  if (sent !== 0) {
2452
- await _optionalChain([this, 'access', _100 => _100.hooks, 'access', _101 => _101.onDidPong, 'optionalCall', _102 => _102(ctx)]);
2480
+ await _optionalChain([this, 'access', _107 => _107.hooks, 'access', _108 => _108.onDidPong, 'optionalCall', _109 => _109(ctx)]);
2453
2481
  }
2454
2482
  }
2455
2483
  async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
@@ -2588,7 +2616,7 @@ var Room = class {
2588
2616
  break;
2589
2617
  }
2590
2618
  case _core.ClientMsgCode.UPDATE_STORAGE: {
2591
- _optionalChain([this, 'access', _103 => _103.driver, 'access', _104 => _104.bump_storage_version, 'optionalCall', _105 => _105()]);
2619
+ _optionalChain([this, 'access', _110 => _110.driver, 'access', _111 => _111.bump_storage_version, 'optionalCall', _112 => _112()]);
2592
2620
  const result = await this.storage.applyOps(msg.ops);
2593
2621
  const opsToForward = result.flatMap(
2594
2622
  (r) => r.action === "accepted" ? [r.op] : []
@@ -2620,7 +2648,7 @@ var Room = class {
2620
2648
  });
2621
2649
  }
2622
2650
  if (opsToForward.length > 0) {
2623
- const p$ = _optionalChain([this, 'access', _106 => _106.hooks, 'access', _107 => _107.postClientMsgStorageDidUpdate, 'optionalCall', _108 => _108(ctx)]);
2651
+ const p$ = _optionalChain([this, 'access', _113 => _113.hooks, 'access', _114 => _114.postClientMsgStorageDidUpdate, 'optionalCall', _115 => _115(ctx)]);
2624
2652
  if (p$) defer(p$);
2625
2653
  }
2626
2654
  break;
@@ -2671,7 +2699,7 @@ var Room = class {
2671
2699
  defer
2672
2700
  );
2673
2701
  if (result.isUpdated) {
2674
- const p$ = _optionalChain([this, 'access', _109 => _109.hooks, 'access', _110 => _110.postClientMsgYdocDidUpdate, 'optionalCall', _111 => _111(ctx, session)]);
2702
+ const p$ = _optionalChain([this, 'access', _116 => _116.hooks, 'access', _117 => _117.postClientMsgYdocDidUpdate, 'optionalCall', _118 => _118(ctx, session)]);
2675
2703
  if (p$) defer(p$);
2676
2704
  }
2677
2705
  break;
@@ -2679,7 +2707,7 @@ var Room = class {
2679
2707
  default: {
2680
2708
  try {
2681
2709
  return _core.assertNever.call(void 0, msg, "Unrecognized client msg");
2682
- } catch (e2) {
2710
+ } catch (e3) {
2683
2711
  }
2684
2712
  }
2685
2713
  }