@liveblocks/server 1.1.1-pnpmtest1 → 1.2.1

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.d.cts CHANGED
@@ -1,10 +1,257 @@
1
- import { DistributiveOmit, SetParentKeyOp, DeleteCrdtOp, ClientMsg as ClientMsg$1, JsonObject, Json, Brand, asPos, SerializedCrdt, IUserInfo, SerializedRootObject, SerializedChild, StorageNode, Awaitable, PlainLsonObject, NodeMap as NodeMap$1, NodeStream as NodeStream$1, ClientWireOp, IgnoredOp, ServerMsg as ServerMsg$1, BaseUserMeta } from '@liveblocks/core';
1
+ import { asPos, SerializedCrdt, Json, IUserInfo, JsonObject, DistributiveOmit, SetParentKeyOp, DeleteCrdtOp, ClientMsg as ClientMsg$1, Brand, SerializedRootObject, SerializedChild, StorageNode, Awaitable, PlainLsonObject, NodeMap as NodeMap$1, NodeStream as NodeStream$1, ClientWireOp, IgnoredOp, ServerMsg as ServerMsg$1, BaseUserMeta } from '@liveblocks/core';
2
2
  export { BroadcastEventClientMsg, ClientMsg, ClientWireOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, DeleteCrdtOp, DeleteObjectKeyOp, FetchStorageClientMsg, FetchYDocClientMsg, HasOpId, IgnoredOp, Op, RoomStateServerMsg, ServerMsg, ServerWireOp, SetParentKeyOp, UpdateObjectOp, UpdatePresenceClientMsg, UpdateStorageClientMsg, UpdateYDocClientMsg } from '@liveblocks/core';
3
3
  import * as decoders from 'decoders';
4
4
  import { Decoder } from 'decoders';
5
5
  import { Mutex } from 'async-mutex';
6
6
  import * as Y from 'yjs';
7
7
 
