@liveblocks/react 3.6.2 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -295,7 +295,6 @@ import {
295
295
  createNotificationSettings,
296
296
  DefaultMap,
297
297
  DerivedSignal,
298
- getMentionsFromCommentBody,
299
298
  getSubscriptionKey,
300
299
  kInternal as kInternal2,
301
300
  MutableSignal as MutableSignal3,
@@ -492,6 +491,9 @@ function makeUserThreadsQueryKey(query) {
492
491
  function makeAiChatsQueryKey(query) {
493
492
  return stableStringify(query ?? {});
494
493
  }
494
+ function makeInboxNotificationsQueryKey(query) {
495
+ return stableStringify(query ?? {});
496
+ }
495
497
  function usify(promise) {
496
498
  if ("status" in promise) {
497
499
  return promise;
@@ -920,7 +922,6 @@ var UmbrellaStore = class {
920
922
  // Notifications
921
923
  #notificationsLastRequestedAt = null;
922
924
  // Keeps track of when we successfully requested an inbox notifications update for the last time. Will be `null` as long as the first successful fetch hasn't happened yet.
923
- #notificationsPaginationState;
924
925
  // Room Threads
925
926
  #roomThreadsLastRequestedAtByRoom = /* @__PURE__ */ new Map();
926
927
  // User Threads
@@ -933,21 +934,6 @@ var UmbrellaStore = class {
933
934
  this.#client = client[kInternal2].as();
934
935
  this.optimisticUpdates = createStore_forOptimistic(this.#client);
935
936
  this.permissionHints = createStore_forPermissionHints();
936
- this.#notificationsPaginationState = new PaginatedResource(
937
- async (cursor) => {
938
- const result = await this.#client.getInboxNotifications({ cursor });
939
- this.updateThreadifications(
940
- result.threads,
941
- result.inboxNotifications,
942
- result.subscriptions
943
- );
944
- if (this.#notificationsLastRequestedAt === null) {
945
- this.#notificationsLastRequestedAt = result.requestedAt;
946
- }
947
- const nextCursor = result.nextCursor;
948
- return nextCursor;
949
- }
950
- );
951
937
  const notificationSettingsFetcher = async () => {
952
938
  const result = await this.#client.getNotificationSettings();
953
939
  this.notificationSettings.update(result);
@@ -1077,25 +1063,46 @@ var UmbrellaStore = class {
1077
1063
  return { signal, waitUntilLoaded: resource.waitUntilLoaded };
1078
1064
  }
1079
1065
  );
1080
- const loadingNotifications = {
1081
- signal: DerivedSignal.from(() => {
1082
- const resource = this.#notificationsPaginationState;
1083
- const result = resource.get();
1084
- if (result.isLoading || result.error) {
1085
- return result;
1086
- }
1087
- const page = result.data;
1066
+ const loadingNotifications = new DefaultMap(
1067
+ (queryKey) => {
1068
+ const query = JSON.parse(queryKey);
1069
+ const resource = new PaginatedResource(async (cursor) => {
1070
+ const result = await this.#client.getInboxNotifications({
1071
+ cursor,
1072
+ query
1073
+ });
1074
+ this.updateThreadifications(
1075
+ result.threads,
1076
+ result.inboxNotifications,
1077
+ result.subscriptions
1078
+ );
1079
+ if (this.#notificationsLastRequestedAt === null) {
1080
+ this.#notificationsLastRequestedAt = result.requestedAt;
1081
+ }
1082
+ const nextCursor = result.nextCursor;
1083
+ return nextCursor;
1084
+ });
1085
+ const signal = DerivedSignal.from(() => {
1086
+ const result = resource.get();
1087
+ if (result.isLoading || result.error) {
1088
+ return result;
1089
+ }
1090
+ const page = result.data;
1091
+ return {
1092
+ isLoading: false,
1093
+ inboxNotifications: this.outputs.notifications.get().sortedNotifications,
1094
+ hasFetchedAll: page.hasFetchedAll,
1095
+ isFetchingMore: page.isFetchingMore,
1096
+ fetchMoreError: page.fetchMoreError,
1097
+ fetchMore: page.fetchMore
1098
+ };
1099
+ }, shallow2);
1088
1100
  return {
1089
- isLoading: false,
1090
- inboxNotifications: this.outputs.notifications.get().sortedNotifications,
1091
- hasFetchedAll: page.hasFetchedAll,
1092
- isFetchingMore: page.isFetchingMore,
1093
- fetchMoreError: page.fetchMoreError,
1094
- fetchMore: page.fetchMore
1101
+ signal,
1102
+ waitUntilLoaded: resource.waitUntilLoaded
1095
1103
  };
1096
- }),
1097
- waitUntilLoaded: this.#notificationsPaginationState.waitUntilLoaded
1098
- };
1104
+ }
1105
+ );
1099
1106
  const roomSubscriptionSettingsByRoomId = new DefaultMap(
1100
1107
  (roomId) => {
1101
1108
  const resource = new SinglePageResource(async () => {
@@ -1741,15 +1748,7 @@ function applyOptimisticUpdates_forSubscriptions(subscriptionsLUT, threads, opti
1741
1748
  delete subscriptions[subscriptionKey];
1742
1749
  break;
1743
1750
  }
1744
- // Create subscriptions for every threads in the room which the user participates in but doesn't have a subscription for yet
1745
1751
  case "replies_and_mentions": {
1746
- if (isThreadParticipant(thread, update.userId) && !subscriptions[subscriptionKey]) {
1747
- subscriptions[subscriptionKey] = {
1748
- kind: "thread",
1749
- subjectId: thread.id,
1750
- createdAt: /* @__PURE__ */ new Date()
1751
- };
1752
- }
1753
1752
  break;
1754
1753
  }
1755
1754
  default:
@@ -1950,27 +1949,6 @@ function upsertReaction(reactions, reaction) {
1950
1949
  }
1951
1950
  return reactions;
1952
1951
  }
1953
- function isThreadParticipant(thread, userId) {
1954
- let isParticipant = false;
1955
- for (const comment of thread.comments) {
1956
- if (comment.deletedAt) {
1957
- continue;
1958
- }
1959
- if (comment.userId === userId) {
1960
- isParticipant = true;
1961
- break;
1962
- }
1963
- const mentions = getMentionsFromCommentBody(
1964
- comment.body,
1965
- (mention) => mention.kind === "user" && mention.id === userId
1966
- );
1967
- if (mentions.length > 0) {
1968
- isParticipant = true;
1969
- break;
1970
- }
1971
- }
1972
- return isParticipant;
1973
- }
1974
1952
 
1975
1953
  // src/liveblocks.tsx
1976
1954
  import { jsx } from "react/jsx-runtime";
@@ -1982,6 +1960,11 @@ function missingRoomInfoError(roomId) {
1982
1960
  `resolveRoomsInfo didn't return anything for room '${roomId}'`
1983
1961
  );
1984
1962
  }
1963
+ function missingGroupInfoError(groupId) {
1964
+ return new Error(
1965
+ `resolveGroupsInfo didn't return anything for group '${groupId}'`
1966
+ );
1967
+ }
1985
1968
  function identity2(x) {
1986
1969
  return x;
1987
1970
  }
@@ -2036,6 +2019,24 @@ function selectorFor_useRoomInfo(state, roomId) {
2036
2019
  info: state.data
2037
2020
  };
2038
2021
  }
2022
+ function selectorFor_useGroupInfo(state, groupId) {
2023
+ if (state === void 0 || state?.isLoading) {
2024
+ return state ?? { isLoading: true };
2025
+ }
2026
+ if (state.error) {
2027
+ return state;
2028
+ }
2029
+ if (!state.data) {
2030
+ return {
2031
+ isLoading: false,
2032
+ error: missingGroupInfoError(groupId)
2033
+ };
2034
+ }
2035
+ return {
2036
+ isLoading: false,
2037
+ info: state.data
2038
+ };
2039
+ }
2039
2040
  function getOrCreateContextBundle(client) {
2040
2041
  let bundle = _bundles.get(client);
2041
2042
  if (!bundle) {
@@ -2126,7 +2127,7 @@ function makeLiveblocksContextBundle(client) {
2126
2127
  const shared = createSharedContext(client);
2127
2128
  const bundle = {
2128
2129
  LiveblocksProvider: LiveblocksProvider2,
2129
- useInboxNotifications: () => useInboxNotifications_withClient(client, identity2, shallow3),
2130
+ useInboxNotifications: (options) => useInboxNotifications_withClient(client, identity2, shallow3, options),
2130
2131
  useUnreadInboxNotificationsCount: () => useUnreadInboxNotificationsCount_withClient(client),
2131
2132
  useMarkInboxNotificationAsRead: useMarkInboxNotificationAsRead2,
2132
2133
  useMarkAllInboxNotificationsAsRead: useMarkAllInboxNotificationsAsRead2,
@@ -2145,7 +2146,7 @@ function makeLiveblocksContextBundle(client) {
2145
2146
  ...shared.classic,
2146
2147
  suspense: {
2147
2148
  LiveblocksProvider: LiveblocksProvider2,
2148
- useInboxNotifications: () => useInboxNotificationsSuspense_withClient(client),
2149
+ useInboxNotifications: (options) => useInboxNotificationsSuspense_withClient(client, options),
2149
2150
  useUnreadInboxNotificationsCount: () => useUnreadInboxNotificationsCountSuspense_withClient(client),
2150
2151
  useMarkInboxNotificationAsRead: useMarkInboxNotificationAsRead2,
2151
2152
  useMarkAllInboxNotificationsAsRead: useMarkAllInboxNotificationsAsRead2,
@@ -2166,10 +2167,11 @@ function makeLiveblocksContextBundle(client) {
2166
2167
  };
2167
2168
  return bundle;
2168
2169
  }
2169
- function useInboxNotifications_withClient(client, selector, isEqual) {
2170
+ function useInboxNotifications_withClient(client, selector, isEqual, options) {
2170
2171
  const { store, notificationsPoller: poller } = getLiveblocksExtrasForClient(client);
2172
+ const queryKey = makeInboxNotificationsQueryKey(options?.query);
2171
2173
  useEffect4(
2172
- () => void store.outputs.loadingNotifications.waitUntilLoaded()
2174
+ () => void store.outputs.loadingNotifications.getOrCreate(queryKey).waitUntilLoaded()
2173
2175
  // NOTE: Deliberately *not* using a dependency array here!
2174
2176
  //
2175
2177
  // It is important to call waitUntil on *every* render.
@@ -2187,16 +2189,24 @@ function useInboxNotifications_withClient(client, selector, isEqual) {
2187
2189
  };
2188
2190
  }, [poller]);
2189
2191
  return useSignal(
2190
- store.outputs.loadingNotifications.signal,
2192
+ store.outputs.loadingNotifications.getOrCreate(queryKey).signal,
2191
2193
  selector,
2192
2194
  isEqual
2193
2195
  );
2194
2196
  }
2195
- function useInboxNotificationsSuspense_withClient(client) {
2197
+ function useInboxNotificationsSuspense_withClient(client, options) {
2196
2198
  ensureNotServerSide();
2197
2199
  const store = getLiveblocksExtrasForClient(client).store;
2198
- use(store.outputs.loadingNotifications.waitUntilLoaded());
2199
- const result = useInboxNotifications_withClient(client, identity2, shallow3);
2200
+ const queryKey = makeInboxNotificationsQueryKey(options?.query);
2201
+ use(
2202
+ store.outputs.loadingNotifications.getOrCreate(queryKey).waitUntilLoaded()
2203
+ );
2204
+ const result = useInboxNotifications_withClient(
2205
+ client,
2206
+ identity2,
2207
+ shallow3,
2208
+ options
2209
+ );
2200
2210
  assert(!result.error, "Did not expect error");
2201
2211
  assert(!result.isLoading, "Did not expect loading");
2202
2212
  return result;
@@ -2211,7 +2221,10 @@ function useUnreadInboxNotificationsCount_withClient(client) {
2211
2221
  function useUnreadInboxNotificationsCountSuspense_withClient(client) {
2212
2222
  ensureNotServerSide();
2213
2223
  const store = getLiveblocksExtrasForClient(client).store;
2214
- use(store.outputs.loadingNotifications.waitUntilLoaded());
2224
+ const queryKey = makeInboxNotificationsQueryKey(void 0);
2225
+ use(
2226
+ store.outputs.loadingNotifications.getOrCreate(queryKey).waitUntilLoaded()
2227
+ );
2215
2228
  const result = useUnreadInboxNotificationsCount_withClient(client);
2216
2229
  assert(!result.isLoading, "Did not expect loading");
2217
2230
  assert(!result.error, "Did not expect error");
@@ -2533,6 +2546,68 @@ function useRoomInfoSuspense_withClient(client, roomId) {
2533
2546
  error: void 0
2534
2547
  };
2535
2548
  }
2549
+ function useGroupInfo_withClient(client, groupId) {
2550
+ const groupsInfoStore = client[kInternal3].groupsInfoStore;
2551
+ const getGroupInfoState = useCallback2(
2552
+ () => groupsInfoStore.getItemState(groupId),
2553
+ [groupsInfoStore, groupId]
2554
+ );
2555
+ const selector = useCallback2(
2556
+ (state) => selectorFor_useGroupInfo(state, groupId),
2557
+ [groupId]
2558
+ );
2559
+ const result = useSyncExternalStoreWithSelector(
2560
+ groupsInfoStore.subscribe,
2561
+ getGroupInfoState,
2562
+ getGroupInfoState,
2563
+ selector,
2564
+ shallow3
2565
+ );
2566
+ useEffect4(
2567
+ () => void groupsInfoStore.enqueue(groupId)
2568
+ // NOTE: Deliberately *not* using a dependency array here!
2569
+ //
2570
+ // It is important to call groupsInfoStore.enqueue on *every* render.
2571
+ // This is harmless though, on most renders, except:
2572
+ // 1. The very first render, in which case we'll want to trigger evaluation
2573
+ // of the groupId.
2574
+ // 2. All other subsequent renders now are a no-op (from the implementation
2575
+ // of .enqueue)
2576
+ // 3. If ever the groupId gets invalidated, the group info would be fetched again.
2577
+ );
2578
+ return result;
2579
+ }
2580
+ function useGroupInfoSuspense_withClient(client, groupId) {
2581
+ const groupsInfoStore = client[kInternal3].groupsInfoStore;
2582
+ const getGroupInfoState = useCallback2(
2583
+ () => groupsInfoStore.getItemState(groupId),
2584
+ [groupsInfoStore, groupId]
2585
+ );
2586
+ const groupInfoState = getGroupInfoState();
2587
+ if (!groupInfoState || groupInfoState.isLoading) {
2588
+ throw groupsInfoStore.enqueue(groupId);
2589
+ }
2590
+ if (groupInfoState.error) {
2591
+ throw groupInfoState.error;
2592
+ }
2593
+ if (!groupInfoState.data) {
2594
+ throw missingGroupInfoError(groupId);
2595
+ }
2596
+ const state = useSyncExternalStore2(
2597
+ groupsInfoStore.subscribe,
2598
+ getGroupInfoState,
2599
+ getGroupInfoState
2600
+ );
2601
+ assert(state !== void 0, "Unexpected missing state");
2602
+ assert(!state.isLoading, "Unexpected loading state");
2603
+ assert(!state.error, "Unexpected error state");
2604
+ assert(state.data !== void 0, "Unexpected missing group info data");
2605
+ return {
2606
+ isLoading: false,
2607
+ info: state.data,
2608
+ error: void 0
2609
+ };
2610
+ }
2536
2611
  function useAiChats(options) {
2537
2612
  const client = useClient();
2538
2613
  const store = getUmbrellaStoreForClient(client);
@@ -2736,6 +2811,7 @@ function createSharedContext(client) {
2736
2811
  useClient: useClient2,
2737
2812
  useUser: (userId) => useUser_withClient(client, userId),
2738
2813
  useRoomInfo: (roomId) => useRoomInfo_withClient(client, roomId),
2814
+ useGroupInfo: (groupId) => useGroupInfo_withClient(client, groupId),
2739
2815
  useIsInsideRoom,
2740
2816
  useErrorListener,
2741
2817
  useSyncStatus: useSyncStatus2,
@@ -2746,6 +2822,7 @@ function createSharedContext(client) {
2746
2822
  useClient: useClient2,
2747
2823
  useUser: (userId) => useUserSuspense_withClient(client, userId),
2748
2824
  useRoomInfo: (roomId) => useRoomInfoSuspense_withClient(client, roomId),
2825
+ useGroupInfo: (groupId) => useGroupInfoSuspense_withClient(client, groupId),
2749
2826
  useIsInsideRoom,
2750
2827
  useErrorListener,
2751
2828
  useSyncStatus: useSyncStatus2,
@@ -2783,6 +2860,7 @@ function LiveblocksProvider(props) {
2783
2860
  ),
2784
2861
  resolveUsers: useInitialUnlessFunction(o.resolveUsers),
2785
2862
  resolveRoomsInfo: useInitialUnlessFunction(o.resolveRoomsInfo),
2863
+ resolveGroupsInfo: useInitialUnlessFunction(o.resolveGroupsInfo),
2786
2864
  baseUrl: useInitial(
2787
2865
  // @ts-expect-error - Hidden config options
2788
2866
  o.baseUrl
@@ -2840,11 +2918,16 @@ function useUserThreadsSuspense_experimental(options = {}) {
2840
2918
  assert(!result.isLoading, "Did not expect loading");
2841
2919
  return result;
2842
2920
  }
2843
- function useInboxNotifications() {
2844
- return useInboxNotifications_withClient(useClient(), identity2, shallow3);
2921
+ function useInboxNotifications(options) {
2922
+ return useInboxNotifications_withClient(
2923
+ useClient(),
2924
+ identity2,
2925
+ shallow3,
2926
+ options
2927
+ );
2845
2928
  }
2846
- function useInboxNotificationsSuspense() {
2847
- return useInboxNotificationsSuspense_withClient(useClient());
2929
+ function useInboxNotificationsSuspense(options) {
2930
+ return useInboxNotificationsSuspense_withClient(useClient(), options);
2848
2931
  }
2849
2932
  function useInboxNotificationThread(inboxNotificationId) {
2850
2933
  return useInboxNotificationThread_withClient(
@@ -2893,6 +2976,12 @@ function useRoomInfo(roomId) {
2893
2976
  function useRoomInfoSuspense(roomId) {
2894
2977
  return useRoomInfoSuspense_withClient(useClient(), roomId);
2895
2978
  }
2979
+ function useGroupInfo(groupId) {
2980
+ return useGroupInfo_withClient(useClient(), groupId);
2981
+ }
2982
+ function useGroupInfoSuspense(groupId) {
2983
+ return useGroupInfoSuspense_withClient(useClient(), groupId);
2984
+ }
2896
2985
  var _useInboxNotificationThread = useInboxNotificationThread;
2897
2986
  var _useUser = useUser;
2898
2987
  var _useUserSuspense = useUserSuspense;
@@ -3424,10 +3513,10 @@ function useYjsProvider() {
3424
3513
  function useCreateTextMention() {
3425
3514
  const room = useRoom();
3426
3515
  return useCallback3(
3427
- (userId, mentionId) => {
3428
- room[kInternal4].createTextMention(userId, mentionId).catch((err) => {
3516
+ (mentionId, mention) => {
3517
+ room[kInternal4].createTextMention(mentionId, mention).catch((err) => {
3429
3518
  console3.error(
3430
- `Cannot create text mention for user '${userId}' and mention '${mentionId}'`,
3519
+ `Cannot create text mention for mention '${mentionId}'`,
3431
3520
  err
3432
3521
  );
3433
3522
  });
@@ -4604,6 +4693,8 @@ export {
4604
4693
  useUpdateNotificationSettings,
4605
4694
  useRoomInfo,
4606
4695
  useRoomInfoSuspense,
4696
+ useGroupInfo,
4697
+ useGroupInfoSuspense,
4607
4698
  _useInboxNotificationThread,
4608
4699
  _useUser,
4609
4700
  _useUserSuspense,
@@ -4692,4 +4783,4 @@ export {
4692
4783
  _useStorageRoot,
4693
4784
  _useUpdateMyPresence
4694
4785
  };
4695
- //# sourceMappingURL=chunk-I2UW4JM4.js.map
4786
+ //# sourceMappingURL=chunk-WGUV4Z4E.js.map