@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.cjs CHANGED
@@ -20,8 +20,131 @@ var _core = require('@liveblocks/core');
20
20
 
21
21
 
22
22
 
23
+
24
+
23
25
  var _decoders = require('decoders');
24
26
 
27
+ // src/protocol/feedMessages.ts
28
+ var FeedMsgCode = {
29
+ // Server → client (50x)
30
+ FEEDS_LIST: 500,
31
+ FEEDS_ADDED: 501,
32
+ FEEDS_UPDATED: 502,
33
+ FEED_DELETED: 503,
34
+ FEED_MESSAGES_LIST: 504,
35
+ FEED_MESSAGES_ADDED: 505,
36
+ FEED_MESSAGES_UPDATED: 506,
37
+ FEED_MESSAGES_DELETED: 507,
38
+ FEED_REQUEST_FAILED: 508,
39
+ // Client → server (51x)
40
+ FETCH_FEEDS: 510,
41
+ FETCH_FEED_MESSAGES: 511,
42
+ ADD_FEED: 512,
43
+ UPDATE_FEED: 513,
44
+ DELETE_FEED: 514,
45
+ ADD_FEED_MESSAGE: 515,
46
+ UPDATE_FEED_MESSAGE: 516,
47
+ DELETE_FEED_MESSAGE: 517
48
+ };
49
+ var FeedRequestErrorCode = {
50
+ INTERNAL: "INTERNAL",
51
+ FEED_ALREADY_EXISTS: "FEED_ALREADY_EXISTS",
52
+ FEED_NOT_FOUND: "FEED_NOT_FOUND",
53
+ FEED_MESSAGE_NOT_FOUND: "FEED_MESSAGE_NOT_FOUND"
54
+ };
55
+
56
+ // src/protocol/feedErrors.ts
57
+ function feedRequestFailed(requestId, code, reason) {
58
+ return {
59
+ type: FeedMsgCode.FEED_REQUEST_FAILED,
60
+ requestId: _nullishCoalesce(requestId, () => ( "")),
61
+ code,
62
+ reason
63
+ };
64
+ }
65
+ function mapFeedError(err) {
66
+ if (!(err instanceof Error)) {
67
+ return { code: FeedRequestErrorCode.INTERNAL };
68
+ }
69
+ const m = err.message;
70
+ if (m.includes("already exists")) {
71
+ return { code: FeedRequestErrorCode.FEED_ALREADY_EXISTS, reason: m };
72
+ }
73
+ if (m.includes("Feed message") && m.includes("not found")) {
74
+ return { code: FeedRequestErrorCode.FEED_MESSAGE_NOT_FOUND, reason: m };
75
+ }
76
+ if (m.includes("not found")) {
77
+ return { code: FeedRequestErrorCode.FEED_NOT_FOUND, reason: m };
78
+ }
79
+ return { code: FeedRequestErrorCode.INTERNAL, reason: m };
80
+ }
81
+ function feedFailureServerMsg(requestId, err) {
82
+ const mapped = mapFeedError(err);
83
+ return feedRequestFailed(requestId, mapped.code, mapped.reason);
84
+ }
85
+
86
+ // src/protocol/ProtocolVersion.ts
87
+
88
+ var ProtocolVersion = /* @__PURE__ */ ((ProtocolVersion2) => {
89
+ ProtocolVersion2[ProtocolVersion2["V7"] = 7] = "V7";
90
+ ProtocolVersion2[ProtocolVersion2["V8"] = 8] = "V8";
91
+ return ProtocolVersion2;
92
+ })(ProtocolVersion || {});
93
+ var protocolVersionDecoder = _decoders.enum_.call(void 0, ProtocolVersion).describe(
94
+ "Unsupported protocol version"
95
+ );
96
+
97
+ // src/decoders/feedMetadata.ts
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+ var MAX_METADATA_COUNT = 50;
111
+ var MAX_METADATA_VALUE_LIST_LENGTH = 50;
112
+ var feedMetadataIdDecoder = _decoders.sized.call(void 0, _decoders.identifier, { min: 1, max: 40 });
113
+ var metadataStringValue = _decoders.sized.call(void 0, _decoders.string, { max: 256 });
114
+ function createRoomMetadataValueDecoder() {
115
+ return _decoders.select.call(void 0,
116
+ _decoders.either.call(void 0, _decoders.string, _decoders.poja).describe("Must be string or string[]"),
117
+ (x) => typeof x === "string" ? metadataStringValue : _decoders.array.call(void 0, metadataStringValue).refine(
118
+ (value) => value.length <= MAX_METADATA_VALUE_LIST_LENGTH,
119
+ `Must be at most ${MAX_METADATA_VALUE_LIST_LENGTH} items`
120
+ )
121
+ );
122
+ }
123
+ var roomMetadataValueDecoder = createRoomMetadataValueDecoder();
124
+ var feedMetadataNullableValueDecoder = _decoders.nullable.call(void 0, roomMetadataValueDecoder);
125
+ var feedMetadataRecordForCreate = _decoders.record.call(void 0,
126
+ feedMetadataIdDecoder,
127
+ roomMetadataValueDecoder
128
+ ).refine(
129
+ (value) => Object.keys(value).length <= MAX_METADATA_COUNT,
130
+ `Must be at most ${MAX_METADATA_COUNT} items`
131
+ );
132
+ var optionalFeedMetadataDecoder = _decoders.optional.call(void 0, feedMetadataRecordForCreate);
133
+ var feedMetadataUpdateDecoder = _decoders.record.call(void 0,
134
+ feedMetadataIdDecoder,
135
+ feedMetadataNullableValueDecoder
136
+ );
137
+ var feedMetadataRecordForFilter = _decoders.record.call(void 0,
138
+ feedMetadataIdDecoder,
139
+ feedMetadataNullableValueDecoder
140
+ ).refine(
141
+ (value) => Object.keys(value).length <= MAX_METADATA_COUNT,
142
+ `Must be at most ${MAX_METADATA_COUNT} items`
143
+ );
144
+ var fetchFeedsMetadataFilterDecoder = _decoders.optional.call(void 0,
145
+ feedMetadataRecordForFilter
146
+ );
147
+
25
148
  // src/decoders/jsonYolo.ts
26
149
 
27
150
  var jsonYolo = _decoders.unknown;
@@ -141,13 +264,77 @@ var updateYDocClientMsg = _decoders.object.call(void 0, {
141
264
  // Don't specify to update the root doc
142
265
  v2: _decoders.optional.call(void 0, _decoders.boolean)
143
266
  });
