@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 +68 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -9
- package/dist/index.d.ts +30 -9
- package/dist/index.js +37 -9
- package/dist/index.js.map +1 -1
- package/package.json +8 -9
package/dist/index.d.cts
CHANGED
|
@@ -843,7 +843,7 @@ declare class YjsStorage {
|
|
|
843
843
|
* @returns a base64 encoded array of YJS updates
|
|
844
844
|
*/
|
|
845
845
|
getYDocUpdate(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<string | null>;
|
|
846
|
-
getYDocUpdateBinary(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<Uint8Array | null>;
|
|
846
|
+
getYDocUpdateBinary(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<Uint8Array<ArrayBuffer> | null>;
|
|
847
847
|
getYStateVector(guid?: Guid): Promise<string | null>;
|
|
848
848
|
getSnapshotHash(options: {
|
|
849
849
|
guid?: Guid;
|
|
@@ -895,6 +895,8 @@ declare class YjsStorage {
|
|
|
895
895
|
|
|
896
896
|
type LoadingState = "initial" | "loading" | "loaded";
|
|
897
897
|
type ActorID = Brand<number, "ActorID">;
|
|
898
|
+
/** Number of milliseconds since Unix epoch. */
|
|
899
|
+
type Millis = Brand<number, "Millis">;
|
|
898
900
|
/**
|
|
899
901
|
* Session keys are also known as the "nonce" in the protocol. It's a random,
|
|
900
902
|
* unique, but PRIVATE, identifier for the session, and it's important that
|
|
@@ -943,14 +945,13 @@ declare class BrowserSession<SM, CM extends JsonObject> {
|
|
|
943
945
|
#private;
|
|
944
946
|
readonly version: ProtocolVersion;
|
|
945
947
|
readonly actor: ActorID;
|
|
946
|
-
readonly createdAt:
|
|
948
|
+
readonly createdAt: Millis;
|
|
947
949
|
readonly user: IUserData;
|
|
948
950
|
readonly scopes: string[];
|
|
949
951
|
readonly meta: SM;
|
|
950
952
|
readonly publicMeta?: CM;
|
|
951
|
-
get lastActiveAt():
|
|
953
|
+
get lastActiveAt(): Millis;
|
|
952
954
|
get hasNotifiedClientStorageUpdateError(): boolean;
|
|
953
|
-
markActive(now?: Date): void;
|
|
954
955
|
setHasNotifiedClientStorageUpdateError(): void;
|
|
955
956
|
sendPong(): number;
|
|
956
957
|
send(serverMsg: ServerMsg | ServerMsg[] | PreSerializedServerMsg): number;
|
|
@@ -1053,6 +1054,15 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
|
|
|
1053
1054
|
meta: RM;
|
|
1054
1055
|
readonly driver: IStorageDriver;
|
|
1055
1056
|
logger: Logger;
|
|
1057
|
+
/**
|
|
1058
|
+
* While a room is in "maintenance mode", all WebSocket connections to the
|
|
1059
|
+
* room should be rejected until it's pulled out of maintenance mode again.
|
|
1060
|
+
* Maintenance mode should only last a couple of milliseconds, typically.
|
|
1061
|
+
*
|
|
1062
|
+
* This mutex ensures that concurrent destructive operations (like
|
|
1063
|
+
* init-storage, storage-reset, etc.) cannot interfere with one another.
|
|
1064
|
+
*/
|
|
1065
|
+
private readonly _maintenanceMode;
|
|
1056
1066
|
private _loadData$;
|
|
1057
1067
|
private _data;
|
|
1058
1068
|
private _qsize;
|
|
@@ -1065,6 +1075,17 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
|
|
|
1065
1075
|
get yjsStorage(): YjsStorage;
|
|
1066
1076
|
get mutex(): Mutex;
|
|
1067
1077
|
private get data();
|
|
1078
|
+
/**
|
|
1079
|
+
* Returns true if the room is currently in maintenance mode.
|
|
1080
|
+
* When in maintenance mode, callers should refuse new WebSocket connections.
|
|
1081
|
+
*/
|
|
1082
|
+
get isInMaintenance(): boolean;
|
|
1083
|
+
/**
|
|
1084
|
+
* Tries to enter maintenance mode and run the given callback exclusively.
|
|
1085
|
+
* If the room is already in maintenance mode, throws E_ALREADY_LOCKED
|
|
1086
|
+
* immediately instead of queuing the request.
|
|
1087
|
+
*/
|
|
1088
|
+
runInMaintenanceMode<T>(callback: () => Promise<T>): Promise<T>;
|
|
1068
1089
|
/**
|
|
1069
1090
|
* Initializes the Room, so it's ready to start accepting connections. Safe
|
|
1070
1091
|
* to call multiple times. After awaiting `room.load()` the Room is ready to
|
|
@@ -1237,7 +1258,7 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
|
|
|
1237
1258
|
/**
|
|
1238
1259
|
* Concatenates multiple Uint8Arrays into a single Uint8Array.
|
|
1239
1260
|
*/
|
|
1240
|
-
declare function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array
|
|
1261
|
+
declare function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array<ArrayBuffer>;
|
|
1241
1262
|
/**
|
|
1242
1263
|
* Check if a leased session is expired.
|
|
1243
1264
|
* Returns true if the current time is greater than or equal to updatedAt + ttl.
|
|
@@ -1475,19 +1496,19 @@ declare class InMemoryDriver implements IStorageDriver {
|
|
|
1475
1496
|
initialActor?: number;
|
|
1476
1497
|
initialNodes?: Iterable<[string, SerializedCrdt]>;
|
|
1477
1498
|
});
|
|
1478
|
-
raw_iter_nodes():
|
|
1499
|
+
raw_iter_nodes(): MapIterator<[string, SerializedCrdt]>;
|
|
1479
1500
|
/** Deletes all nodes and replaces them with the given document. */
|
|
1480
1501
|
DANGEROUSLY_reset_nodes(doc: PlainLsonObject): void;
|
|
1481
1502
|
get_meta(key: string): Promise<Json | undefined>;
|
|
1482
1503
|
put_meta(key: string, value: Json): Promise<void>;
|
|
1483
1504
|
delete_meta(key: string): Promise<void>;
|
|
1484
|
-
list_leased_sessions(): Promise<
|
|
1505
|
+
list_leased_sessions(): Promise<MapIterator<[string, LeasedSession]>>;
|
|
1485
1506
|
get_leased_session(sessionId: string): Promise<LeasedSession | undefined>;
|
|
1486
1507
|
put_leased_session(session: LeasedSession): Promise<void>;
|
|
1487
1508
|
delete_leased_session(sessionId: string): Promise<void>;
|
|
1488
1509
|
takeRowsWritten(): number;
|
|
1489
1510
|
next_actor(): number;
|
|
1490
|
-
iter_y_updates(docId: YDocId): Promise<IterableIterator<[string, Uint8Array]>>;
|
|
1511
|
+
iter_y_updates(docId: YDocId): Promise<IterableIterator<[string, Uint8Array<ArrayBufferLike>]>>;
|
|
1491
1512
|
write_y_updates(docId: YDocId, key: string, data: Uint8Array): Promise<void>;
|
|
1492
1513
|
delete_y_updates(docId: YDocId, keys: string[]): Promise<void>;
|
|
1493
1514
|
/** @private Only use this in unit tests, never in production. */
|
|
@@ -1495,4 +1516,4 @@ declare class InMemoryDriver implements IStorageDriver {
|
|
|
1495
1516
|
load_nodes_api(): IStorageDriverNodeAPI;
|
|
1496
1517
|
}
|
|
1497
1518
|
|
|
1498
|
-
export { type ActorID, BackendSession, BrowserSession, ConsoleTarget, type CreateTicketOptions, DefaultMap, type FixOp, type Guid, type IReadableSnapshot, type IServerWebSocket, type IStorageDriver, type IStorageDriverNodeAPI, type IUserData, InMemoryDriver, type LeasedSession, type LoadingState, LogLevel, LogTarget, Logger, type MetadataDB, NestedMap, type NodeMap, type NodeStream, type NodeTuple, type Pos, type PreSerializedServerMsg, ProtocolVersion, ROOT_YDOC_ID, Room, type SessionKey, type Ticket, UniqueMap, type YDocId, type YUpdate, type YVector, ackIgnoredOp, clientMsgDecoder, concatUint8Arrays, guidDecoder, isLeasedSessionExpired, jsonObjectYolo, jsonYolo, makeInMemorySnapshot, makeMetadataDB, plainLsonToNodeStream, protocolVersionDecoder, quote, serialize as serializeServerMsg, snapshotToLossyJson_eager, snapshotToLossyJson_lazy, snapshotToNodeStream, snapshotToPlainLson_eager, snapshotToPlainLson_lazy, Storage as test_only__Storage, YjsStorage as test_only__YjsStorage, transientClientMsgDecoder, tryCatch };
|
|
1519
|
+
export { type ActorID, BackendSession, BrowserSession, ConsoleTarget, type CreateTicketOptions, DefaultMap, type FixOp, type Guid, type IReadableSnapshot, type IServerWebSocket, type IStorageDriver, type IStorageDriverNodeAPI, type IUserData, InMemoryDriver, type LeasedSession, type LoadingState, LogLevel, LogTarget, Logger, type MetadataDB, type Millis, NestedMap, type NodeMap, type NodeStream, type NodeTuple, type Pos, type PreSerializedServerMsg, ProtocolVersion, ROOT_YDOC_ID, Room, type SessionKey, type Ticket, UniqueMap, type YDocId, type YUpdate, type YVector, ackIgnoredOp, clientMsgDecoder, concatUint8Arrays, guidDecoder, isLeasedSessionExpired, jsonObjectYolo, jsonYolo, makeInMemorySnapshot, makeMetadataDB, plainLsonToNodeStream, protocolVersionDecoder, quote, serialize as serializeServerMsg, snapshotToLossyJson_eager, snapshotToLossyJson_lazy, snapshotToNodeStream, snapshotToPlainLson_eager, snapshotToPlainLson_lazy, Storage as test_only__Storage, YjsStorage as test_only__YjsStorage, transientClientMsgDecoder, tryCatch };
|
package/dist/index.d.ts
CHANGED
|
@@ -843,7 +843,7 @@ declare class YjsStorage {
|
|
|
843
843
|
* @returns a base64 encoded array of YJS updates
|
|
844
844
|
*/
|
|
845
845
|
getYDocUpdate(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<string | null>;
|
|
846
|
-
getYDocUpdateBinary(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<Uint8Array | null>;
|
|
846
|
+
getYDocUpdateBinary(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<Uint8Array<ArrayBuffer> | null>;
|
|
847
847
|
getYStateVector(guid?: Guid): Promise<string | null>;
|
|
848
848
|
getSnapshotHash(options: {
|
|
849
849
|
guid?: Guid;
|
|
@@ -895,6 +895,8 @@ declare class YjsStorage {
|
|
|
895
895
|
|
|
896
896
|
type LoadingState = "initial" | "loading" | "loaded";
|
|
897
897
|
type ActorID = Brand<number, "ActorID">;
|
|
898
|
+
/** Number of milliseconds since Unix epoch. */
|
|
899
|
+
type Millis = Brand<number, "Millis">;
|
|
898
900
|
/**
|
|
899
901
|
* Session keys are also known as the "nonce" in the protocol. It's a random,
|
|
900
902
|
* unique, but PRIVATE, identifier for the session, and it's important that
|
|
@@ -943,14 +945,13 @@ declare class BrowserSession<SM, CM extends JsonObject> {
|
|
|
943
945
|
#private;
|
|
944
946
|
readonly version: ProtocolVersion;
|
|
945
947
|
readonly actor: ActorID;
|
|
946
|
-
readonly createdAt:
|
|
948
|
+
readonly createdAt: Millis;
|
|
947
949
|
readonly user: IUserData;
|
|
948
950
|
readonly scopes: string[];
|
|
949
951
|
readonly meta: SM;
|
|
950
952
|
readonly publicMeta?: CM;
|
|
951
|
-
get lastActiveAt():
|
|
953
|
+
get lastActiveAt(): Millis;
|
|
952
954
|
get hasNotifiedClientStorageUpdateError(): boolean;
|
|
953
|
-
markActive(now?: Date): void;
|
|
954
955
|
setHasNotifiedClientStorageUpdateError(): void;
|
|
955
956
|
sendPong(): number;
|
|
956
957
|
send(serverMsg: ServerMsg | ServerMsg[] | PreSerializedServerMsg): number;
|
|
@@ -1053,6 +1054,15 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
|
|
|
1053
1054
|
meta: RM;
|
|
1054
1055
|
readonly driver: IStorageDriver;
|
|
1055
1056
|
logger: Logger;
|
|
1057
|
+
/**
|
|
1058
|
+
* While a room is in "maintenance mode", all WebSocket connections to the
|
|
1059
|
+
* room should be rejected until it's pulled out of maintenance mode again.
|
|
1060
|
+
* Maintenance mode should only last a couple of milliseconds, typically.
|
|
1061
|
+
*
|
|
1062
|
+
* This mutex ensures that concurrent destructive operations (like
|
|
1063
|
+
* init-storage, storage-reset, etc.) cannot interfere with one another.
|
|
1064
|
+
*/
|
|
1065
|
+
private readonly _maintenanceMode;
|
|
1056
1066
|
private _loadData$;
|
|
1057
1067
|
private _data;
|
|
1058
1068
|
private _qsize;
|
|
@@ -1065,6 +1075,17 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
|
|
|
1065
1075
|
get yjsStorage(): YjsStorage;
|
|
1066
1076
|
get mutex(): Mutex;
|
|
1067
1077
|
private get data();
|
|
1078
|
+
/**
|
|
1079
|
+
* Returns true if the room is currently in maintenance mode.
|
|
1080
|
+
* When in maintenance mode, callers should refuse new WebSocket connections.
|
|
1081
|
+
*/
|
|
1082
|
+
get isInMaintenance(): boolean;
|
|
1083
|
+
/**
|
|
1084
|
+
* Tries to enter maintenance mode and run the given callback exclusively.
|
|
1085
|
+
* If the room is already in maintenance mode, throws E_ALREADY_LOCKED
|
|
1086
|
+
* immediately instead of queuing the request.
|
|
1087
|
+
*/
|
|
1088
|
+
runInMaintenanceMode<T>(callback: () => Promise<T>): Promise<T>;
|
|
1068
1089
|
/**
|
|
1069
1090
|
* Initializes the Room, so it's ready to start accepting connections. Safe
|
|
1070
1091
|
* to call multiple times. After awaiting `room.load()` the Room is ready to
|
|
@@ -1237,7 +1258,7 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
|
|
|
1237
1258
|
/**
|
|
1238
1259
|
* Concatenates multiple Uint8Arrays into a single Uint8Array.
|
|
1239
1260
|
*/
|
|
1240
|
-
declare function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array
|
|
1261
|
+
declare function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array<ArrayBuffer>;
|
|
1241
1262
|
/**
|
|
1242
1263
|
* Check if a leased session is expired.
|
|
1243
1264
|
* Returns true if the current time is greater than or equal to updatedAt + ttl.
|
|
@@ -1475,19 +1496,19 @@ declare class InMemoryDriver implements IStorageDriver {
|
|
|
1475
1496
|
initialActor?: number;
|
|
1476
1497
|
initialNodes?: Iterable<[string, SerializedCrdt]>;
|
|
1477
1498
|
});
|
|
1478
|
-
raw_iter_nodes():
|
|
1499
|
+
raw_iter_nodes(): MapIterator<[string, SerializedCrdt]>;
|
|
1479
1500
|
/** Deletes all nodes and replaces them with the given document. */
|
|
1480
1501
|
DANGEROUSLY_reset_nodes(doc: PlainLsonObject): void;
|
|
1481
1502
|
get_meta(key: string): Promise<Json | undefined>;
|
|
1482
1503
|
put_meta(key: string, value: Json): Promise<void>;
|
|
1483
1504
|
delete_meta(key: string): Promise<void>;
|
|
1484
|
-
list_leased_sessions(): Promise<
|
|
1505
|
+
list_leased_sessions(): Promise<MapIterator<[string, LeasedSession]>>;
|
|
1485
1506
|
get_leased_session(sessionId: string): Promise<LeasedSession | undefined>;
|
|
1486
1507
|
put_leased_session(session: LeasedSession): Promise<void>;
|
|
1487
1508
|
delete_leased_session(sessionId: string): Promise<void>;
|
|
1488
1509
|
takeRowsWritten(): number;
|
|
1489
1510
|
next_actor(): number;
|
|
1490
|
-
iter_y_updates(docId: YDocId): Promise<IterableIterator<[string, Uint8Array]>>;
|
|
1511
|
+
iter_y_updates(docId: YDocId): Promise<IterableIterator<[string, Uint8Array<ArrayBufferLike>]>>;
|
|
1491
1512
|
write_y_updates(docId: YDocId, key: string, data: Uint8Array): Promise<void>;
|
|
1492
1513
|
delete_y_updates(docId: YDocId, keys: string[]): Promise<void>;
|
|
1493
1514
|
/** @private Only use this in unit tests, never in production. */
|
|
@@ -1495,4 +1516,4 @@ declare class InMemoryDriver implements IStorageDriver {
|
|
|
1495
1516
|
load_nodes_api(): IStorageDriverNodeAPI;
|
|
1496
1517
|
}
|
|
1497
1518
|
|
|
1498
|
-
export { type ActorID, BackendSession, BrowserSession, ConsoleTarget, type CreateTicketOptions, DefaultMap, type FixOp, type Guid, type IReadableSnapshot, type IServerWebSocket, type IStorageDriver, type IStorageDriverNodeAPI, type IUserData, InMemoryDriver, type LeasedSession, type LoadingState, LogLevel, LogTarget, Logger, type MetadataDB, NestedMap, type NodeMap, type NodeStream, type NodeTuple, type Pos, type PreSerializedServerMsg, ProtocolVersion, ROOT_YDOC_ID, Room, type SessionKey, type Ticket, UniqueMap, type YDocId, type YUpdate, type YVector, ackIgnoredOp, clientMsgDecoder, concatUint8Arrays, guidDecoder, isLeasedSessionExpired, jsonObjectYolo, jsonYolo, makeInMemorySnapshot, makeMetadataDB, plainLsonToNodeStream, protocolVersionDecoder, quote, serialize as serializeServerMsg, snapshotToLossyJson_eager, snapshotToLossyJson_lazy, snapshotToNodeStream, snapshotToPlainLson_eager, snapshotToPlainLson_lazy, Storage as test_only__Storage, YjsStorage as test_only__YjsStorage, transientClientMsgDecoder, tryCatch };
|
|
1519
|
+
export { type ActorID, BackendSession, BrowserSession, ConsoleTarget, type CreateTicketOptions, DefaultMap, type FixOp, type Guid, type IReadableSnapshot, type IServerWebSocket, type IStorageDriver, type IStorageDriverNodeAPI, type IUserData, InMemoryDriver, type LeasedSession, type LoadingState, LogLevel, LogTarget, Logger, type MetadataDB, type Millis, NestedMap, type NodeMap, type NodeStream, type NodeTuple, type Pos, type PreSerializedServerMsg, ProtocolVersion, ROOT_YDOC_ID, Room, type SessionKey, type Ticket, UniqueMap, type YDocId, type YUpdate, type YVector, ackIgnoredOp, clientMsgDecoder, concatUint8Arrays, guidDecoder, isLeasedSessionExpired, jsonObjectYolo, jsonYolo, makeInMemorySnapshot, makeMetadataDB, plainLsonToNodeStream, protocolVersionDecoder, quote, serialize as serializeServerMsg, snapshotToLossyJson_eager, snapshotToLossyJson_lazy, snapshotToNodeStream, snapshotToPlainLson_eager, snapshotToPlainLson_lazy, Storage as test_only__Storage, YjsStorage as test_only__YjsStorage, transientClientMsgDecoder, tryCatch };
|
package/dist/index.js
CHANGED
|
@@ -650,7 +650,7 @@ import {
|
|
|
650
650
|
tryParseJson,
|
|
651
651
|
WebsocketCloseCodes as CloseCode
|
|
652
652
|
} from "@liveblocks/core";
|
|
653
|
-
import { Mutex } from "async-mutex";
|
|
653
|
+
import { Mutex, tryAcquire } from "async-mutex";
|
|
654
654
|
import { array as array2, formatInline } from "decoders";
|
|
655
655
|
import { chunked } from "itertools";
|
|
656
656
|
import { nanoid as nanoid2 } from "nanoid";
|
|
@@ -1448,7 +1448,7 @@ var YjsStorage = class {
|
|
|
1448
1448
|
let encodedTargetVector;
|
|
1449
1449
|
try {
|
|
1450
1450
|
encodedTargetVector = stateVector.length > 0 ? Base64.toUint8Array(stateVector) : void 0;
|
|
1451
|
-
} catch
|
|
1451
|
+
} catch {
|
|
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 = createdAt ??
|
|
1737
|
+
const now = createdAt?.getTime() ?? 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
1743
|
const lastPing = __privateGet(this, __socket).getLastPongTimestamp?.();
|
|
1743
|
-
if (lastPing && lastPing > __privateGet(this, __lastActiveAt)) {
|
|
1744
|
-
return lastPing;
|
|
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
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
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 Mutex());
|
|
1827
1836
|
__publicField(this, "_loadData$", null);
|
|
1828
1837
|
__publicField(this, "_data", null);
|
|
1829
1838
|
__publicField(this, "_qsize", 0);
|
|
@@ -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 tryAcquire(this._maintenanceMode).runExclusive(callback);
|
|
1912
|
+
}
|
|
1913
|
+
// ------------------------------------------------------------------------------------
|
|
1887
1914
|
// Public API
|
|
1888
1915
|
// ------------------------------------------------------------------------------------
|
|
1889
1916
|
/**
|
|
@@ -2127,6 +2154,7 @@ var Room = class {
|
|
|
2127
2154
|
);
|
|
2128
2155
|
}) {
|
|
2129
2156
|
const text = typeof data === "string" ? data : raise3("Unsupported message format");
|
|
2157
|
+
this.sessions.get(key)?.markActive();
|
|
2130
2158
|
if (text === "ping") {
|
|
2131
2159
|
await this.handlePing(key, ctx);
|
|
2132
2160
|
} else {
|