@liveblocks/react 3.14.1 → 3.15.0-feeds1

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.
@@ -512,6 +512,12 @@ function makeAiChatsQueryKey(query) {
512
512
  function makeInboxNotificationsQueryKey(query) {
513
513
  return stableStringify(query ?? {});
514
514
  }
515
+ function makeFeedsQueryKey(roomId, options) {
516
+ return stableStringify([roomId, options ?? {}]);
517
+ }
518
+ function makeFeedMessagesQueryKey(roomId, feedId, options) {
519
+ return stableStringify([roomId, feedId, options ?? {}]);
520
+ }
515
521
  function usify(promise) {
516
522
  if ("status" in promise) {
517
523
  return promise;
@@ -979,6 +985,16 @@ var UmbrellaStore = class {
979
985
  #roomVersionsLastRequestedAtByRoom = /* @__PURE__ */ new Map();
980
986
  // Notification Settings
981
987
  #notificationSettings;
988
+ // Feeds
989
+ #feedsByRoomId = /* @__PURE__ */ new Map();
990
+ #feedMessagesByFeedId = /* @__PURE__ */ new Map();
991
+ // Signals for feeds and feed messages to trigger reactivity
992
+ #feedsSignal = new MutableSignal3({
993
+ version: 0
994
+ });
995
+ #feedMessagesSignal = new MutableSignal3({
996
+ version: 0
997
+ });
982
998
  constructor(client) {
983
999
  this.#client = client[kInternal2].as();
984
1000
  this.optimisticUpdates = createStore_forOptimistic(this.#client);
@@ -1350,6 +1366,91 @@ var UmbrellaStore = class {
1350
1366
  return { signal, waitUntilLoaded: resource.waitUntilLoaded };
1351
1367
  }
1352
1368
  );
1369
+ const loadingFeeds = new DefaultMap(
1370
+ (queryKey) => {
1371
+ const [roomId, options] = JSON.parse(queryKey);
1372
+ const resource = new PaginatedResource(async (cursor) => {
1373
+ const room = this.#client.getRoom(roomId);
1374
+ if (room === null) {
1375
+ throw new Error(
1376
+ `Room '${roomId}' is not available on client. Make sure you're calling useFeeds inside a RoomProvider.`
1377
+ );
1378
+ }
1379
+ const result = await room.fetchFeeds({
1380
+ cursor,
1381
+ since: options?.since,
1382
+ metadata: options?.metadata
1383
+ });
1384
+ this.upsertFeeds(roomId, result.feeds);
1385
+ return result.nextCursor ?? null;
1386
+ });
1387
+ const signal = DerivedSignal.from(
1388
+ resource.signal,
1389
+ this.#feedsSignal,
1390
+ (resourceResult, _signalState) => {
1391
+ if (resourceResult.isLoading || resourceResult.error) {
1392
+ return resourceResult;
1393
+ }
1394
+ const feedsMap = this.#feedsByRoomId.get(roomId);
1395
+ const feeds = feedsMap ? Array.from(feedsMap.values()) : [];
1396
+ const page = resourceResult.data;
1397
+ return {
1398
+ isLoading: false,
1399
+ feeds,
1400
+ hasFetchedAll: page.hasFetchedAll,
1401
+ isFetchingMore: page.isFetchingMore,
1402
+ fetchMoreError: page.fetchMoreError,
1403
+ fetchMore: page.fetchMore
1404
+ };
1405
+ },
1406
+ shallow2
1407
+ );
1408
+ return { signal, waitUntilLoaded: resource.waitUntilLoaded };
1409
+ }
1410
+ );
1411
+ const loadingFeedMessages = new DefaultMap(
1412
+ (queryKey) => {
1413
+ const [roomId, feedId, options] = JSON.parse(queryKey);
1414
+ const resource = new PaginatedResource(async (cursor) => {
1415
+ const room = this.#client.getRoom(roomId);
1416
+ if (room === null) {
1417
+ throw new Error(
1418
+ `Room '${roomId}' is not available on client. Make sure you're calling useFeedMessages inside a RoomProvider.`
1419
+ );
1420
+ }
1421
+ const result = await room.fetchFeedMessages(feedId, {
1422
+ cursor,
1423
+ limit: options?.limit
1424
+ });
1425
+ this.upsertFeedMessages(roomId, feedId, result.messages);
1426
+ return result.nextCursor ?? null;
1427
+ });
1428
+ const signal = DerivedSignal.from(
1429
+ resource.signal,
1430
+ this.#feedMessagesSignal,
1431
+ (resourceResult, _signalState) => {
1432
+ if (resourceResult.isLoading || resourceResult.error) {
1433
+ return resourceResult;
1434
+ }
1435
+ const messagesMap = this.#feedMessagesByFeedId.get(feedId);
1436
+ const messages = messagesMap ? Array.from(messagesMap.values()).sort(
1437
+ (a, b) => a.timestamp - b.timestamp
1438
+ ) : [];
1439
+ const page = resourceResult.data;
1440
+ return {
1441
+ isLoading: false,
1442
+ messages,
1443
+ hasFetchedAll: page.hasFetchedAll,
1444
+ isFetchingMore: page.isFetchingMore,
1445
+ fetchMoreError: page.fetchMoreError,
1446
+ fetchMore: page.fetchMore
1447
+ };
1448
+ },
1449
+ shallow2
1450
+ );
1451
+ return { signal, waitUntilLoaded: resource.waitUntilLoaded };
1452
+ }
1453
+ );
1353
1454
  this.outputs = {
1354
1455
  threadifications,
1355
1456
  threads,
@@ -1365,7 +1466,9 @@ var UmbrellaStore = class {
1365
1466
  aiChats,
1366
1467
  messagesByChatId,
1367
1468
  aiChatById,
1368
- urlMetadataByUrl
1469
+ urlMetadataByUrl,
1470
+ loadingFeeds,
1471
+ loadingFeedMessages
1369
1472
  };
1370
1473
  autobind(this);
1371
1474
  }
@@ -1586,6 +1689,64 @@ var UmbrellaStore = class {
1586
1689
  result.subscriptions.deleted
1587
1690
  );
1588
1691
  }