267
+ var fetchFeedsClientMsg = _decoders.object.call(void 0, {
268
+ type: _decoders.constant.call(void 0, FeedMsgCode.FETCH_FEEDS),
269
+ requestId: _decoders.string,
270
+ cursor: _decoders.optional.call(void 0, _decoders.string),
271
+ since: _decoders.optional.call(void 0, _decoders.number),
272
+ limit: _decoders.optional.call(void 0, _decoders.number),
273
+ metadata: fetchFeedsMetadataFilterDecoder
274
+ });
275
+ var fetchFeedMessagesClientMsg = _decoders.object.call(void 0, {
276
+ type: _decoders.constant.call(void 0, FeedMsgCode.FETCH_FEED_MESSAGES),
277
+ requestId: _decoders.string,
278
+ feedId: _decoders.nonEmptyString,
279
+ cursor: _decoders.optional.call(void 0, _decoders.string),
280
+ since: _decoders.optional.call(void 0, _decoders.number),
281
+ limit: _decoders.optional.call(void 0, _decoders.number)
282
+ });
283
+ var addFeedClientMsg = _decoders.object.call(void 0, {
284
+ type: _decoders.constant.call(void 0, FeedMsgCode.ADD_FEED),
285
+ feedId: _decoders.string,
286
+ metadata: optionalFeedMetadataDecoder,
287
+ timestamp: _decoders.optional.call(void 0, _decoders.number),
288
+ requestId: _decoders.optional.call(void 0, _decoders.string)
289
+ });
290
+ var updateFeedClientMsg = _decoders.object.call(void 0, {
291
+ type: _decoders.constant.call(void 0, FeedMsgCode.UPDATE_FEED),
292
+ feedId: _decoders.string,
293
+ metadata: feedMetadataUpdateDecoder,
294
+ requestId: _decoders.optional.call(void 0, _decoders.string)
295
+ });
296
+ var deleteFeedClientMsg = _decoders.object.call(void 0, {
297
+ type: _decoders.constant.call(void 0, FeedMsgCode.DELETE_FEED),
298
+ feedId: _decoders.string,
299
+ requestId: _decoders.optional.call(void 0, _decoders.string)
300
+ });
301
+ var addFeedMessageClientMsg = _decoders.object.call(void 0, {
302
+ type: _decoders.constant.call(void 0, FeedMsgCode.ADD_FEED_MESSAGE),
303
+ feedId: _decoders.string,
304
+ data: _decoders.jsonObject,
305
+ id: _decoders.optional.call(void 0, _decoders.string),
306
+ timestamp: _decoders.optional.call(void 0, _decoders.number),
307
+ requestId: _decoders.optional.call(void 0, _decoders.string)
308
+ });
309
+ var updateFeedMessageClientMsg = _decoders.object.call(void 0, {
310
+ type: _decoders.constant.call(void 0, FeedMsgCode.UPDATE_FEED_MESSAGE),
311
+ feedId: _decoders.string,
312
+ messageId: _decoders.string,
313
+ data: _decoders.jsonObject,
314
+ timestamp: _decoders.optional.call(void 0, _decoders.number),
315
+ requestId: _decoders.optional.call(void 0, _decoders.string)
316
+ });
317
+ var deleteFeedMessageClientMsg = _decoders.object.call(void 0, {
318
+ type: _decoders.constant.call(void 0, FeedMsgCode.DELETE_FEED_MESSAGE),
319
+ feedId: _decoders.string,
320
+ messageId: _decoders.string,
321
+ requestId: _decoders.optional.call(void 0, _decoders.string)
322
+ });
144
323
  var clientMsgDecoder = _decoders.taggedUnion.call(void 0, "type", {
145
324
  [_core.ClientMsgCode.UPDATE_PRESENCE]: updatePresenceClientMsg,
146
325
  [_core.ClientMsgCode.BROADCAST_EVENT]: broadcastEventClientMsg,
147
326
  [_core.ClientMsgCode.FETCH_STORAGE]: fetchStorageClientMsg,
148
327
  [_core.ClientMsgCode.UPDATE_STORAGE]: updateStorageClientMsg,
149
328
  [_core.ClientMsgCode.FETCH_YDOC]: fetchYDocClientMsg,
150
- [_core.ClientMsgCode.UPDATE_YDOC]: updateYDocClientMsg
329
+ [_core.ClientMsgCode.UPDATE_YDOC]: updateYDocClientMsg,
330
+ [FeedMsgCode.FETCH_FEEDS]: fetchFeedsClientMsg,
331
+ [FeedMsgCode.FETCH_FEED_MESSAGES]: fetchFeedMessagesClientMsg,
332
+ [FeedMsgCode.ADD_FEED]: addFeedClientMsg,
333
+ [FeedMsgCode.UPDATE_FEED]: updateFeedClientMsg,
334
+ [FeedMsgCode.DELETE_FEED]: deleteFeedClientMsg,
335
+ [FeedMsgCode.ADD_FEED_MESSAGE]: addFeedMessageClientMsg,
336
+ [FeedMsgCode.UPDATE_FEED_MESSAGE]: updateFeedMessageClientMsg,
337
+ [FeedMsgCode.DELETE_FEED_MESSAGE]: deleteFeedMessageClientMsg
151
338
  }).describe("Must be a valid client message");
152
339
  var transientClientMsgDecoder = _decoders.taggedUnion.call(void 0, "type", {
153
340
  // [ClientMsgCode.UPDATE_PRESENCE]: updatePresenceClientMsg,
@@ -628,17 +815,6 @@ function makeMetadataDB(driver) {
628
815
  };
629
816
  }
630
817
 
631
- // src/protocol/ProtocolVersion.ts
632
-
633
- var ProtocolVersion = /* @__PURE__ */ ((ProtocolVersion2) => {
634
- ProtocolVersion2[ProtocolVersion2["V7"] = 7] = "V7";
635
- ProtocolVersion2[ProtocolVersion2["V8"] = 8] = "V8";
636
- return ProtocolVersion2;
637
- })(ProtocolVersion || {});
638
- var protocolVersionDecoder = _decoders.enum_.call(void 0, ProtocolVersion).describe(
639
- "Unsupported protocol version"
640
- );
641
-
642
818
  // src/Room.ts
643
819
 
644
820
 
@@ -845,16 +1021,21 @@ function hasStaticDataAt(node, key) {
845
1021
  return node.type === _core.CrdtType.OBJECT && Object.prototype.hasOwnProperty.call(node.data, key) && node.data[key] !== void 0;
846
1022
  }
847
1023
  var InMemoryDriver = class {
1024
+ // Key: `${feedId}:${messageId}`
848
1025
  constructor(options) {
849
1026
  __publicField(this, "_nextActor");
850
1027
  __publicField(this, "_nodes");
851
1028
  __publicField(this, "_metadb");
852
1029
  __publicField(this, "_ydb");
853
1030
  __publicField(this, "_leasedSessions");
1031
+ __publicField(this, "_feeds");
1032
+ __publicField(this, "_feedMessages");
854
1033
  this._nodes = /* @__PURE__ */ new Map();
855
1034
  this._metadb = /* @__PURE__ */ new Map();
856
1035
  this._ydb = /* @__PURE__ */ new Map();
857
1036
  this._leasedSessions = /* @__PURE__ */ new Map();
1037
+ this._feeds = /* @__PURE__ */ new Map();
1038
+ this._feedMessages = /* @__PURE__ */ new Map();
858
1039
  this._nextActor = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _35 => _35.initialActor]), () => ( -1));