8
+ /**
9
+ * Copyright (c) Liveblocks Inc.
10
+ *
11
+ * This program is free software: you can redistribute it and/or modify
12
+ * it under the terms of the GNU Affero General Public License as published
13
+ * by the Free Software Foundation, either version 3 of the License, or
14
+ * (at your option) any later version.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU Affero General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU Affero General Public License
22
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
23
+ */
24
+
25
+ type Pos = ReturnType<typeof asPos>;
26
+ type NodeTuple<T extends SerializedCrdt = SerializedCrdt> = [
27
+ id: string,
28
+ value: T
29
+ ];
30
+ type NodeMap = {
31
+ size: number;
32
+ [Symbol.iterator]: () => IterableIterator<[id: string, node: SerializedCrdt]>;
33
+ clear: () => void;
34
+ delete: (key: string) => boolean;
35
+ get: (key: string) => SerializedCrdt | undefined;
36
+ has: (key: string) => boolean;
37
+ keys: () => Iterable<string>;
38
+ set(key: string, value: SerializedCrdt): void;
39
+ };
40
+ type NodeStream = Iterable<NodeTuple>;
41
+ /**
42
+ * Leased session data structure for server-side sessions with temporarily persisted presence.
43
+ */
44
+ type LeasedSession = {
45
+ sessionId: string;
46
+ presence: Json;
47
+ updatedAt: number;
48
+ info: IUserInfo;
49
+ ttl: number;
50
+ actorId: number;
51
+ };
52
+ /**
53
+ * Feed message data structure for messages within feeds.
54
+ */
55
+ type FeedMessage = {
56
+ id: string;
57
+ createdAt: number;
58
+ updatedAt: number;
59
+ data: Json;
60
+ };
61
+ /**
62
+ * Feed data structure for feed-related data within a room.
63
+ * Note: Messages are stored separately and accessed via list_feed_messages.
64
+ */
65
+ type Feed = {
66
+ feedId: string;
67
+ metadata: Json;
68
+ createdAt: number;
69
+ updatedAt: number;
70
+ };
71
+
72
+ /**
73
+ * Copyright (c) Liveblocks Inc.
74
+ *
75
+ * This program is free software: you can redistribute it and/or modify
76
+ * it under the terms of the GNU Affero General Public License as published
77
+ * by the Free Software Foundation, either version 3 of the License, or
78
+ * (at your option) any later version.
79
+ *
80
+ * This program is distributed in the hope that it will be useful,
81
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
82
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83
+ * GNU Affero General Public License for more details.
84
+ *
85
+ * You should have received a copy of the GNU Affero General Public License
86
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
87
+ */
88
+ /**
89
+ * NOTE: this will be moved to @liveblocks/core in the future.
90
+ * Feed WebSocket message codes.
91
+ * 50x = server → client, 51x = client → server.
92
+ */
93
+ declare const FeedMsgCode: {
94
+ readonly FEEDS_LIST: 500;
95
+ readonly FEEDS_ADDED: 501;
96
+ readonly FEEDS_UPDATED: 502;
97
+ readonly FEED_DELETED: 503;
98
+ readonly FEED_MESSAGES_LIST: 504;
99
+ readonly FEED_MESSAGES_ADDED: 505;
100
+ readonly FEED_MESSAGES_UPDATED: 506;
101
+ readonly FEED_MESSAGES_DELETED: 507;
102
+ readonly FEED_REQUEST_FAILED: 508;
103
+ readonly FETCH_FEEDS: 510;
104
+ readonly FETCH_FEED_MESSAGES: 511;
105
+ readonly ADD_FEED: 512;
106
+ readonly UPDATE_FEED: 513;
107
+ readonly DELETE_FEED: 514;
108
+ readonly ADD_FEED_MESSAGE: 515;
109
+ readonly UPDATE_FEED_MESSAGE: 516;
110
+ readonly DELETE_FEED_MESSAGE: 517;
111
+ };
112
+ /** Error codes for {@link FeedRequestFailedServerMsg}. */
113
+ declare const FeedRequestErrorCode: {
114
+ readonly INTERNAL: "INTERNAL";
115
+ readonly FEED_ALREADY_EXISTS: "FEED_ALREADY_EXISTS";
116
+ readonly FEED_NOT_FOUND: "FEED_NOT_FOUND";
117
+ readonly FEED_MESSAGE_NOT_FOUND: "FEED_MESSAGE_NOT_FOUND";
118
+ };
119
+
120
+ type FeedsListServerMsg = {
121
+ type: 500;
122
+ requestId: string;
123
+ feeds: Feed[];
124
+ nextCursor?: string;
125
+ };
126
+ type FeedsAddedServerMsg = {
127
+ type: 501;
128
+ feeds: Feed[];
129
+ };
130
+ type FeedsUpdatedServerMsg = {
131
+ type: 502;
132
+ feeds: Feed[];
133
+ };
134
+ type FeedDeletedServerMsg = {
135
+ type: 503;
136
+ feedId: string;
137
+ };
138
+ type FeedRequestFailedServerMsg = {
139
+ type: 508;
140
+ requestId: string;
141
+ code: string;
142
+ reason?: string;
143
+ };
144
+ type FeedsServerMsg = FeedsListServerMsg | FeedsAddedServerMsg | FeedsUpdatedServerMsg | FeedDeletedServerMsg | FeedRequestFailedServerMsg;
145
+ type FeedMessagesListServerMsg = {
146
+ type: 504;
147
+ requestId: string;
148
+ feedId: string;
149
+ messages: FeedMessage[];
150
+ nextCursor?: string;
151
+ };
152
+ type FeedMessagesAddedServerMsg = {
153
+ type: 505;
154
+ feedId: string;
155
+ messages: FeedMessage[];
156
+ };
157
+ type FeedMessagesUpdatedServerMsg = {
158
+ type: 506;
159
+ feedId: string;
160
+ messages: FeedMessage[];
161
+ };
162
+ type FeedMessagesDeletedServerMsg = {
163
+ type: 507;
164
+ feedId: string;
165
+ messageIds: string[];
166
+ };
167
+ type FeedMessagesServerMsg = FeedMessagesListServerMsg | FeedMessagesAddedServerMsg | FeedMessagesUpdatedServerMsg | FeedMessagesDeletedServerMsg | FeedRequestFailedServerMsg;
168
+ type FetchFeedsClientMsg = {
169
+ type: 510;
170
+ requestId: string;
171
+ cursor?: string;
172
+ since?: number;
173
+ limit?: number;
174
+ /** Match feeds whose metadata contains these keys (same value rules as room metadata updates). */
175
+ metadata?: Record<string, string | string[] | null>;
176
+ };
177
+ type FetchFeedMessagesClientMsg = {
178
+ type: 511;
179
+ requestId: string;
180
+ feedId: string;
181
+ cursor?: string;
182
+ since?: number;
183
+ limit?: number;
184
+ };
185
+ type AddFeedClientMsg = {
186
+ type: 512;
187
+ feedId: string;
188
+ metadata?: Record<string, string[] | string>;
189
+ timestamp?: number;
190
+ requestId?: string;
191
+ };
192
+ type UpdateFeedClientMsg = {
193
+ type: 513;
194
+ feedId: string;
195
+ metadata: Record<string, string[] | string | null>;
196
+ requestId?: string;
197
+ };
198
+ type DeleteFeedClientMsg = {
199
+ type: 514;
200
+ feedId: string;
201
+ requestId?: string;
202
+ };
203
+ type AddFeedMessageClientMsg = {
204
+ type: 515;
205
+ feedId: string;
206
+ data: JsonObject;
207
+ id?: string;
208
+ timestamp?: number;
209
+ requestId?: string;
210
+ };
211
+ type UpdateFeedMessageClientMsg = {
212
+ type: 516;
213
+ feedId: string;
214
+ messageId: string;
215
+ data: JsonObject;
216
+ timestamp?: number;
217
+ requestId?: string;
218
+ };
219
+ type DeleteFeedMessageClientMsg = {
220
+ type: 517;
221
+ feedId: string;
222
+ messageId: string;
223
+ requestId?: string;
224
+ };
225
+
226
+ /**
227
+ * Copyright (c) Liveblocks Inc.
228
+ *
229
+ * This program is free software: you can redistribute it and/or modify
230
+ * it under the terms of the GNU Affero General Public License as published
231
+ * by the Free Software Foundation, either version 3 of the License, or
232
+ * (at your option) any later version.
233
+ *
234
+ * This program is distributed in the hope that it will be useful,
235
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
236
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
237
+ * GNU Affero General Public License for more details.
238
+ *
239
+ * You should have received a copy of the GNU Affero General Public License
240
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
241
+ */
242
+
243
+ declare function feedRequestFailed(requestId: string | undefined, code: string, reason?: string): FeedRequestFailedServerMsg;
244
+ /**
245
+ * Maps driver / Room errors to stable {@link FeedRequestFailedServerMsg} codes.
246
+ * Prefer matching known {@link Error#message} shapes storage drivers.
247
+ */
248
+ declare function mapFeedError(err: unknown): {
249
+ code: string;
250
+ reason?: string;
251
+ };
252
+ /** Maps an arbitrary thrown value to a {@link FeedRequestFailedServerMsg}. */
253
+ declare function feedFailureServerMsg(requestId: string | undefined, err: unknown): FeedRequestFailedServerMsg;
254
+
8
255
  /**
9
256
  * Copyright (c) Liveblocks Inc.
10
257
  *
@@ -109,6 +356,44 @@ type FixOp = DistributiveOmit<SetParentKeyOp | DeleteCrdtOp, "opId">;
109
356
  declare const clientMsgDecoder: Decoder<ClientMsg$1<JsonObject, Json>>;
110
357
  declare const transientClientMsgDecoder: Decoder<ClientMsg$1<JsonObject, Json>>;
111
358
 
359
+ /**
360
+ * Copyright (c) Liveblocks Inc.
361
+ *
362
+ * This program is free software: you can redistribute it and/or modify
363
+ * it under the terms of the GNU Affero General Public License as published
364
+ * by the Free Software Foundation, either version 3 of the License, or
365
+ * (at your option) any later version.
366
+ *
367
+ * This program is distributed in the hope that it will be useful,
368
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
369
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
370
+ * GNU Affero General Public License for more details.
371
+ *
372
+ * You should have received a copy of the GNU Affero General Public License
373
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
374
+ */
375
+ /**
376
+ * Feed metadata decoders — same rules as room/thread metadata (see @shared/common
377
+ * createMetadataDecoder / updateRoomMetadataDecoder).
378
+ */
379
+
380
+ declare const feedMetadataIdDecoder: Decoder<string>;
381
+ /**
382
+ * Optional feed metadata on create (WebSocket ADD_FEED, HTTP POST …/feeds).
383
+ * Same rules as createMetadataDecoder / room metadata on create (no null values).
384
+ */
385
+ declare const optionalFeedMetadataDecoder: Decoder<Record<string, string | string[]> | undefined>;
386
+ /**
387
+ * Full metadata object for update (WebSocket UPDATE_FEED, HTTP PATCH …/feeds/:id).
388
+ * Same shape as updateRoomMetadataDecoder.
389
+ */
390
+ declare const feedMetadataUpdateDecoder: Decoder<Record<string, string | string[] | null>>;
391
+ /**
392
+ * Optional metadata filter for FETCH_FEEDS — same key/value rules as
393
+ * {@link feedMetadataUpdateDecoder} / updateRoomMetadataDecoder in @shared/common.
394
+ */
395
+ declare const fetchFeedsMetadataFilterDecoder: Decoder<Record<string, string | string[] | null> | undefined>;
396
+
112
397
  /**
113
398
  * Copyright (c) Liveblocks Inc.
114
399
  *
@@ -312,51 +597,37 @@ declare class Logger {
312
597
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
313
598
  */