1692
+ /**
1693
+ * Upserts feeds in the cache (for list/added/updated operations).
1694
+ */
1695
+ upsertFeeds(roomId, feeds) {
1696
+ let feedsMap = this.#feedsByRoomId.get(roomId);
1697
+ if (!feedsMap) {
1698
+ feedsMap = /* @__PURE__ */ new Map();
1699
+ this.#feedsByRoomId.set(roomId, feedsMap);
1700
+ }
1701
+ for (const feed of feeds) {
1702
+ feedsMap.set(feed.feedId, feed);
1703
+ }
1704
+ this.#feedsSignal.mutate((state) => {
1705
+ state.version++;
1706
+ });
1707
+ }
1708
+ /**
1709
+ * Removes feeds from the cache (for deleted operations).
1710
+ */
1711
+ deleteFeeds(roomId, feeds) {
1712
+ const feedsMap = this.#feedsByRoomId.get(roomId);
1713
+ if (!feedsMap) return;
1714
+ for (const feed of feeds) {
1715
+ feedsMap.delete(feed.feedId);
1716
+ }
1717
+ this.#feedsSignal.mutate((state) => {
1718
+ state.version++;
1719
+ });
1720
+ }
1721
+ /**
1722
+ * Upserts feed messages in the cache (for list/added/updated operations).
1723
+ */
1724
+ upsertFeedMessages(_roomId, feedId, messages) {
1725
+ let messagesMap = this.#feedMessagesByFeedId.get(feedId);
1726
+ if (!messagesMap) {
1727
+ messagesMap = /* @__PURE__ */ new Map();
1728
+ this.#feedMessagesByFeedId.set(feedId, messagesMap);
1729
+ }
1730
+ for (const message of messages) {
1731
+ messagesMap.set(message.id, message);
1732
+ }
1733
+ this.#feedMessagesSignal.mutate((state) => {
1734
+ state.version++;
1735
+ });
1736
+ }
1737
+ /**
1738
+ * Removes feed messages from the cache (for deleted operations).
1739
+ */
1740
+ deleteFeedMessages(_roomId, feedId, messages) {
1741
+ const messagesMap = this.#feedMessagesByFeedId.get(feedId);
1742
+ if (!messagesMap) return;
1743
+ for (const message of messages) {
1744
+ messagesMap.delete(message.id);
1745
+ }
1746
+ this.#feedMessagesSignal.mutate((state) => {
1747
+ state.version++;
1748
+ });
1749
+ }
1589
1750
  async fetchUnreadNotificationsCount(queryKey, signal) {
1590
1751
  const query = JSON.parse(queryKey);
1591
1752
  const result = await this.#client.getUnreadInboxNotificationsCount({
@@ -3575,6 +3736,14 @@ function makeRoomContextBundle(client) {
3575
3736
  // prettier-ignore
3576
3737
  useMutation,
3577
3738
  useThreads,
3739
+ useFeeds,
3740
+ useFeedMessages,
3741
+ useCreateFeed,
3742
+ useDeleteFeed,
3743
+ useUpdateFeedMetadata,
3744
+ useCreateFeedMessage,
3745
+ useDeleteFeedMessage,
3746
+ useUpdateFeedMessage,
3578
3747
  useSearchComments,
3579
3748
  // prettier-ignore
3580
3749
  useCreateThread,
@@ -3624,6 +3793,14 @@ function makeRoomContextBundle(client) {
3624
3793
  // prettier-ignore
3625
3794
  useMutation,
3626
3795
  useThreads: useThreadsSuspense,
3796
+ useFeeds: useFeedsSuspense,
3797
+ useFeedMessages: useFeedMessagesSuspense,
3798
+ useCreateFeed,
3799
+ useDeleteFeed,
3800
+ useUpdateFeedMetadata,
3801
+ useCreateFeedMessage,
3802
+ useDeleteFeedMessage,
3803
+ useUpdateFeedMessage,
3627
3804
  // prettier-ignore
3628
3805
  useCreateThread,
3629
3806
  useDeleteThread,
@@ -3763,6 +3940,33 @@ function RoomProviderInner(props) {
3763
3940
  (message) => void handleCommentEvent(message)
3764
3941
  );
3765
3942
  }, [client, room]);
3943
+ useEffect6(() => {
3944
+ const { store } = getRoomExtrasForClient(client);
3945
+ function handleFeedEvent(message) {
3946
+ switch (message.type) {
3947
+ case ServerMsgCode.FEEDS_ADDED:
3948
+ case ServerMsgCode.FEEDS_UPDATED:
3949
+ store.upsertFeeds(room.id, message.feeds);
3950
+ break;
3951
+ case ServerMsgCode.FEEDS_DELETED:
3952
+ store.deleteFeeds(room.id, message.feeds);
3953
+ break;
3954
+ case ServerMsgCode.FEED_MESSAGES_ADDED:
3955
+ case ServerMsgCode.FEED_MESSAGES_UPDATED:
3956
+ store.upsertFeedMessages(room.id, message.feedId, message.messages);
3957
+ break;
3958
+ case ServerMsgCode.FEED_MESSAGES_DELETED:
3959
+ store.deleteFeedMessages(room.id, message.feedId, message.messages);
3960
+ break;
3961
+ // FEEDS_LIST and FEED_MESSAGES_LIST are handled by fetch promise resolution in room.ts
3962
+ default:
3963
+ break;
3964
+ }
3965
+ }
3966
+ return room.events.feeds.subscribe(
3967
+ (message) => void handleFeedEvent(message)
3968
+ );
3969
+ }, [client, room]);
3766
3970
  useEffect6(() => {
3767
3971
  const pair = stableEnterRoom(roomId, frozenProps);
3768
3972
  setRoomLeavePair(pair);
@@ -4088,6 +4292,92 @@ function useThreads(options = {}) {
4088
4292
  useScrollToCommentOnLoadEffect(scrollOnLoad, result);
4089
4293
  return result;
4090
4294
  }
4295
+ function useFeeds(options) {
4296
+ const room = useRoom();
4297
+ const client = useClient();
4298
+ const { store } = getRoomExtrasForClient(client);
4299
+ const queryKey = makeFeedsQueryKey(room.id, options);
4300
+ const loadableResource = store.outputs.loadingFeeds.getOrCreate(queryKey);
4301
+ useEffect6(() => {
4302
+ void loadableResource.waitUntilLoaded();
4303
+ });
4304
+ return useSignal(loadableResource.signal);
4305
+ }
4306
+ function useFeedMessages(feedId, options) {
4307
+ const room = useRoom();
4308
+ const client = useClient();
4309
+ const { store } = getRoomExtrasForClient(client);
4310
+ const queryKey = makeFeedMessagesQueryKey(room.id, feedId, options);
4311
+ useEffect6(() => {
4312
+ void store.outputs.loadingFeedMessages.getOrCreate(queryKey).waitUntilLoaded();
4313
+ });
4314
+ return useSignal(
4315
+ store.outputs.loadingFeedMessages.getOrCreate(queryKey).signal
4316
+ );
4317
+ }
4318
+ function useFeedsSuspense(options) {
4319
+ ensureNotServerSide();
4320
+ const client = useClient();
4321
+ const room = useRoom();
4322
+ const { store } = getRoomExtrasForClient(client);
4323
+ const queryKey = makeFeedsQueryKey(room.id, options);
4324
+ use(store.outputs.loadingFeeds.getOrCreate(queryKey).waitUntilLoaded());
4325
+ const result = useFeeds(options);
4326
+ assert2(!result.error, "Did not expect error");
4327
+ assert2(!result.isLoading, "Did not expect loading");
4328
+ return result;
4329
+ }
4330
+ function useFeedMessagesSuspense(feedId, options) {
4331
+ ensureNotServerSide();
4332
+ const client = useClient();
4333
+ const room = useRoom();
4334
+ const { store } = getRoomExtrasForClient(client);
4335
+ const queryKey = makeFeedMessagesQueryKey(room.id, feedId, options);
4336
+ use(store.outputs.loadingFeedMessages.getOrCreate(queryKey).waitUntilLoaded());
4337
+ const result = useFeedMessages(feedId, options);
4338
+ assert2(!result.error, "Did not expect error");
4339
+ assert2(!result.isLoading, "Did not expect loading");
4340
+ return result;
4341
+ }
4342
+ function useCreateFeed() {
4343
+ const room = useRoom();
4344
+ return useCallback3(
4345
+ (feedId, options) => room.addFeed(feedId, options),
4346
+ [room]
4347
+ );
4348
+ }
4349
+ function useDeleteFeed() {
4350
+ const room = useRoom();
4351
+ return useCallback3((feedId) => room.deleteFeed(feedId), [room]);
4352
+ }
4353
+ function useUpdateFeedMetadata() {
4354
+ const room = useRoom();
4355
+ return useCallback3(
4356
+ (feedId, metadata) => room.updateFeed(feedId, metadata),
4357
+ [room]
4358
+ );
4359
+ }
4360
+ function useCreateFeedMessage() {
4361
+ const room = useRoom();
4362
+ return useCallback3(
4363
+ (feedId, data, options) => room.addFeedMessage(feedId, data, options),
4364
+ [room]
4365
+ );
4366
+ }
4367
+ function useDeleteFeedMessage() {
4368
+ const room = useRoom();
4369
+ return useCallback3(
4370
+ (feedId, messageId) => room.deleteFeedMessage(feedId, messageId),
4371
+ [room]
4372
+ );
4373
+ }
4374
+ function useUpdateFeedMessage() {
4375
+ const room = useRoom();
4376
+ return useCallback3(
4377
+ (feedId, messageId, data) => room.updateFeedMessage(feedId, messageId, data),
4378
+ [room]
4379
+ );
4380
+ }
4091
4381
  function useSearchComments(options) {
4092
4382
  const [result, setResult] = useState3({
4093
4383
  isLoading: true
@@ -5093,6 +5383,10 @@ var _useMyPresence = useMyPresence;
5093
5383
  var _useOthersMapped = useOthersMapped;
5094
5384
  var _useOthersMappedSuspense = useOthersMappedSuspense;
5095
5385
  var _useThreads = useThreads;
5386
+ var _useFeeds = useFeeds;
5387
+ var _useFeedMessages = useFeedMessages;
5388
+ var _useFeedsSuspense = useFeedsSuspense;
5389
+ var _useFeedMessagesSuspense = useFeedMessagesSuspense;
5096
5390
  var _useSearchComments = useSearchComments;
5097
5391
  var _useThreadsSuspense = useThreadsSuspense;
5098
5392
  var _useRoomSubscriptionSettings = useRoomSubscriptionSettings;
@@ -5179,6 +5473,12 @@ export {
5179
5473
  useCanUndo,
5180
5474
  useCanRedo,
5181
5475
  useOthersConnectionIds,
5476
+ useCreateFeed,
5477
+ useDeleteFeed,
5478
+ useUpdateFeedMetadata,
5479
+ useCreateFeedMessage,
5480
+ useDeleteFeedMessage,
5481
+ useUpdateFeedMessage,
5182
5482
  useCreateRoomThread,
5183
5483
  useDeleteRoomThread,
5184
5484
  useEditRoomThreadMetadata,
@@ -5225,6 +5525,10 @@ export {
5225
5525
  _useOthersMapped,
5226
5526
  _useOthersMappedSuspense,
5227
5527
  _useThreads,
5528
+ _useFeeds,
5529
+ _useFeedMessages,
5530
+ _useFeedsSuspense,
5531
+ _useFeedMessagesSuspense,
5228
5532
  _useSearchComments,
5229
5533
  _useThreadsSuspense,
5230
5534
  _useRoomSubscriptionSettings,
@@ -5242,4 +5546,4 @@ export {
5242
5546
  _useStorageRoot,
5243
5547
  _useUpdateMyPresence
5244
5548
  };
5245
- //# sourceMappingURL=chunk-EB7KWKMS.js.map
5549
+ //# sourceMappingURL=chunk-JQZ4SSGD.js.map