859
1040
  for (const [key, value] of _nullishCoalesce(_optionalChain([options, 'optionalAccess', _36 => _36.initialNodes]), () => ( []))) {
860
1041
  this._nodes.set(key, value);
@@ -894,6 +1075,180 @@ var InMemoryDriver = class {
894
1075
  takeRowsWritten() {
895
1076
  return 0;
896
1077
  }
1078
+ // ---------------------------------------------------------------------------
1079
+ // Feed APIs
1080
+ // ---------------------------------------------------------------------------
1081
+ async list_feeds(options) {
1082
+ const limit = Math.min(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _37 => _37.limit]), () => ( 20)), 100);
1083
+ const since = _optionalChain([options, 'optionalAccess', _38 => _38.since]);
1084
+ const cursor = _optionalChain([options, 'optionalAccess', _39 => _39.cursor]);
1085
+ const metadata = _optionalChain([options, 'optionalAccess', _40 => _40.metadata]);
1086
+ let feeds = [];
1087
+ for (const [_, feed] of this._feeds.entries()) {
1088
+ if (metadata !== void 0) {
1089
+ const feedMetadata = feed.metadata;
1090
+ let matches = true;
1091
+ for (const [key, value] of Object.entries(metadata)) {
1092
+ if (feedMetadata[key] !== value) {
1093
+ matches = false;
1094
+ break;
1095
+ }
1096
+ }
1097
+ if (!matches) continue;
1098
+ }
1099
+ if (since !== void 0 && feed.createdAt < since) {
1100
+ continue;
1101
+ }
1102
+ feeds.push(feed);
1103
+ }
1104
+ feeds.sort((a, b) => {
1105
+ if (b.createdAt !== a.createdAt) {
1106
+ return b.createdAt - a.createdAt;
1107
+ }
1108
+ return b.feedId.localeCompare(a.feedId);
1109
+ });
1110
+ if (cursor !== void 0) {
1111
+ try {
1112
+ const decoded = JSON.parse(
1113
+ decodeURIComponent(
1114
+ escape(atob(cursor.replace(/-/g, "+").replace(/_/g, "/")))
1115
+ )
1116
+ );
1117
+ const [cursorFeedId, cursorCreatedAt] = decoded;
1118
+ feeds = feeds.filter((s) => {
1119
+ return s.createdAt < cursorCreatedAt || s.createdAt === cursorCreatedAt && s.feedId < cursorFeedId;
1120
+ });
1121
+ } catch (e2) {
1122
+ }
1123
+ }
1124
+ let nextCursor;
1125
+ if (feeds.length > limit) {
1126
+ feeds = feeds.slice(0, limit);
1127
+ const last = feeds[feeds.length - 1];
1128
+ if (last) {
1129
+ const cursorData = [last.feedId, last.createdAt];
1130
+ nextCursor = btoa(
1131
+ unescape(encodeURIComponent(JSON.stringify(cursorData)))
1132
+ ).replace("/", "_").replace("+", "-").replace(/=+$/, "");
1133
+ }
1134
+ }
1135
+ return { feeds, nextCursor };
1136
+ }
1137
+ async get_feed(feedId) {
1138
+ const feed = this._feeds.get(feedId);
1139
+ if (feed === void 0) {
1140
+ return void 0;
1141
+ }
1142
+ return feed;
1143
+ }
1144
+ async create_feed(feed) {
1145
+ if (this._feeds.has(feed.feedId)) {
1146
+ throw new Error(`Feed ${feed.feedId} already exists`);
1147
+ }
1148
+ this._feeds.set(feed.feedId, {
1149
+ feedId: feed.feedId,
1150
+ metadata: feed.metadata,
1151
+ createdAt: feed.createdAt,
1152
+ updatedAt: feed.updatedAt
1153
+ });
1154
+ }
1155
+ async update_feed_metadata(feedId, metadata) {
1156
+ const existing = this._feeds.get(feedId);
1157
+ if (existing === void 0) {
1158
+ throw new Error(`Feed ${feedId} not found`);
1159
+ }
1160
+ this._feeds.set(feedId, {
1161
+ ...existing,
1162
+ metadata
1163
+ });
1164
+ }
1165
+ async delete_feed(feedId) {
1166
+ const messageKeys = [];
1167
+ for (const [key] of this._feedMessages.entries()) {
1168
+ if (key.startsWith(`${feedId}:`)) {
1169
+ messageKeys.push(key);
1170
+ }
1171
+ }
1172
+ for (const key of messageKeys) {
1173
+ this._feedMessages.delete(key);
1174
+ }
1175
+ this._feeds.delete(feedId);
1176
+ }
1177
+ async list_feed_messages(feedId, options) {
1178
+ const limit = Math.min(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _41 => _41.limit]), () => ( 20)), 100);
1179
+ const since = _optionalChain([options, 'optionalAccess', _42 => _42.since]);
1180
+ const cursor = _optionalChain([options, 'optionalAccess', _43 => _43.cursor]);
1181
+ let messages = [];
1182
+ const prefix = `${feedId}:`;
1183
+ for (const [key, message] of this._feedMessages.entries()) {
1184
+ if (key.startsWith(prefix)) {
1185
+ if (since !== void 0 && message.createdAt < since) {
1186
+ continue;
1187
+ }
1188
+ messages.push(message);
1189
+ }
1190
+ }
1191
+ messages.sort((a, b) => {
1192
+ if (b.createdAt !== a.createdAt) {
1193
+ return b.createdAt - a.createdAt;
1194
+ }
1195
+ return b.id.localeCompare(a.id);
1196
+ });
1197
+ if (cursor !== void 0) {
1198
+ try {
1199
+ const decoded = JSON.parse(
1200
+ decodeURIComponent(
1201
+ escape(atob(cursor.replace(/-/g, "+").replace(/_/g, "/")))
1202
+ )
1203
+ );
1204
+ const [cursorMessageId, cursorCreatedAt] = decoded;
1205
+ messages = messages.filter((m) => {
1206
+ return m.createdAt < cursorCreatedAt || m.createdAt === cursorCreatedAt && m.id < cursorMessageId;
1207
+ });
1208
+ } catch (e3) {
1209
+ }
1210
+ }
1211
+ let nextCursor;
1212
+ if (messages.length > limit) {
1213
+ messages = messages.slice(0, limit);
1214
+ const last = messages[messages.length - 1];
1215
+ if (last) {
1216
+ const cursorData = [last.id, last.createdAt];
1217
+ nextCursor = btoa(
1218
+ unescape(encodeURIComponent(JSON.stringify(cursorData)))
1219
+ ).replace("/", "_").replace("+", "-").replace(/=+$/, "");
1220
+ }
1221
+ }
1222
+ return { messages, nextCursor };
1223
+ }
1224
+ async add_feed_message(feedId, message) {
1225
+ const feed = this._feeds.get(feedId);
1226
+ if (feed === void 0) {
1227
+ throw new Error(`Feed ${feedId} not found`);
1228
+ }
1229
+ this._feedMessages.set(`${feedId}:${message.id}`, message);
1230
+ }
1231
+ async update_feed_message(feedId, messageId, data, timestamp) {
1232
+ const key = `${feedId}:${messageId}`;
1233
+ const message = this._feedMessages.get(key);
1234
+ if (message === void 0) {
1235
+ throw new Error(`Feed message ${messageId} not found in feed ${feedId}`);
1236
+ }
1237
+ const effectiveTimestamp = _nullishCoalesce(timestamp, () => ( Date.now()));
1238
+ if (effectiveTimestamp < message.updatedAt) {
1239
+ return message;
1240
+ }
1241
+ const updatedMessage = {
1242
+ ...message,
1243
+ updatedAt: effectiveTimestamp,
1244
+ data
1245
+ };
1246
+ this._feedMessages.set(key, updatedMessage);
1247
+ return updatedMessage;
1248
+ }
1249
+ async delete_feed_message(feedId, messageId) {
1250
+ this._feedMessages.delete(`${feedId}:${messageId}`);
1251
+ }
897
1252
  next_actor() {
898
1253
  return ++this._nextActor;
899
1254
  }
@@ -958,7 +1313,7 @@ var InMemoryDriver = class {
958
1313
  }