314
599
 
315
- type Pos = ReturnType<typeof asPos>;
316
- type NodeTuple<T extends SerializedCrdt = SerializedCrdt> = [
317
- id: string,
318
- value: T
319
- ];
320
- type NodeMap = {
321
- size: number;
322
- [Symbol.iterator]: () => IterableIterator<[id: string, node: SerializedCrdt]>;
323
- clear: () => void;
324
- delete: (key: string) => boolean;
325
- get: (key: string) => SerializedCrdt | undefined;
326
- has: (key: string) => boolean;
327
- keys: () => Iterable<string>;
328
- set(key: string, value: SerializedCrdt): void;
600
+ /**
601
+ * Options for listing feeds with pagination and filtering.
602
+ */
603
+ type ListFeedsOptions = {
604
+ cursor?: string;
605
+ since?: number;
606
+ limit?: number;
607
+ metadata?: Record<string, Json>;
329
608
  };
330
- type NodeStream = Iterable<NodeTuple>;
331
609
  /**
332
- * Leased session data structure for server-side sessions with temporarily persisted presence.
610
+ * Options for listing feed messages with pagination.
333
611
  */
334
- type LeasedSession = {
335
- sessionId: string;
336
- presence: Json;
337
- updatedAt: number;
338
- info: IUserInfo;
339
- ttl: number;
340
- actorId: number;
612
+ type ListFeedMessagesOptions = {
613
+ cursor?: string;
614
+ since?: number;
615
+ limit?: number;
341
616
  };
342
-
343
617
  /**
344
- * Copyright (c) Liveblocks Inc.
345
- *
346
- * This program is free software: you can redistribute it and/or modify
347
- * it under the terms of the GNU Affero General Public License as published
348
- * by the Free Software Foundation, either version 3 of the License, or
349
- * (at your option) any later version.
350
- *
351
- * This program is distributed in the hope that it will be useful,
352
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
353
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
354
- * GNU Affero General Public License for more details.
355
- *
356
- * You should have received a copy of the GNU Affero General Public License
357
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
618
+ * Result of listing feeds with pagination info.
358
619
  */
359
-
620
+ type ListFeedsResult = {
621
+ feeds: Feed[];
622
+ nextCursor?: string;
623
+ };
624
+ /**
625
+ * Result of listing feed messages with pagination info.
626
+ */
627
+ type ListFeedMessagesResult = {
628
+ messages: FeedMessage[];
629
+ nextCursor?: string;
630
+ };
360
631
  /**
361
632
  * An isolated, read-only copy of the storage document at a point in time.
362
633
  *
@@ -567,6 +838,58 @@ interface IStorageDriver {
567
838
  * and reset the counter.
568
839
  */
569
840
  takeRowsWritten?(): number;
841
+ /**
842
+ * List feeds with pagination, filtering, and metadata querying.
843
+ * Feeds are sorted by createdAt descending (newest first).
844
+ */
845
+ list_feeds(options?: ListFeedsOptions): Awaitable<ListFeedsResult>;
846
+ /**
847
+ * Get a specific feed by feed ID.
848
+ * Returns feed metadata only (without messages).
849
+ * Use list_feed_messages to retrieve messages for this feed.
850
+ * Returns undefined if the feed doesn't exist.
851
+ */
852
+ get_feed(feedId: string): Awaitable<Feed | undefined>;
853
+ /**
854
+ * Create a new feed.
855
+ * If feedId already exists, throws an error.
856
+ */
857
+ create_feed(feed: Feed): Awaitable<void>;
858
+ /**
859
+ * Update a feed's metadata.
860
+ * The feed must exist, otherwise throws an error.
861
+ */
862
+ update_feed_metadata(feedId: string, metadata: Json): Awaitable<void>;
863
+ /**
864
+ * Delete a feed by feed ID.
865
+ * Also deletes all messages associated with the feed (via CASCADE).
866
+ * No-op if feed doesn't exist.
867
+ */
868
+ delete_feed(feedId: string): Awaitable<void>;
869
+ /**
870
+ * List feed messages for a feed with pagination.
871
+ * Messages are sorted by createdAt descending (newest first).
872
+ */
873
+ list_feed_messages(feedId: string, options?: ListFeedMessagesOptions): Awaitable<ListFeedMessagesResult>;
874
+ /**
875
+ * Add a message to a feed.
876
+ * The message must have id, createdAt, and updatedAt already set (handled by Room layer).
877
+ * The feed must exist, otherwise throws an error.
878
+ */
879
+ add_feed_message(feedId: string, message: FeedMessage): Awaitable<void>;
880
+ /**
881
+ * Update a feed message's data.
882
+ * Returns the updated message.
883
+ * The feed and message must exist, otherwise throws an error.
884
+ * If timestamp is not provided, current server time is used.
885
+ * Messages are only updated if the provided timestamp is greater than or equal to the stored updatedAt.
886
+ */
887
+ update_feed_message(feedId: string, messageId: string, data: Json, timestamp?: number): Awaitable<FeedMessage>;
888
+ /**
889
+ * Delete a feed message.
890
+ * The feed and message must exist, otherwise throws an error.
891
+ */
892
+ delete_feed_message(feedId: string, messageId: string): Awaitable<void>;
570
893
  }
571
894
 
572
895
  /**
@@ -843,7 +1166,7 @@ declare class YjsStorage {
843
1166
  * @returns a base64 encoded array of YJS updates
844
1167
  */
845
1168
  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>;
1169
+ getYDocUpdateBinary(logger: Logger, stateVector?: string, guid?: Guid, isV2?: boolean): Promise<Uint8Array<ArrayBuffer> | null>;
847
1170
  getYStateVector(guid?: Guid): Promise<string | null>;
848
1171
  getSnapshotHash(options: {
849
1172
  guid?: Guid;
@@ -895,6 +1218,8 @@ declare class YjsStorage {
895
1218
 
896
1219
  type LoadingState = "initial" | "loading" | "loaded";
897
1220
  type ActorID = Brand<number, "ActorID">;
1221
+ /** Number of milliseconds since Unix epoch. */
1222
+ type Millis = Brand<number, "Millis">;
898
1223
  /**
899
1224
  * Session keys are also known as the "nonce" in the protocol. It's a random,
900
1225
  * unique, but PRIVATE, identifier for the session, and it's important that
@@ -903,8 +1228,8 @@ type ActorID = Brand<number, "ActorID">;
903
1228
  */
904
1229
  type SessionKey = Brand<string, "SessionKey">;
905
1230
  type PreSerializedServerMsg = Brand<string, "PreSerializedServerMsg">;
906
- type ClientMsg = ClientMsg$1<JsonObject, Json>;
907
- type ServerMsg = ServerMsg$1<JsonObject, BaseUserMeta, Json>;
1231
+ type ClientMsg = ClientMsg$1<JsonObject, Json> | FetchFeedsClientMsg | FetchFeedMessagesClientMsg | AddFeedClientMsg | UpdateFeedClientMsg | DeleteFeedClientMsg | AddFeedMessageClientMsg | UpdateFeedMessageClientMsg | DeleteFeedMessageClientMsg;
1232
+ type ServerMsg = ServerMsg$1<JsonObject, BaseUserMeta, Json> | FeedMessagesServerMsg | FeedsServerMsg;
908
1233
  declare function serialize(msgs: ServerMsg | readonly ServerMsg[]): PreSerializedServerMsg;
909
1234
  declare function ackIgnoredOp(opId: string): IgnoredOp;
910
1235
  /**
@@ -943,14 +1268,13 @@ declare class BrowserSession<SM, CM extends JsonObject> {
943
1268
  #private;
944
1269
  readonly version: ProtocolVersion;
945
1270
  readonly actor: ActorID;
946
- readonly createdAt: Date;
1271
+ readonly createdAt: Millis;
947
1272
  readonly user: IUserData;
948
1273
  readonly scopes: string[];
949
1274
  readonly meta: SM;
950
1275
  readonly publicMeta?: CM;
951
- get lastActiveAt(): Date;
1276
+ get lastActiveAt(): Millis;
952
1277
  get hasNotifiedClientStorageUpdateError(): boolean;
953
- markActive(now?: Date): void;
954
1278
  setHasNotifiedClientStorageUpdateError(): void;
955
1279
  sendPong(): number;
956
1280
  send(serverMsg: ServerMsg | ServerMsg[] | PreSerializedServerMsg): number;
@@ -1053,6 +1377,15 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
1053
1377
  meta: RM;
1054
1378
  readonly driver: IStorageDriver;
1055
1379
  logger: Logger;
1380
+ /**
1381
+ * While a room is in "maintenance mode", all WebSocket connections to the
1382
+ * room should be rejected until it's pulled out of maintenance mode again.
1383
+ * Maintenance mode should only last a couple of milliseconds, typically.
1384
+ *
1385
+ * This mutex ensures that concurrent destructive operations (like
1386
+ * init-storage, storage-reset, etc.) cannot interfere with one another.
1387
+ */
1388
+ private readonly _maintenanceMode;
1056
1389
  private _loadData$;
1057
1390
  private _data;
1058
1391
  private _qsize;
@@ -1065,6 +1398,17 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
1065
1398
  get yjsStorage(): YjsStorage;
1066
1399
  get mutex(): Mutex;
1067
1400
  private get data();
1401
+ /**
1402
+ * Returns true if the room is currently in maintenance mode.
1403
+ * When in maintenance mode, callers should refuse new WebSocket connections.
1404
+ */
1405
+ get isInMaintenance(): boolean;
1406
+ /**
1407
+ * Tries to enter maintenance mode and run the given callback exclusively.
1408
+ * If the room is already in maintenance mode, throws E_ALREADY_LOCKED
1409
+ * immediately instead of queuing the request.
1410
+ */
1411
+ runInMaintenanceMode<T>(callback: () => Promise<T>): Promise<T>;
1068
1412
  /**
1069
1413
  * Initializes the Room, so it's ready to start accepting connections. Safe
1070
1414
  * to call multiple times. After awaiting `room.load()` the Room is ready to
@@ -1188,6 +1532,50 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
1188
1532
  * Delete all server sessions and broadcast USER_LEFT to all sessions.
1189
1533
  */
1190
1534
  deleteAllLeasedSessions(ctx?: C, defer?: (promise: Promise<void>) => void): Promise<void>;
1535
+ /**
1536
+ * List feeds with pagination and filtering.
1537
+ */
1538
+ listFeeds(options?: ListFeedsOptions): Promise<ListFeedsResult>;
1539
+ /**
1540
+ * Get a specific feed by feed ID.
1541
+ */
1542
+ getFeed(feedId: string): Promise<Feed | undefined>;
1543
+ /**
1544
+ * Create a new feed.
1545
+ * If timestamp is not provided, current server time is used.
1546
+ */
1547
+ createFeed(feed: Omit<Feed, "createdAt" | "updatedAt"> & {
1548
+ timestamp?: number;
1549
+ }): Promise<Feed>;
1550
+ /**
1551
+ * Update a feed's metadata.
1552
+ */
1553
+ updateFeedMetadata(feedId: string, metadata: Json): Promise<void>;
1554
+ /**
1555
+ * Delete a feed.
1556
+ */
1557
+ deleteFeed(feedId: string): Promise<void>;
1558
+ /**
1559
+ * List feed messages for a feed with pagination.
1560
+ */
1561
+ listFeedMessages(feedId: string, options?: ListFeedMessagesOptions): Promise<ListFeedMessagesResult>;
1562
+ /**
1563
+ * Add a message to a feed.
1564
+ * If message id is not provided, a unique ID is automatically generated.
1565
+ * If timestamp is not provided, current server time is used.
1566
+ */
1567
+ addFeedMessage(feedId: string, message: Omit<FeedMessage, "id" | "createdAt" | "updatedAt"> & Partial<Pick<FeedMessage, "id">> & {
1568
+ timestamp?: number;
1569
+ }): Promise<FeedMessage>;
1570
+ /**
1571
+ * Update a feed message's data.
1572
+ * Returns the updated message.
1573
+ */
1574
+ updateFeedMessage(feedId: string, messageId: string, data: Json, timestamp?: number): Promise<FeedMessage>;
1575
+ /**
1576
+ * Delete a feed message.
1577
+ */
1578
+ deleteFeedMessage(feedId: string, messageId: string): Promise<void>;
1191
1579
  /**
1192
1580
  * Will send the given ServerMsg through all Session, except the Session
1193
1581
  * where the message originates from.
@@ -1237,7 +1625,7 @@ declare class Room<RM, SM, CM extends JsonObject, C = undefined> {
1237
1625
  /**
1238
1626
  * Concatenates multiple Uint8Arrays into a single Uint8Array.
1239
1627
  */
1240
- declare function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array;
1628
+ declare function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array<ArrayBuffer>;
1241
1629
  /**
1242
1630
  * Check if a leased session is expired.
1243
1631
  * Returns true if the current time is greater than or equal to updatedAt + ttl.
@@ -1471,23 +1859,34 @@ declare class InMemoryDriver implements IStorageDriver {
1471
1859
  private _metadb;
1472
1860
  private _ydb;
1473
1861
  private _leasedSessions;
1862
+ private _feeds;
1863
+ private _feedMessages;
1474
1864
  constructor(options?: {
1475
1865
  initialActor?: number;
1476
1866
  initialNodes?: Iterable<[string, SerializedCrdt]>;
1477
1867
  });
1478
- raw_iter_nodes(): IterableIterator<[string, SerializedCrdt]>;
1868
+ raw_iter_nodes(): MapIterator<[string, SerializedCrdt]>;
1479
1869
  /** Deletes all nodes and replaces them with the given document. */
1480
1870
  DANGEROUSLY_reset_nodes(doc: PlainLsonObject): void;
1481
1871
  get_meta(key: string): Promise<Json | undefined>;
1482
1872
  put_meta(key: string, value: Json): Promise<void>;
1483
1873
  delete_meta(key: string): Promise<void>;
1484
- list_leased_sessions(): Promise<IterableIterator<[string, LeasedSession]>>;
1874
+ list_leased_sessions(): Promise<MapIterator<[string, LeasedSession]>>;
1485
1875
  get_leased_session(sessionId: string): Promise<LeasedSession | undefined>;
1486
1876
  put_leased_session(session: LeasedSession): Promise<void>;
1487
1877
  delete_leased_session(sessionId: string): Promise<void>;
1488
1878
  takeRowsWritten(): number;
1879
+ list_feeds(options?: ListFeedsOptions): Promise<ListFeedsResult>;
1880
+ get_feed(feedId: string): Promise<Feed | undefined>;
1881
+ create_feed(feed: Feed): Promise<void>;
1882
+ update_feed_metadata(feedId: string, metadata: Json): Promise<void>;
1883
+ delete_feed(feedId: string): Promise<void>;
1884
+ list_feed_messages(feedId: string, options?: ListFeedMessagesOptions): Promise<ListFeedMessagesResult>;
1885
+ add_feed_message(feedId: string, message: FeedMessage): Promise<void>;
1886
+ update_feed_message(feedId: string, messageId: string, data: Json, timestamp?: number): Promise<FeedMessage>;
1887
+ delete_feed_message(feedId: string, messageId: string): Promise<void>;
1489
1888
  next_actor(): number;
1490
- iter_y_updates(docId: YDocId): Promise<IterableIterator<[string, Uint8Array]>>;
1889
+ iter_y_updates(docId: YDocId): Promise<IterableIterator<[string, Uint8Array<ArrayBufferLike>]>>;
1491
1890
  write_y_updates(docId: YDocId, key: string, data: Uint8Array): Promise<void>;
1492
1891
  delete_y_updates(docId: YDocId, keys: string[]): Promise<void>;
1493
1892
  /** @private Only use this in unit tests, never in production. */
@@ -1495,4 +1894,4 @@ declare class InMemoryDriver implements IStorageDriver {
1495
1894
  load_nodes_api(): IStorageDriverNodeAPI;
1496
1895
  }
1497
1896
 
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 };
1897
+ export { type ActorID, type AddFeedClientMsg, type AddFeedMessageClientMsg, BackendSession, BrowserSession, ConsoleTarget, type CreateTicketOptions, DefaultMap, type DeleteFeedClientMsg, type DeleteFeedMessageClientMsg, type Feed, type FeedDeletedServerMsg, type FeedMessage, type FeedMessagesAddedServerMsg, type FeedMessagesDeletedServerMsg, type FeedMessagesListServerMsg, type FeedMessagesServerMsg, type FeedMessagesUpdatedServerMsg, FeedMsgCode, FeedRequestErrorCode, type FeedRequestFailedServerMsg, type FeedsAddedServerMsg, type FeedsListServerMsg, type FeedsServerMsg, type FeedsUpdatedServerMsg, type FetchFeedMessagesClientMsg, type FetchFeedsClientMsg, type FixOp, type Guid, type IReadableSnapshot, type IServerWebSocket, type IStorageDriver, type IStorageDriverNodeAPI, type IUserData, InMemoryDriver, type LeasedSession, type ListFeedMessagesOptions, type ListFeedMessagesResult, type ListFeedsOptions, type ListFeedsResult, 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 UpdateFeedClientMsg, type UpdateFeedMessageClientMsg, type YDocId, type YUpdate, type YVector, ackIgnoredOp, clientMsgDecoder, concatUint8Arrays, feedFailureServerMsg, feedMetadataIdDecoder, feedMetadataUpdateDecoder, feedRequestFailed, fetchFeedsMetadataFilterDecoder, guidDecoder, isLeasedSessionExpired, jsonObjectYolo, jsonYolo, makeInMemorySnapshot, makeMetadataDB, mapFeedError, optionalFeedMetadataDecoder, 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 };