@liveblocks/server 1.1.0 → 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 +79 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -9
- package/dist/index.d.ts +38 -9
- package/dist/index.js +48 -12
- package/dist/index.js.map +1 -1
- package/package.json +32 -18
package/dist/index.cjs
CHANGED
|
@@ -891,6 +891,9 @@ var InMemoryDriver = class {
|
|
|
891
891
|
async delete_leased_session(sessionId) {
|
|
892
892
|
this._leasedSessions.delete(sessionId);
|
|
893
893
|
}
|
|
894
|
+
takeRowsWritten() {
|
|
895
|
+
return 0;
|
|
896
|
+
}
|
|
894
897
|
next_actor() {
|
|
895
898
|
return ++this._nextActor;
|
|
896
899
|
}
|
|
@@ -1445,7 +1448,7 @@ var YjsStorage = class {
|
|
|
1445
1448
|
let encodedTargetVector;
|
|
1446
1449
|
try {
|
|
1447
1450
|
encodedTargetVector = stateVector.length > 0 ? _jsbase64.Base64.toUint8Array(stateVector) : void 0;
|
|
1448
|
-
} catch (
|
|
1451
|
+
} catch (e2) {
|
|
1449
1452
|
logger.warn(
|
|
1450
1453
|
"Could not get update from passed vector, returning all updates"
|
|
1451
1454
|
);
|
|
@@ -1701,7 +1704,7 @@ function stripOpId(op2) {
|
|
|
1701
1704
|
var __socket, __debug, __lastActiveAt, __hasNotifiedClientStorageUpdateError;
|
|
1702
1705
|
var BrowserSession = class {
|
|
1703
1706
|
/** @internal - Never create a BrowserSession instance manually. Use the room.startBrowserSession() API instead. */
|
|
1704
|
-
constructor(ticket, socket, debug) {
|
|
1707
|
+
constructor(ticket, socket, debug, createdAt) {
|
|
1705
1708
|
// ^^ User-defined Session Metadata
|
|
1706
1709
|
// ^^ User-defined Client Metadata (sent to client in ROOM_STATE)
|
|
1707
1710
|
__publicField(this, "version");
|
|
@@ -1719,6 +1722,7 @@ var BrowserSession = class {
|
|
|
1719
1722
|
// Metadata sent to client in ROOM_STATE message's "meta" field
|
|
1720
1723
|
__privateAdd(this, __socket);
|
|
1721
1724
|
__privateAdd(this, __debug);
|
|
1725
|
+
/** Updated on every incoming message (including pings) via handleData(). Used for idle timeout detection. */
|
|
1722
1726
|
__privateAdd(this, __lastActiveAt);
|
|
1723
1727
|
// We keep a status in-memory in the session of whether we already sent a rejected ops message to the client.
|
|
1724
1728
|
__privateAdd(this, __hasNotifiedClientStorageUpdateError);
|
|
@@ -1730,15 +1734,15 @@ var BrowserSession = class {
|
|
|
1730
1734
|
this.publicMeta = ticket.publicMeta;
|
|
1731
1735
|
__privateSet(this, __socket, socket);
|
|
1732
1736
|
__privateSet(this, __debug, debug);
|
|
1733
|
-
const now =
|
|
1737
|
+
const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _49 => _49.getTime, 'call', _50 => _50()]), () => ( Date.now()));
|
|
1734
1738
|
this.createdAt = now;
|
|
1735
1739
|
__privateSet(this, __lastActiveAt, now);
|
|
1736
1740
|
__privateSet(this, __hasNotifiedClientStorageUpdateError, false);
|
|
1737
1741
|
}
|
|
1738
1742
|
get lastActiveAt() {
|
|
1739
|
-
const lastPing = _optionalChain([__privateGet, 'call',
|
|
1740
|
-
if (lastPing && lastPing > __privateGet(this, __lastActiveAt)) {
|
|
1741
|
-
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();
|
|
1742
1746
|
} else {
|
|
1743
1747
|
return __privateGet(this, __lastActiveAt);
|
|
1744
1748
|
}
|
|
@@ -1746,10 +1750,9 @@ var BrowserSession = class {
|
|
|
1746
1750
|
get hasNotifiedClientStorageUpdateError() {
|
|
1747
1751
|
return __privateGet(this, __hasNotifiedClientStorageUpdateError);
|
|
1748
1752
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
}
|
|
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());
|
|
1753
1756
|
}
|
|
1754
1757
|
setHasNotifiedClientStorageUpdateError() {
|
|
1755
1758
|
__privateSet(this, __hasNotifiedClientStorageUpdateError, true);
|
|
@@ -1821,6 +1824,15 @@ var Room = class {
|
|
|
1821
1824
|
__publicField(this, "meta");
|
|
1822
1825
|
__publicField(this, "driver");
|
|
1823
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)());
|
|
1824
1836
|
__publicField(this, "_loadData$", null);
|
|
1825
1837
|
__publicField(this, "_data", null);
|
|
1826
1838
|
__publicField(this, "_qsize", 0);
|
|
@@ -1828,28 +1840,28 @@ var Room = class {
|
|
|
1828
1840
|
__publicField(this, "hooks");
|
|
1829
1841
|
__privateAdd(this, __debug2);
|
|
1830
1842
|
__privateAdd(this, __allowStreaming);
|
|
1831
|
-
const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1843
|
+
const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _54 => _54.storage]), () => ( makeNewInMemoryDriver()));
|
|
1832
1844
|
this.meta = meta;
|
|
1833
1845
|
this.driver = driver;
|
|
1834
|
-
this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1835
|
-
__privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1846
|
+
this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _55 => _55.logger]), () => ( BLACK_HOLE));
|
|
1847
|
+
__privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _56 => _56.allowStreaming]), () => ( true)));
|
|
1836
1848
|
this.hooks = {
|
|
1837
|
-
isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1849
|
+
isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _57 => _57.hooks, 'optionalAccess', _58 => _58.isClientMsgAllowed]), () => ( (() => {
|
|
1838
1850
|
return {
|
|
1839
1851
|
allowed: true
|
|
1840
1852
|
};
|
|
1841
1853
|
}))),
|
|
1842
1854
|
// YYY .load() isn't called on the RoomServer yet! As soon as it does, these hooks will get called
|
|
1843
|
-
onRoomWillLoad: _optionalChain([options, 'optionalAccess',
|
|
1844
|
-
onRoomDidLoad: _optionalChain([options, 'optionalAccess',
|
|
1845
|
-
onRoomWillUnload: _optionalChain([options, 'optionalAccess',
|
|
1846
|
-
onRoomDidUnload: _optionalChain([options, 'optionalAccess',
|
|
1847
|
-
onSessionDidStart: _optionalChain([options, 'optionalAccess',
|
|
1848
|
-
onSessionDidEnd: _optionalChain([options, 'optionalAccess',
|
|
1849
|
-
postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess',
|
|
1850
|
-
postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess',
|
|
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])
|
|
1851
1863
|
};
|
|
1852
|
-
__privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1864
|
+
__privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _75 => _75.enableDebugLogging]), () => ( false)));
|
|
1853
1865
|
}
|
|
1854
1866
|
get loadingState() {
|
|
1855
1867
|
if (this._loadData$ === null) {
|
|
@@ -1881,6 +1893,24 @@ var Room = class {
|
|
|
1881
1893
|
}
|
|
1882
1894
|
// prettier-ignore
|
|
1883
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
|
+
// ------------------------------------------------------------------------------------
|
|
1884
1914
|
// Public API
|
|
1885
1915
|
// ------------------------------------------------------------------------------------
|
|
1886
1916
|
/**
|
|
@@ -1905,13 +1935,13 @@ var Room = class {
|
|
|
1905
1935
|
* room will be reloaded from storage.
|
|
1906
1936
|
*/
|
|
1907
1937
|
unload(ctx) {
|
|
1908
|
-
_optionalChain([this, 'access',
|
|
1938
|
+
_optionalChain([this, 'access', _76 => _76.hooks, 'access', _77 => _77.onRoomWillUnload, 'optionalCall', _78 => _78(ctx)]);
|
|
1909
1939
|
if (this._data) {
|
|
1910
1940
|
this.storage.unload();
|
|
1911
1941
|
this.yjsStorage.unload();
|
|
1912
1942
|
}
|
|
1913
1943
|
this._loadData$ = null;
|
|
1914
|
-
_optionalChain([this, 'access',
|
|
1944
|
+
_optionalChain([this, 'access', _79 => _79.hooks, 'access', _80 => _80.onRoomDidUnload, 'optionalCall', _81 => _81(ctx)]);
|
|
1915
1945
|
}
|
|
1916
1946
|
/**
|
|
1917
1947
|
* Issues a Ticket with a new/unique actor ID
|
|
@@ -1925,17 +1955,17 @@ var Room = class {
|
|
|
1925
1955
|
* unused Ticket will simply get garbage collected.
|
|
1926
1956
|
*/
|
|
1927
1957
|
async createTicket(options) {
|
|
1928
|
-
const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1958
|
+
const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.actor]), () => ( this.getNextActor()));
|
|
1929
1959
|
const sessionKey = _nanoid.nanoid.call(void 0, );
|
|
1930
|
-
const info = _optionalChain([options, 'optionalAccess',
|
|
1960
|
+
const info = _optionalChain([options, 'optionalAccess', _83 => _83.info]);
|
|
1931
1961
|
const ticket = {
|
|
1932
|
-
version: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
1962
|
+
version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
|
|
1933
1963
|
actor: await actor$,
|
|
1934
1964
|
sessionKey,
|
|
1935
|
-
meta: _optionalChain([options, 'optionalAccess',
|
|
1936
|
-
publicMeta: _optionalChain([options, 'optionalAccess',
|
|
1937
|
-
user: _optionalChain([options, 'optionalAccess',
|
|
1938
|
-
scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
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"]))
|
|
1939
1969
|
};
|
|
1940
1970
|
if (__privateGet(this, __debug2)) {
|
|
1941
1971
|
console.log(`new ticket created: ${JSON.stringify(ticket)}`);
|
|
@@ -1973,8 +2003,13 @@ var Room = class {
|
|
|
1973
2003
|
if (this.sessions.size > 0) {
|
|
1974
2004
|
throw new Error("This API can only be called before any sessions exist");
|
|
1975
2005
|
}
|
|
1976
|
-
for (const { ticket, socket, lastActivity } of sessions) {
|
|
1977
|
-
const newSession = new BrowserSession(
|
|
2006
|
+
for (const { ticket, socket, lastActivity, createdAt } of sessions) {
|
|
2007
|
+
const newSession = new BrowserSession(
|
|
2008
|
+
ticket,
|
|
2009
|
+
socket,
|
|
2010
|
+
__privateGet(this, __debug2),
|
|
2011
|
+
createdAt
|
|
2012
|
+
);
|
|
1978
2013
|
this.sessions.set(ticket.sessionKey, newSession);
|
|
1979
2014
|
newSession.markActive(lastActivity);
|
|
1980
2015
|
}
|
|
@@ -2064,7 +2099,7 @@ var Room = class {
|
|
|
2064
2099
|
ctx,
|
|
2065
2100
|
defer
|
|
2066
2101
|
);
|
|
2067
|
-
const p$ = _optionalChain([this, 'access',
|
|
2102
|
+
const p$ = _optionalChain([this, 'access', _90 => _90.hooks, 'access', _91 => _91.onSessionDidStart, 'optionalCall', _92 => _92(newSession, ctx)]);
|
|
2068
2103
|
if (p$) defer(p$);
|
|
2069
2104
|
}
|
|
2070
2105
|
/**
|
|
@@ -2088,7 +2123,7 @@ var Room = class {
|
|
|
2088
2123
|
for (const other of this.otherSessions(key)) {
|
|
2089
2124
|
other.send({ type: _core.ServerMsgCode.USER_LEFT, actor: session.actor });
|
|
2090
2125
|
}
|
|
2091
|
-
const p$ = _optionalChain([this, 'access',
|
|
2126
|
+
const p$ = _optionalChain([this, 'access', _93 => _93.hooks, 'access', _94 => _94.onSessionDidEnd, 'optionalCall', _95 => _95(session, ctx)]);
|
|
2092
2127
|
if (p$) defer(p$);
|
|
2093
2128
|
}
|
|
2094
2129
|
}
|
|
@@ -2119,6 +2154,7 @@ var Room = class {
|
|
|
2119
2154
|
);
|
|
2120
2155
|
}) {
|
|
2121
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()]);
|
|
2122
2158
|
if (text === "ping") {
|
|
2123
2159
|
await this.handlePing(key, ctx);
|
|
2124
2160
|
} else {
|
|
@@ -2392,7 +2428,7 @@ var Room = class {
|
|
|
2392
2428
|
}
|
|
2393
2429
|
// Don't ever manually call this!
|
|
2394
2430
|
async _load(ctx) {
|
|
2395
|
-
await _optionalChain([this, 'access',
|
|
2431
|
+
await _optionalChain([this, 'access', _101 => _101.hooks, 'access', _102 => _102.onRoomWillLoad, 'optionalCall', _103 => _103(ctx)]);
|
|
2396
2432
|
const storage = await this._loadStorage();
|
|
2397
2433
|
const yjsStorage = await this._loadYjsStorage();
|
|
2398
2434
|
this._data = {
|
|
@@ -2400,7 +2436,7 @@ var Room = class {
|
|
|
2400
2436
|
storage,
|
|
2401
2437
|
yjsStorage
|
|
2402
2438
|
};
|
|
2403
|
-
await _optionalChain([this, 'access',
|
|
2439
|
+
await _optionalChain([this, 'access', _104 => _104.hooks, 'access', _105 => _105.onRoomDidLoad, 'optionalCall', _106 => _106(ctx)]);
|
|
2404
2440
|
}
|
|
2405
2441
|
/**
|
|
2406
2442
|
* Returns a new, unique, actor ID.
|
|
@@ -2441,7 +2477,7 @@ var Room = class {
|
|
|
2441
2477
|
}
|
|
2442
2478
|
const sent = session.sendPong();
|
|
2443
2479
|
if (sent !== 0) {
|
|
2444
|
-
await _optionalChain([this, 'access',
|
|
2480
|
+
await _optionalChain([this, 'access', _107 => _107.hooks, 'access', _108 => _108.onDidPong, 'optionalCall', _109 => _109(ctx)]);
|
|
2445
2481
|
}
|
|
2446
2482
|
}
|
|
2447
2483
|
async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
|
|
@@ -2580,7 +2616,7 @@ var Room = class {
|
|
|
2580
2616
|
break;
|
|
2581
2617
|
}
|
|
2582
2618
|
case _core.ClientMsgCode.UPDATE_STORAGE: {
|
|
2583
|
-
_optionalChain([this, 'access',
|
|
2619
|
+
_optionalChain([this, 'access', _110 => _110.driver, 'access', _111 => _111.bump_storage_version, 'optionalCall', _112 => _112()]);
|
|
2584
2620
|
const result = await this.storage.applyOps(msg.ops);
|
|
2585
2621
|
const opsToForward = result.flatMap(
|
|
2586
2622
|
(r) => r.action === "accepted" ? [r.op] : []
|
|
@@ -2612,7 +2648,7 @@ var Room = class {
|
|
|
2612
2648
|
});
|
|
2613
2649
|
}
|
|
2614
2650
|
if (opsToForward.length > 0) {
|
|
2615
|
-
const p$ = _optionalChain([this, 'access',
|
|
2651
|
+
const p$ = _optionalChain([this, 'access', _113 => _113.hooks, 'access', _114 => _114.postClientMsgStorageDidUpdate, 'optionalCall', _115 => _115(ctx)]);
|
|
2616
2652
|
if (p$) defer(p$);
|
|
2617
2653
|
}
|
|
2618
2654
|
break;
|
|
@@ -2663,7 +2699,7 @@ var Room = class {
|
|
|
2663
2699
|
defer
|
|
2664
2700
|
);
|
|
2665
2701
|
if (result.isUpdated) {
|
|
2666
|
-
const p$ = _optionalChain([this, 'access',
|
|
2702
|
+
const p$ = _optionalChain([this, 'access', _116 => _116.hooks, 'access', _117 => _117.postClientMsgYdocDidUpdate, 'optionalCall', _118 => _118(ctx, session)]);
|
|
2667
2703
|
if (p$) defer(p$);
|
|
2668
2704
|
}
|
|
2669
2705
|
break;
|
|
@@ -2671,7 +2707,7 @@ var Room = class {
|
|
|
2671
2707
|
default: {
|
|
2672
2708
|
try {
|
|
2673
2709
|
return _core.assertNever.call(void 0, msg, "Unrecognized client msg");
|
|
2674
|
-
} catch (
|
|
2710
|
+
} catch (e3) {
|
|
2675
2711
|
}
|
|
2676
2712
|
}
|
|
2677
2713
|
}
|