959
1314
  async function move_sibling(id, newPos) {
960
1315
  const node = nodes.get(id);
961
- if (_optionalChain([node, 'optionalAccess', _37 => _37.parentId]) === void 0) {
1316
+ if (_optionalChain([node, 'optionalAccess', _44 => _44.parentId]) === void 0) {
962
1317
  return;
963
1318
  }
964
1319
  if (revNodes.has(node.parentId, newPos))
@@ -970,7 +1325,7 @@ var InMemoryDriver = class {
970
1325
  }
971
1326
  async function set_object_data(id, data, allowOverwrite = false) {
972
1327
  const node = nodes.get(id);
973
- if (_optionalChain([node, 'optionalAccess', _38 => _38.type]) !== _core.CrdtType.OBJECT) {
1328
+ if (_optionalChain([node, 'optionalAccess', _45 => _45.type]) !== _core.CrdtType.OBJECT) {
974
1329
  return;
975
1330
  }
976
1331
  for (const key of Object.keys(data)) {
@@ -987,7 +1342,7 @@ var InMemoryDriver = class {
987
1342
  }
988
1343
  function delete_node(id) {
989
1344
  const node = nodes.get(id);
990
- if (_optionalChain([node, 'optionalAccess', _39 => _39.parentId]) === void 0) {
1345
+ if (_optionalChain([node, 'optionalAccess', _46 => _46.parentId]) === void 0) {
991
1346
  return;
992
1347
  }
993
1348
  revNodes.delete(node.parentId, node.parentKey);
@@ -1256,7 +1611,7 @@ var Storage = class {
1256
1611
  }
1257
1612
  return accept(op2);
1258
1613
  } else if (intent === "set") {
1259
- const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _40 => _40.loadedDriver, 'access', _41 => _41.get_node, 'call', _42 => _42(op2.deletedId), 'optionalAccess', _43 => _43.parentId]) === node.parentId ? op2.deletedId : void 0;
1614
+ const deletedId = op2.deletedId !== void 0 && op2.deletedId !== op2.id && _optionalChain([this, 'access', _47 => _47.loadedDriver, 'access', _48 => _48.get_node, 'call', _49 => _49(op2.deletedId), 'optionalAccess', _50 => _50.parentId]) === node.parentId ? op2.deletedId : void 0;
1260
1615
  if (deletedId !== void 0) {
1261
1616
  await this.loadedDriver.delete_node(deletedId);
1262
1617
  }
@@ -1335,10 +1690,10 @@ var Storage = class {
1335
1690
  */
1336
1691
  async moveToPosInList(id, targetKey) {
1337
1692
  const node = this.loadedDriver.get_node(id);
1338
- if (_optionalChain([node, 'optionalAccess', _44 => _44.parentId]) === void 0) {
1693
+ if (_optionalChain([node, 'optionalAccess', _51 => _51.parentId]) === void 0) {
1339
1694
  return;
1340
1695
  }
1341
- if (_optionalChain([this, 'access', _45 => _45.loadedDriver, 'access', _46 => _46.get_node, 'call', _47 => _47(node.parentId), 'optionalAccess', _48 => _48.type]) !== _core.CrdtType.LIST) {
1696
+ if (_optionalChain([this, 'access', _52 => _52.loadedDriver, 'access', _53 => _53.get_node, 'call', _54 => _54(node.parentId), 'optionalAccess', _55 => _55.type]) !== _core.CrdtType.LIST) {
1342
1697
  return;
1343
1698
  }
1344
1699
  if (node.parentKey === targetKey) {
@@ -1448,7 +1803,7 @@ var YjsStorage = class {
1448
1803
  let encodedTargetVector;
1449
1804
  try {
1450
1805
  encodedTargetVector = stateVector.length > 0 ? _jsbase64.Base64.toUint8Array(stateVector) : void 0;
1451
- } catch (e) {
1806
+ } catch (e4) {
1452
1807
  logger.warn(
1453
1808
  "Could not get update from passed vector, returning all updates"
1454
1809
  );
@@ -1673,13 +2028,14 @@ function isLeasedSessionExpired(leasedSession) {
1673
2028
 
1674
2029
  // src/Room.ts
1675
2030
  var messagesDecoder = _decoders.array.call(void 0, clientMsgDecoder);
2031
+ var ServerMsgCode2 = { ..._core.ServerMsgCode, ...FeedMsgCode };
1676
2032
  var HIGHEST_PROTOCOL_VERSION = Math.max(
1677
2033
  ...Object.values(ProtocolVersion).filter(
1678
2034
  (v) => typeof v === "number"
1679
2035
  )
1680
2036
  );
1681
2037
  var SERVER_MSG_CODE_NAMES = Object.fromEntries(
1682
- Object.entries(_core.ServerMsgCode).map(([k, v]) => [v, k])
2038
+ Object.entries(ServerMsgCode2).map(([k, v]) => [v, k])
1683
2039
  );
1684
2040
  var BLACK_HOLE = new Logger([
1685
2041
  /* No targets, i.e. black hole logger */
@@ -1722,6 +2078,7 @@ var BrowserSession = class {
1722
2078
  // Metadata sent to client in ROOM_STATE message's "meta" field
1723
2079
  __privateAdd(this, __socket);
1724
2080
  __privateAdd(this, __debug);
2081
+ /** Updated on every incoming message (including pings) via handleData(). Used for idle timeout detection. */
1725
2082
  __privateAdd(this, __lastActiveAt);
1726
2083
  // We keep a status in-memory in the session of whether we already sent a rejected ops message to the client.
1727
2084
  __privateAdd(this, __hasNotifiedClientStorageUpdateError);
@@ -1733,15 +2090,15 @@ var BrowserSession = class {
1733
2090
  this.publicMeta = ticket.publicMeta;
1734
2091
  __privateSet(this, __socket, socket);
1735
2092
  __privateSet(this, __debug, debug);
1736
- const now = _nullishCoalesce(createdAt, () => ( /* @__PURE__ */ new Date()));
2093
+ const now = _nullishCoalesce(_optionalChain([createdAt, 'optionalAccess', _56 => _56.getTime, 'call', _57 => _57()]), () => ( Date.now()));
1737
2094
  this.createdAt = now;
1738
2095
  __privateSet(this, __lastActiveAt, now);
1739
2096
  __privateSet(this, __hasNotifiedClientStorageUpdateError, false);
1740
2097
  }
1741
2098
  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;
2099
+ const lastPing = _optionalChain([__privateGet, 'call', _58 => _58(this, __socket), 'access', _59 => _59.getLastPongTimestamp, 'optionalCall', _60 => _60()]);
2100
+ if (lastPing && lastPing.getTime() > __privateGet(this, __lastActiveAt)) {
2101
+ return lastPing.getTime();
1745
2102
  } else {
1746
2103
  return __privateGet(this, __lastActiveAt);
1747
2104
  }
@@ -1749,10 +2106,9 @@ var BrowserSession = class {
1749
2106
  get hasNotifiedClientStorageUpdateError() {
1750
2107
  return __privateGet(this, __hasNotifiedClientStorageUpdateError);
1751
2108
  }
1752
- markActive(now = /* @__PURE__ */ new Date()) {
1753
- if (now > __privateGet(this, __lastActiveAt)) {
1754
- __privateSet(this, __lastActiveAt, now);
1755
- }
2109
+ /** @internal - This should have to be called only from Room, never externally */
2110
+ markActive(now) {
2111
+ __privateSet(this, __lastActiveAt, now ? now.getTime() : Date.now());
1756
2112
  }
1757
2113
  setHasNotifiedClientStorageUpdateError() {
1758
2114
  __privateSet(this, __hasNotifiedClientStorageUpdateError, true);
@@ -1824,6 +2180,15 @@ var Room = class {
1824
2180
  __publicField(this, "meta");
1825
2181
  __publicField(this, "driver");
1826
2182
  __publicField(this, "logger");
2183
+ /**
2184
+ * While a room is in "maintenance mode", all WebSocket connections to the
2185
+ * room should be rejected until it's pulled out of maintenance mode again.
2186
+ * Maintenance mode should only last a couple of milliseconds, typically.
2187
+ *
2188
+ * This mutex ensures that concurrent destructive operations (like
2189
+ * init-storage, storage-reset, etc.) cannot interfere with one another.
2190
+ */
2191
+ __publicField(this, "_maintenanceMode", new (0, _asyncmutex.Mutex)());
1827
2192
  __publicField(this, "_loadData$", null);
1828
2193
  __publicField(this, "_data", null);
1829
2194
  __publicField(this, "_qsize", 0);
@@ -1831,28 +2196,28 @@ var Room = class {
1831
2196
  __publicField(this, "hooks");
1832
2197
  __privateAdd(this, __debug2);
1833
2198
  __privateAdd(this, __allowStreaming);
1834
- const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _52 => _52.storage]), () => ( makeNewInMemoryDriver()));
2199
+ const driver = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _61 => _61.storage]), () => ( makeNewInMemoryDriver()));
1835
2200
  this.meta = meta;
1836
2201
  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)));
2202
+ this.logger = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _62 => _62.logger]), () => ( BLACK_HOLE));
2203
+ __privateSet(this, __allowStreaming, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _63 => _63.allowStreaming]), () => ( true)));
1839
2204
  this.hooks = {
1840
- isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _55 => _55.hooks, 'optionalAccess', _56 => _56.isClientMsgAllowed]), () => ( (() => {
2205
+ isClientMsgAllowed: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _64 => _64.hooks, 'optionalAccess', _65 => _65.isClientMsgAllowed]), () => ( (() => {
1841
2206
  return {
1842
2207
  allowed: true
1843
2208
  };
1844
2209
  }))),
1845
2210
  // 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])
2211
+ onRoomWillLoad: _optionalChain([options, 'optionalAccess', _66 => _66.hooks, 'optionalAccess', _67 => _67.onRoomWillLoad]),
2212
+ onRoomDidLoad: _optionalChain([options, 'optionalAccess', _68 => _68.hooks, 'optionalAccess', _69 => _69.onRoomDidLoad]),
2213
+ onRoomWillUnload: _optionalChain([options, 'optionalAccess', _70 => _70.hooks, 'optionalAccess', _71 => _71.onRoomWillUnload]),
2214
+ onRoomDidUnload: _optionalChain([options, 'optionalAccess', _72 => _72.hooks, 'optionalAccess', _73 => _73.onRoomDidUnload]),
2215
+ onSessionDidStart: _optionalChain([options, 'optionalAccess', _74 => _74.hooks, 'optionalAccess', _75 => _75.onSessionDidStart]),
2216
+ onSessionDidEnd: _optionalChain([options, 'optionalAccess', _76 => _76.hooks, 'optionalAccess', _77 => _77.onSessionDidEnd]),
2217
+ postClientMsgStorageDidUpdate: _optionalChain([options, 'optionalAccess', _78 => _78.hooks, 'optionalAccess', _79 => _79.postClientMsgStorageDidUpdate]),
2218
+ postClientMsgYdocDidUpdate: _optionalChain([options, 'optionalAccess', _80 => _80.hooks, 'optionalAccess', _81 => _81.postClientMsgYdocDidUpdate])
1854
2219
  };
1855
- __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _73 => _73.enableDebugLogging]), () => ( false)));
2220
+ __privateSet(this, __debug2, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.enableDebugLogging]), () => ( false)));
1856
2221
  }
1857
2222
  get loadingState() {
1858
2223
  if (this._loadData$ === null) {
@@ -1884,6 +2249,24 @@ var Room = class {
1884
2249
  }
1885
2250
  // prettier-ignore
1886
2251
  // ------------------------------------------------------------------------------------
2252
+ // Maintenance mode
2253
+ // ------------------------------------------------------------------------------------
2254
+ /**
2255
+ * Returns true if the room is currently in maintenance mode.
2256
+ * When in maintenance mode, callers should refuse new WebSocket connections.
2257
+ */
2258
+ get isInMaintenance() {
2259
+ return this._maintenanceMode.isLocked();
2260
+ }
2261
+ /**
2262
+ * Tries to enter maintenance mode and run the given callback exclusively.
2263
+ * If the room is already in maintenance mode, throws E_ALREADY_LOCKED
2264
+ * immediately instead of queuing the request.
2265
+ */
2266
+ async runInMaintenanceMode(callback) {
2267
+ return _asyncmutex.tryAcquire.call(void 0, this._maintenanceMode).runExclusive(callback);
2268
+ }
2269
+ // ------------------------------------------------------------------------------------
1887
2270
  // Public API
1888
2271
  // ------------------------------------------------------------------------------------
1889
2272
  /**
@@ -1908,13 +2291,13 @@ var Room = class {
1908
2291
  * room will be reloaded from storage.
1909
2292
  */
1910
2293
  unload(ctx) {
1911
- _optionalChain([this, 'access', _74 => _74.hooks, 'access', _75 => _75.onRoomWillUnload, 'optionalCall', _76 => _76(ctx)]);
2294
+ _optionalChain([this, 'access', _83 => _83.hooks, 'access', _84 => _84.onRoomWillUnload, 'optionalCall', _85 => _85(ctx)]);
1912
2295
  if (this._data) {
1913
2296
  this.storage.unload();
1914
2297
  this.yjsStorage.unload();
1915
2298
  }
1916
2299
  this._loadData$ = null;
1917
- _optionalChain([this, 'access', _77 => _77.hooks, 'access', _78 => _78.onRoomDidUnload, 'optionalCall', _79 => _79(ctx)]);
2300
+ _optionalChain([this, 'access', _86 => _86.hooks, 'access', _87 => _87.onRoomDidUnload, 'optionalCall', _88 => _88(ctx)]);
1918
2301
  }
1919
2302
  /**
1920
2303
  * Issues a Ticket with a new/unique actor ID
@@ -1928,17 +2311,17 @@ var Room = class {
1928
2311
  * unused Ticket will simply get garbage collected.
1929
2312
  */
1930
2313
  async createTicket(options) {
1931
- const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.actor]), () => ( this.getNextActor()));
2314
+ const actor$ = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.actor]), () => ( this.getNextActor()));
1932
2315
  const sessionKey = _nanoid.nanoid.call(void 0, );
1933
- const info = _optionalChain([options, 'optionalAccess', _81 => _81.info]);
2316
+ const info = _optionalChain([options, 'optionalAccess', _90 => _90.info]);
1934
2317
  const ticket = {
1935
- version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
2318
+ version: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _91 => _91.version]), () => ( HIGHEST_PROTOCOL_VERSION)),
1936
2319
  actor: await actor$,
1937
2320
  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"]))
2321
+ meta: _optionalChain([options, 'optionalAccess', _92 => _92.meta]),
2322
+ publicMeta: _optionalChain([options, 'optionalAccess', _93 => _93.publicMeta]),
2323
+ 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 },
2324
+ scopes: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _96 => _96.scopes]), () => ( ["room:write"]))
1942
2325
  };
1943
2326
  if (__privateGet(this, __debug2)) {
1944
2327
  console.log(`new ticket created: ${JSON.stringify(ticket)}`);
@@ -2023,7 +2406,7 @@ var Room = class {
2023
2406
  );
2024
2407
  for (const leasedSession of leasedSessions) {
2025
2408
  newSession.send({
2026
- type: _core.ServerMsgCode.UPDATE_PRESENCE,
2409
+ type: ServerMsgCode2.UPDATE_PRESENCE,
2027
2410
  actor: leasedSession.actorId,
2028
2411
  targetActor: newSession.actor,
2029
2412
  // full presence to new user
@@ -2063,7 +2446,7 @@ var Room = class {
2063
2446
  this.sendToOthers(
2064
2447
  ticket.sessionKey,
2065
2448
  {
2066
- type: _core.ServerMsgCode.USER_JOINED,
2449
+ type: ServerMsgCode2.USER_JOINED,
2067
2450
  actor: newSession.actor,
2068
2451
  id: newSession.user.id,
2069
2452
  info: newSession.user.info,
@@ -2072,7 +2455,7 @@ var Room = class {
2072
2455
  ctx,
2073
2456
  defer
2074
2457
  );
2075
- const p$ = _optionalChain([this, 'access', _88 => _88.hooks, 'access', _89 => _89.onSessionDidStart, 'optionalCall', _90 => _90(newSession, ctx)]);
2458
+ const p$ = _optionalChain([this, 'access', _97 => _97.hooks, 'access', _98 => _98.onSessionDidStart, 'optionalCall', _99 => _99(newSession, ctx)]);
2076
2459
  if (p$) defer(p$);
2077
2460
  }
2078
2461
  /**
@@ -2094,9 +2477,9 @@ var Room = class {
2094
2477
  const deleted = sessions.delete(key);
2095
2478
  if (deleted) {
2096
2479
  for (const other of this.otherSessions(key)) {
2097
- other.send({ type: _core.ServerMsgCode.USER_LEFT, actor: session.actor });
2480
+ other.send({ type: ServerMsgCode2.USER_LEFT, actor: session.actor });
2098
2481
  }
2099
- const p$ = _optionalChain([this, 'access', _91 => _91.hooks, 'access', _92 => _92.onSessionDidEnd, 'optionalCall', _93 => _93(session, ctx)]);
2482
+ const p$ = _optionalChain([this, 'access', _100 => _100.hooks, 'access', _101 => _101.onSessionDidEnd, 'optionalCall', _102 => _102(session, ctx)]);
2100
2483
  if (p$) defer(p$);
2101
2484
  }
2102
2485
  }
@@ -2127,6 +2510,7 @@ var Room = class {
2127
2510
  );
2128
2511
  }) {
2129
2512
  const text = typeof data === "string" ? data : _core.raise.call(void 0, "Unsupported message format");
2513
+ _optionalChain([this, 'access', _103 => _103.sessions, 'access', _104 => _104.get, 'call', _105 => _105(key), 'optionalAccess', _106 => _106.markActive, 'call', _107 => _107()]);
2130
2514
  if (text === "ping") {
2131
2515
  await this.handlePing(key, ctx);
2132
2516
  } else {
@@ -2239,7 +2623,7 @@ var Room = class {
2239
2623
  await this.driver.put_leased_session(session);
2240
2624
  this.sendToAll(
2241
2625
  {
2242
- type: _core.ServerMsgCode.USER_JOINED,
2626
+ type: ServerMsgCode2.USER_JOINED,
2243
2627
  actor: actorId,
2244
2628
  id: sessionId,
2245
2629
  info,
@@ -2250,7 +2634,7 @@ var Room = class {
2250
2634
  );
2251
2635
  this.sendToAll(
2252
2636
  {
2253
- type: _core.ServerMsgCode.UPDATE_PRESENCE,
2637
+ type: ServerMsgCode2.UPDATE_PRESENCE,
2254
2638
  actor: actorId,
2255
2639
  data: presence,
2256
2640
  targetActor: 1
@@ -2273,7 +2657,7 @@ var Room = class {
2273
2657
  await this.driver.put_leased_session(updatedSession);
2274
2658
  this.sendToAll(
2275
2659
  {
2276
- type: _core.ServerMsgCode.UPDATE_PRESENCE,
2660
+ type: ServerMsgCode2.UPDATE_PRESENCE,
2277
2661
  actor: existingSession.actorId,
2278
2662
  data: presence
2279
2663
  // Send only the patch, not the full merged presence
@@ -2318,7 +2702,7 @@ var Room = class {
2318
2702
  }) {
2319
2703
  this.sendToAll(
2320
2704
  {
2321
- type: _core.ServerMsgCode.USER_LEFT,
2705
+ type: ServerMsgCode2.USER_LEFT,
2322
2706
  actor: session.actorId
2323
2707
  },
2324
2708
  ctx,
@@ -2340,6 +2724,87 @@ var Room = class {
2340
2724
  await this.deleteLeasedSession(session, ctx, defer);
2341
2725
  }
2342
2726
  }
2727
+ // ---------------------------------------------------------------------------
2728
+ // Feed APIs
2729
+ // ---------------------------------------------------------------------------
2730
+ /**
2731
+ * List feeds with pagination and filtering.
2732
+ */
2733
+ async listFeeds(options) {
2734
+ return await this.driver.list_feeds(options);
2735
+ }
2736
+ /**
2737
+ * Get a specific feed by feed ID.
2738
+ */
2739
+ async getFeed(feedId) {
2740
+ return await this.driver.get_feed(feedId);
2741
+ }
2742
+ /**
2743
+ * Create a new feed.
2744
+ * If timestamp is not provided, current server time is used.
2745
+ */
2746
+ async createFeed(feed) {
2747
+ const now = _nullishCoalesce(feed.timestamp, () => ( Date.now()));
2748
+ const fullFeed = {
2749
+ ...feed,
2750
+ createdAt: now,
2751
+ updatedAt: now
2752
+ };
2753
+ await this.driver.create_feed(fullFeed);
2754
+ return fullFeed;
2755
+ }
2756
+ /**
2757
+ * Update a feed's metadata.
2758
+ */
2759
+ async updateFeedMetadata(feedId, metadata) {
2760
+ await this.driver.update_feed_metadata(feedId, metadata);
2761
+ }
2762
+ /**
2763
+ * Delete a feed.
2764
+ */
2765
+ async deleteFeed(feedId) {
2766
+ await this.driver.delete_feed(feedId);
2767
+ }
2768
+ /**
2769
+ * List feed messages for a feed with pagination.
2770
+ */
2771
+ async listFeedMessages(feedId, options) {
2772
+ return await this.driver.list_feed_messages(feedId, options);
2773
+ }
2774
+ /**
2775
+ * Add a message to a feed.
2776
+ * If message id is not provided, a unique ID is automatically generated.
2777
+ * If timestamp is not provided, current server time is used.
2778
+ */
2779
+ async addFeedMessage(feedId, message) {
2780
+ const now = _nullishCoalesce(message.timestamp, () => ( Date.now()));
2781
+ const fullMessage = {
2782
+ id: _nullishCoalesce(message.id, () => ( _nanoid.nanoid.call(void 0, ))),
2783
+ createdAt: now,
2784
+ updatedAt: now,
2785
+ data: message.data
2786
+ };
2787
+ await this.driver.add_feed_message(feedId, fullMessage);
2788
+ return fullMessage;
2789
+ }
2790
+ /**
2791
+ * Update a feed message's data.
2792
+ * Returns the updated message.
2793
+ */
2794
+ async updateFeedMessage(feedId, messageId, data, timestamp) {
2795
+ return await this.driver.update_feed_message(
2796
+ feedId,
2797
+ messageId,
2798
+ data,
2799
+ _nullishCoalesce(timestamp, () => ( Date.now()))
2800
+ );
2801
+ }
2802
+ /**
2803
+ * Delete a feed message.
2804
+ */
2805
+ async deleteFeedMessage(feedId, messageId) {
2806
+ await this.driver.delete_feed_message(feedId, messageId);
2807
+ }
2343
2808
  /**
2344
2809
  * Will send the given ServerMsg through all Session, except the Session
2345
2810
  * where the message originates from.
@@ -2400,7 +2865,7 @@ var Room = class {
2400
2865
  }
2401
2866
  // Don't ever manually call this!
2402
2867
  async _load(ctx) {
2403
- await _optionalChain([this, 'access', _94 => _94.hooks, 'access', _95 => _95.onRoomWillLoad, 'optionalCall', _96 => _96(ctx)]);
2868
+ await _optionalChain([this, 'access', _108 => _108.hooks, 'access', _109 => _109.onRoomWillLoad, 'optionalCall', _110 => _110(ctx)]);
2404
2869
  const storage = await this._loadStorage();
2405
2870
  const yjsStorage = await this._loadYjsStorage();
2406
2871
  this._data = {
@@ -2408,7 +2873,7 @@ var Room = class {
2408
2873
  storage,
2409
2874
  yjsStorage
2410
2875
  };
2411
- await _optionalChain([this, 'access', _97 => _97.hooks, 'access', _98 => _98.onRoomDidLoad, 'optionalCall', _99 => _99(ctx)]);
2876
+ await _optionalChain([this, 'access', _111 => _111.hooks, 'access', _112 => _112.onRoomDidLoad, 'optionalCall', _113 => _113(ctx)]);
2412
2877
  }
2413
2878
  /**
2414
2879
  * Returns a new, unique, actor ID.
@@ -2449,7 +2914,7 @@ var Room = class {
2449
2914
  }
2450
2915
  const sent = session.sendPong();
2451
2916
  if (sent !== 0) {
2452
- await _optionalChain([this, 'access', _100 => _100.hooks, 'access', _101 => _101.onDidPong, 'optionalCall', _102 => _102(ctx)]);
2917
+ await _optionalChain([this, 'access', _114 => _114.hooks, 'access', _115 => _115.onDidPong, 'optionalCall', _116 => _116(ctx)]);
2453
2918
  }
2454
2919
  }
2455
2920
  async _processClientMsg_withExclusiveAccess(sessionKey, messages, ctx, defer) {
@@ -2478,7 +2943,7 @@ var Room = class {
2478
2943
  } else {
2479
2944
  if (!session.hasNotifiedClientStorageUpdateError) {
2480
2945
  toReply.push({
2481
- type: _core.ServerMsgCode.REJECT_STORAGE_OP,
2946
+ type: ServerMsgCode2.REJECT_STORAGE_OP,
2482
2947
  opIds: msg.type === _core.ClientMsgCode.UPDATE_STORAGE ? msg.ops.map((op2) => op2.opId) : [],
2483
2948
  reason: isMsgAllowed.reason
2484
2949
  });
@@ -2542,7 +3007,7 @@ var Room = class {
2542
3007
  switch (msg.type) {
2543
3008
  case _core.ClientMsgCode.UPDATE_PRESENCE: {
2544
3009
  scheduleFanOut({
2545
- type: _core.ServerMsgCode.UPDATE_PRESENCE,
3010
+ type: ServerMsgCode2.UPDATE_PRESENCE,
2546
3011
  actor: session.actor,
2547
3012
  data: msg.data,
2548
3013
  targetActor: msg.targetActor
@@ -2551,7 +3016,7 @@ var Room = class {
2551
3016
  }
2552
3017
  case _core.ClientMsgCode.BROADCAST_EVENT: {
2553
3018
  scheduleFanOut({
2554
- type: _core.ServerMsgCode.BROADCASTED_EVENT,
3019
+ type: ServerMsgCode2.BROADCASTED_EVENT,
2555
3020
  actor: session.actor,
2556
3021
  event: msg.event
2557
3022
  });
@@ -2566,29 +3031,29 @@ var Room = class {
2566
3031
  NODES_PER_CHUNK
2567
3032
  )) {
2568
3033
  replyImmediately({
2569
- type: _core.ServerMsgCode.STORAGE_CHUNK,
3034
+ type: ServerMsgCode2.STORAGE_CHUNK,
2570
3035
  nodes: chunk
2571
3036
  });
2572
3037
  }
2573
3038
  } else {
2574
3039
  replyImmediately({
2575
- type: _core.ServerMsgCode.STORAGE_CHUNK,
3040
+ type: ServerMsgCode2.STORAGE_CHUNK,
2576
3041
  nodes: Array.from(
2577
3042
  _core.nodeStreamToCompactNodes.call(void 0, this.storage.loadedDriver.iter_nodes())
2578
3043
  )
2579
3044
  });
2580
3045
  }
2581
- replyImmediately({ type: _core.ServerMsgCode.STORAGE_STREAM_END });
3046
+ replyImmediately({ type: ServerMsgCode2.STORAGE_STREAM_END });
2582
3047
  } else {
2583
3048
  replyImmediately({
2584
- type: _core.ServerMsgCode.STORAGE_STATE_V7,
3049
+ type: ServerMsgCode2.STORAGE_STATE_V7,
2585
3050
  items: Array.from(this.storage.loadedDriver.iter_nodes())
2586
3051
  });
2587
3052
  }
2588
3053
  break;
2589
3054
  }
2590
3055
  case _core.ClientMsgCode.UPDATE_STORAGE: {
2591
- _optionalChain([this, 'access', _103 => _103.driver, 'access', _104 => _104.bump_storage_version, 'optionalCall', _105 => _105()]);
3056
+ _optionalChain([this, 'access', _117 => _117.driver, 'access', _118 => _118.bump_storage_version, 'optionalCall', _119 => _119()]);
2592
3057
  const result = await this.storage.applyOps(msg.ops);
2593
3058
  const opsToForward = result.flatMap(
2594
3059
  (r) => r.action === "accepted" ? [r.op] : []
@@ -2605,22 +3070,22 @@ var Room = class {
2605
3070
  });
2606
3071
  if (opsToForward.length > 0) {
2607
3072
  scheduleFanOut({
2608
- type: _core.ServerMsgCode.UPDATE_STORAGE,
3073
+ type: ServerMsgCode2.UPDATE_STORAGE,
2609
3074
  ops: opsToForward.map(stripOpId)
2610
3075
  });
2611
3076
  scheduleReply({
2612
- type: _core.ServerMsgCode.UPDATE_STORAGE,
3077
+ type: ServerMsgCode2.UPDATE_STORAGE,
2613
3078
  ops: opsToForward
2614
3079
  });
2615
3080
  }
2616
3081
  if (opsToSendBack.length > 0) {
2617
3082
  replyImmediately({
2618
- type: _core.ServerMsgCode.UPDATE_STORAGE,
3083
+ type: ServerMsgCode2.UPDATE_STORAGE,
2619
3084
  ops: opsToSendBack
2620
3085
  });
2621
3086
  }
2622
3087
  if (opsToForward.length > 0) {
2623
- const p$ = _optionalChain([this, 'access', _106 => _106.hooks, 'access', _107 => _107.postClientMsgStorageDidUpdate, 'optionalCall', _108 => _108(ctx)]);
3088
+ const p$ = _optionalChain([this, 'access', _120 => _120.hooks, 'access', _121 => _121.postClientMsgStorageDidUpdate, 'optionalCall', _122 => _122(ctx)]);
2624
3089
  if (p$) defer(p$);
2625
3090
  }
2626
3091
  break;
@@ -2636,7 +3101,7 @@ var Room = class {
2636
3101
  ]);
2637
3102
  if (update !== null && snapshotHash !== null) {
2638
3103
  replyImmediately({
2639
- type: _core.ServerMsgCode.UPDATE_YDOC,
3104
+ type: ServerMsgCode2.UPDATE_YDOC,
2640
3105
  update,
2641
3106
  isSync: true,
2642
3107
  // this is no longer used by the client, instead we use the presence of stateVector
@@ -2659,7 +3124,7 @@ var Room = class {
2659
3124
  break;
2660
3125
  this.sendToAll(
2661
3126
  {
2662
- type: _core.ServerMsgCode.UPDATE_YDOC,
3127
+ type: ServerMsgCode2.UPDATE_YDOC,
2663
3128
  update,
2664
3129
  guid,
2665
3130
  isSync: false,
@@ -2671,15 +3136,185 @@ var Room = class {
2671
3136
  defer
2672
3137
  );
2673
3138
  if (result.isUpdated) {
2674
- const p$ = _optionalChain([this, 'access', _109 => _109.hooks, 'access', _110 => _110.postClientMsgYdocDidUpdate, 'optionalCall', _111 => _111(ctx, session)]);
3139
+ const p$ = _optionalChain([this, 'access', _123 => _123.hooks, 'access', _124 => _124.postClientMsgYdocDidUpdate, 'optionalCall', _125 => _125(ctx, session)]);
2675
3140
  if (p$) defer(p$);
2676
3141
  }
2677
3142
  break;
2678
3143
  }
3144
+ case FeedMsgCode.FETCH_FEEDS: {
3145
+ const fetchMsg = msg;
3146
+ const [result, err] = await tryCatch(
3147
+ this.listFeeds({
3148
+ cursor: fetchMsg.cursor,
3149
+ since: fetchMsg.since,
3150
+ limit: fetchMsg.limit,
3151
+ metadata: fetchMsg.metadata
3152
+ })
3153
+ );
3154
+ if (err) {
3155
+ replyImmediately(feedFailureServerMsg(fetchMsg.requestId, err));
3156
+ break;
3157
+ }
3158
+ replyImmediately({
3159
+ type: FeedMsgCode.FEEDS_LIST,
3160
+ requestId: fetchMsg.requestId,
3161
+ feeds: result.feeds,
3162
+ nextCursor: result.nextCursor
3163
+ });
3164
+ break;
3165
+ }
3166
+ case FeedMsgCode.FETCH_FEED_MESSAGES: {
3167
+ const fetchMsg = msg;
3168
+ const [result, err] = await tryCatch(
3169
+ this.listFeedMessages(fetchMsg.feedId, {
3170
+ cursor: fetchMsg.cursor,
3171
+ since: fetchMsg.since,
3172
+ limit: fetchMsg.limit
3173
+ })
3174
+ );
3175
+ if (err) {
3176
+ replyImmediately(feedFailureServerMsg(fetchMsg.requestId, err));
3177
+ break;
3178
+ }
3179
+ replyImmediately({
3180
+ type: FeedMsgCode.FEED_MESSAGES_LIST,
3181
+ requestId: fetchMsg.requestId,
3182
+ feedId: fetchMsg.feedId,
3183
+ messages: result.messages,
3184
+ nextCursor: result.nextCursor
3185
+ });
3186
+ break;
3187
+ }
3188
+ case FeedMsgCode.ADD_FEED: {
3189
+ const addMsg = msg;
3190
+ const [feed, err] = await tryCatch(
3191
+ this.createFeed({
3192
+ feedId: addMsg.feedId,
3193
+ metadata: _nullishCoalesce(addMsg.metadata, () => ( {})),
3194
+ timestamp: addMsg.timestamp
3195
+ })
3196
+ );
3197
+ if (err) {
3198
+ replyImmediately(feedFailureServerMsg(addMsg.requestId, err));
3199
+ break;
3200
+ }
3201
+ const feedsMsg = {
3202
+ type: FeedMsgCode.FEEDS_ADDED,
3203
+ feeds: [feed]
3204
+ };
3205
+ replyImmediately(feedsMsg);
3206
+ scheduleFanOut(feedsMsg);
3207
+ break;
3208
+ }
3209
+ case FeedMsgCode.UPDATE_FEED: {
3210
+ const updateMsg = msg;
3211
+ const [, metaErr] = await tryCatch(
3212
+ this.updateFeedMetadata(updateMsg.feedId, updateMsg.metadata)
3213
+ );
3214
+ if (metaErr) {
3215
+ replyImmediately(feedFailureServerMsg(updateMsg.requestId, metaErr));
3216
+ break;
3217
+ }
3218
+ const feed = await this.getFeed(updateMsg.feedId);
3219
+ if (!feed) {
3220
+ replyImmediately(
3221
+ feedRequestFailed(
3222
+ updateMsg.requestId,
3223
+ FeedRequestErrorCode.FEED_NOT_FOUND
3224
+ )
3225
+ );
3226
+ break;
3227
+ }
3228
+ const feedsMsg = {
3229
+ type: FeedMsgCode.FEEDS_UPDATED,
3230
+ feeds: [feed]
3231
+ };
3232
+ replyImmediately(feedsMsg);
3233
+ scheduleFanOut(feedsMsg);
3234
+ break;
3235
+ }
3236
+ case FeedMsgCode.DELETE_FEED: {
3237
+ const deleteMsg = msg;
3238
+ const [, err] = await tryCatch(this.deleteFeed(deleteMsg.feedId));
3239
+ if (err) {
3240
+ replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
3241
+ break;
3242
+ }
3243
+ const feedDeletedMsg = {
3244
+ type: FeedMsgCode.FEED_DELETED,
3245
+ feedId: deleteMsg.feedId
3246
+ };
3247
+ replyImmediately(feedDeletedMsg);
3248
+ scheduleFanOut(feedDeletedMsg);
3249
+ break;
3250
+ }
3251
+ case FeedMsgCode.ADD_FEED_MESSAGE: {
3252
+ const addMsg = msg;
3253
+ const [message, err] = await tryCatch(
3254
+ this.addFeedMessage(addMsg.feedId, {
3255
+ data: addMsg.data,
3256
+ id: addMsg.id,
3257
+ timestamp: addMsg.timestamp
3258
+ })
3259
+ );
3260
+ if (err) {
3261
+ replyImmediately(feedFailureServerMsg(addMsg.requestId, err));
3262
+ break;
3263
+ }
3264
+ const feedMessagesMsg = {
3265
+ type: FeedMsgCode.FEED_MESSAGES_ADDED,
3266
+ feedId: addMsg.feedId,
3267
+ messages: [message]
3268
+ };
3269
+ replyImmediately(feedMessagesMsg);
3270
+ scheduleFanOut(feedMessagesMsg);
3271
+ break;
3272
+ }
3273
+ case FeedMsgCode.UPDATE_FEED_MESSAGE: {
3274
+ const updateMsg = msg;
3275
+ const [message, err] = await tryCatch(
3276
+ this.updateFeedMessage(
3277
+ updateMsg.feedId,
3278
+ updateMsg.messageId,
3279
+ updateMsg.data,
3280
+ updateMsg.timestamp
3281
+ )
3282
+ );
3283
+ if (err) {
3284
+ replyImmediately(feedFailureServerMsg(updateMsg.requestId, err));
3285
+ break;
3286
+ }
3287
+ const feedMessagesMsg = {
3288
+ type: FeedMsgCode.FEED_MESSAGES_UPDATED,
3289
+ feedId: updateMsg.feedId,
3290
+ messages: [message]
3291
+ };
3292
+ replyImmediately(feedMessagesMsg);
3293
+ scheduleFanOut(feedMessagesMsg);
3294
+ break;
3295
+ }
3296
+ case FeedMsgCode.DELETE_FEED_MESSAGE: {
3297
+ const deleteMsg = msg;
3298
+ const [, err] = await tryCatch(
3299
+ this.deleteFeedMessage(deleteMsg.feedId, deleteMsg.messageId)
3300
+ );
3301
+ if (err) {
3302
+ replyImmediately(feedFailureServerMsg(deleteMsg.requestId, err));
3303
+ break;
3304
+ }
3305
+ const feedMessagesMsg = {
3306
+ type: FeedMsgCode.FEED_MESSAGES_DELETED,
3307
+ feedId: deleteMsg.feedId,
3308
+ messageIds: [deleteMsg.messageId]
3309
+ };
3310
+ replyImmediately(feedMessagesMsg);
3311
+ scheduleFanOut(feedMessagesMsg);
3312
+ break;
3313
+ }
2679
3314
  default: {
2680
3315
  try {
2681
3316
  return _core.assertNever.call(void 0, msg, "Unrecognized client msg");
2682
- } catch (e2) {
3317
+ } catch (e5) {
2683
3318
  }
2684
3319
  }
2685
3320
  }
@@ -2723,5 +3358,14 @@ __allowStreaming = new WeakMap();
2723
3358
 
2724
3359
 
2725
3360
 
2726
- exports.BackendSession = BackendSession; exports.BrowserSession = BrowserSession; exports.ConsoleTarget = ConsoleTarget; exports.DefaultMap = DefaultMap; exports.InMemoryDriver = InMemoryDriver; exports.LogLevel = LogLevel; exports.LogTarget = LogTarget; exports.Logger = Logger; exports.NestedMap = NestedMap; exports.ProtocolVersion = ProtocolVersion; exports.ROOT_YDOC_ID = ROOT_YDOC_ID; exports.Room = Room; exports.UniqueMap = UniqueMap; exports.ackIgnoredOp = ackIgnoredOp; exports.clientMsgDecoder = clientMsgDecoder; exports.concatUint8Arrays = concatUint8Arrays; exports.guidDecoder = guidDecoder; exports.isLeasedSessionExpired = isLeasedSessionExpired; exports.jsonObjectYolo = jsonObjectYolo; exports.jsonYolo = jsonYolo; exports.makeInMemorySnapshot = makeInMemorySnapshot; exports.makeMetadataDB = makeMetadataDB; exports.plainLsonToNodeStream = plainLsonToNodeStream; exports.protocolVersionDecoder = protocolVersionDecoder; exports.quote = quote; exports.serializeServerMsg = serialize; exports.snapshotToLossyJson_eager = snapshotToLossyJson_eager; exports.snapshotToLossyJson_lazy = snapshotToLossyJson_lazy; exports.snapshotToNodeStream = snapshotToNodeStream; exports.snapshotToPlainLson_eager = snapshotToPlainLson_eager; exports.snapshotToPlainLson_lazy = snapshotToPlainLson_lazy; exports.test_only__Storage = Storage; exports.test_only__YjsStorage = YjsStorage; exports.transientClientMsgDecoder = transientClientMsgDecoder; exports.tryCatch = tryCatch;
3361
+
3362
+
3363
+
3364
+
3365
+
3366
+
3367
+
3368
+
3369
+
3370
+ exports.BackendSession = BackendSession; exports.BrowserSession = BrowserSession; exports.ConsoleTarget = ConsoleTarget; exports.DefaultMap = DefaultMap; exports.FeedMsgCode = FeedMsgCode; exports.FeedRequestErrorCode = FeedRequestErrorCode; exports.InMemoryDriver = InMemoryDriver; exports.LogLevel = LogLevel; exports.LogTarget = LogTarget; exports.Logger = Logger; exports.NestedMap = NestedMap; exports.ProtocolVersion = ProtocolVersion; exports.ROOT_YDOC_ID = ROOT_YDOC_ID; exports.Room = Room; exports.UniqueMap = UniqueMap; exports.ackIgnoredOp = ackIgnoredOp; exports.clientMsgDecoder = clientMsgDecoder; exports.concatUint8Arrays = concatUint8Arrays; exports.feedFailureServerMsg = feedFailureServerMsg; exports.feedMetadataIdDecoder = feedMetadataIdDecoder; exports.feedMetadataUpdateDecoder = feedMetadataUpdateDecoder; exports.feedRequestFailed = feedRequestFailed; exports.fetchFeedsMetadataFilterDecoder = fetchFeedsMetadataFilterDecoder; exports.guidDecoder = guidDecoder; exports.isLeasedSessionExpired = isLeasedSessionExpired; exports.jsonObjectYolo = jsonObjectYolo; exports.jsonYolo = jsonYolo; exports.makeInMemorySnapshot = makeInMemorySnapshot; exports.makeMetadataDB = makeMetadataDB; exports.mapFeedError = mapFeedError; exports.optionalFeedMetadataDecoder = optionalFeedMetadataDecoder; exports.plainLsonToNodeStream = plainLsonToNodeStream; exports.protocolVersionDecoder = protocolVersionDecoder; exports.quote = quote; exports.serializeServerMsg = serialize; exports.snapshotToLossyJson_eager = snapshotToLossyJson_eager; exports.snapshotToLossyJson_lazy = snapshotToLossyJson_lazy; exports.snapshotToNodeStream = snapshotToNodeStream; exports.snapshotToPlainLson_eager = snapshotToPlainLson_eager; exports.snapshotToPlainLson_lazy = snapshotToPlainLson_lazy; exports.test_only__Storage = Storage; exports.test_only__YjsStorage = YjsStorage; exports.transientClientMsgDecoder = transientClientMsgDecoder; exports.tryCatch = tryCatch;
2727
3371
  //# sourceMappingURL=index.cjs.map