@liveblocks/react 1.10.0-beta1 → 1.10.0-beta3

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.js CHANGED
@@ -5,7 +5,7 @@ var _core = require('@liveblocks/core');
5
5
 
6
6
  // src/version.ts
7
7
  var PKG_NAME = "@liveblocks/react";
8
- var PKG_VERSION = "1.10.0-beta1";
8
+ var PKG_VERSION = "1.10.0-beta3";
9
9
  var PKG_FORMAT = "cjs";
10
10
 
11
11
  // src/ClientSideSuspense.tsx
@@ -34,7 +34,10 @@ var _withselectorjs = require('use-sync-external-store/shim/with-selector.js');
34
34
 
35
35
  function selectedInboxNotifications(state) {
36
36
  const result = _core.applyOptimisticUpdates.call(void 0, state);
37
- return Object.values(result.inboxNotifications);
37
+ return Object.values(result.inboxNotifications).sort(
38
+ // Sort so that the most recent notifications are first
39
+ (a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime()
40
+ );
38
41
  }
39
42
 
40
43
  // src/shared.ts
@@ -153,9 +156,10 @@ function createCommentId() {
153
156
 
154
157
 
155
158
 
159
+
156
160
  function selectNotificationSettings(roomId, state) {
157
161
  const { notificationSettings } = _core.applyOptimisticUpdates.call(void 0, state);
158
- return notificationSettings[roomId];
162
+ return _core.nn.call(void 0, notificationSettings[roomId]);
159
163
  }
160
164
 
161
165
  // src/comments/lib/selected-threads.ts
@@ -164,9 +168,12 @@ function selectNotificationSettings(roomId, state) {
164
168
 
165
169
  function selectedThreads(roomId, state, options) {
166
170
  const result = _core.applyOptimisticUpdates.call(void 0, state);
167
- return Object.values(result.threads).filter((thread) => {
171
+ const threads = Object.values(result.threads).filter((thread) => {
168
172
  if (thread.roomId !== roomId)
169
173
  return false;
174
+ if (thread.deletedAt !== void 0) {
175
+ return false;
176
+ }
170
177
  const query = options.query;
171
178
  if (!query)
172
179
  return true;
@@ -177,6 +184,7 @@ function selectedThreads(roomId, state, options) {
177
184
  }
178
185
  return true;
179
186
  });
187
+ return threads.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
180
188
  }
181
189
 
182
190
  // src/comments/lib/upsert-comment.ts
@@ -299,7 +307,17 @@ function useRoomContextBundle() {
299
307
  }
300
308
  return bundle;
301
309
  }
302
- function createRoomContext(client) {
310
+ function createRoomContext(client, options) {
311
+ if (_optionalChain([options, 'optionalAccess', _ => _.resolveUsers])) {
312
+ throw new Error(
313
+ "The 'resolveUsers' option has moved to 'createClient' from '@liveblocks/client'. Please refer to our Upgrade Guide to learn more, see https://liveblocks.io/docs/platform/upgrading/1.10."
314
+ );
315
+ }
316
+ if (_optionalChain([options, 'optionalAccess', _2 => _2.resolveMentionSuggestions])) {
317
+ throw new Error(
318
+ "The 'resolveMentionSuggestions' option has moved to 'createClient' from '@liveblocks/client'. Please refer to our Upgrade Guide to learn more, see https://liveblocks.io/docs/platform/upgrading/1.10."
319
+ );
320
+ }
303
321
  const RoomContext = React2.createContext(null);
304
322
  const commentsErrorEventSource = _core.makeEventSource.call(void 0, );
305
323
  const shared = createSharedContext(client);
@@ -308,13 +326,13 @@ function createRoomContext(client) {
308
326
  () => /* @__PURE__ */ new Map()
309
327
  );
310
328
  const stableEnterRoom = React2.useCallback(
311
- (roomId, options) => {
329
+ (roomId, options2) => {
312
330
  const cached = cache.get(roomId);
313
331
  if (cached)
314
332
  return cached;
315
333
  const rv = client.enterRoom(
316
334
  roomId,
317
- options
335
+ options2
318
336
  );
319
337
  const origLeave = rv.leave;
320
338
  rv.leave = () => {
@@ -507,8 +525,8 @@ function createRoomContext(client) {
507
525
  function useBroadcastEvent() {
508
526
  const room = useRoom();
509
527
  return React2.useCallback(
510
- (event, options = { shouldQueueEventIfNotReady: false }) => {
511
- room.broadcastEvent(event, options);
528
+ (event, options2 = { shouldQueueEventIfNotReady: false }) => {
529
+ room.broadcastEvent(event, options2);
512
530
  },
513
531
  [room]
514
532
  );
@@ -618,7 +636,7 @@ function createRoomContext(client) {
618
636
  function onRootChange() {
619
637
  const newValue = root.get(key);
620
638
  if (newValue !== curr) {
621
- _optionalChain([unsubCurr, 'optionalCall', _2 => _2()]);
639
+ _optionalChain([unsubCurr, 'optionalCall', _3 => _3()]);
622
640
  curr = newValue;
623
641
  subscribeToCurr();
624
642
  rerender();
@@ -629,7 +647,7 @@ function createRoomContext(client) {
629
647
  const unsubscribeRoot = room.subscribe(root, onRootChange);
630
648
  return () => {
631
649
  unsubscribeRoot();
632
- _optionalChain([unsubCurr, 'optionalCall', _3 => _3()]);
650
+ _optionalChain([unsubCurr, 'optionalCall', _4 => _4()]);
633
651
  };
634
652
  }, [rootOrNull, room, key, rerender]);
635
653
  if (rootOrNull === null) {
@@ -775,15 +793,46 @@ function createRoomContext(client) {
775
793
  const requestsCache = /* @__PURE__ */ new Map();
776
794
  const poller = _core.makePoller.call(void 0, refreshThreadsAndNotifications);
777
795
  async function refreshThreadsAndNotifications() {
778
- await Promise.allSettled(
779
- Array.from(requestsCache.entries()).filter(([_, requestCache]) => requestCache.subscribers > 0).map(async ([_, requestCache]) => {
780
- return requestCache.requestFactory().then(
781
- (result) => requestCache.onSuccess(result),
782
- () => {
783
- }
796
+ const requests = [];
797
+ client[_core.kInternal].getRoomIds().map((roomId) => {
798
+ const room = client.getRoom(roomId);
799
+ if (room === null)
800
+ return;
801
+ const notificationSettingsQuery = makeNotificationSettingsQueryKey(
802
+ room.id
803
+ );
804
+ if (requestsCache.has(notificationSettingsQuery)) {
805
+ requests.push(
806
+ room.getRoomNotificationSettings().then((settings) => {
807
+ store.updateRoomInboxNotificationSettings(
808
+ room.id,
809
+ settings,
810
+ notificationSettingsQuery
811
+ );
812
+ }).catch(() => {
813
+ })
784
814
  );
785
- })
786
- );
815
+ }
816
+ const lastRequestedAt = room[_core.kInternal].comments.lastRequestedAt;
817
+ if (lastRequestedAt === null)
818
+ return;
819
+ requests.push(
820
+ room.getThreads({ since: lastRequestedAt }).then((result) => {
821
+ store.updateThreadsAndNotifications(
822
+ result.threads,
823
+ result.inboxNotifications,
824
+ result.deletedThreads,
825
+ result.deletedInboxNotifications
826
+ );
827
+ const room2 = client.getRoom(roomId);
828
+ if (room2 === null)
829
+ return;
830
+ room2[_core.kInternal].comments.lastRequestedAt = result.meta.requestedAt;
831
+ }).catch(() => {
832
+ })
833
+ );
834
+ });
835
+ await Promise.allSettled(requests);
787
836
  }
788
837
  function incrementQuerySubscribers(queryKey) {
789
838
  const requestCache = requestsCache.get(queryKey);
@@ -813,16 +862,14 @@ function createRoomContext(client) {
813
862
  poller.stop();
814
863
  }
815
864
  }
816
- async function getOrInitRequest(queryKey, requestFactory, onSuccess) {
865
+ async function getThreadsAndInboxNotifications(room, queryKey, options2) {
817
866
  const requestInfo = requestsCache.get(queryKey);
818
867
  if (requestInfo !== void 0) {
819
868
  return requestInfo.promise;
820
869
  }
821
- const promise = requestFactory();
870
+ const promise = room.getThreads(options2);
822
871
  requestsCache.set(queryKey, {
823
872
  promise,
824
- requestFactory,
825
- onSuccess,
826
873
  subscribers: 0
827
874
  });
828
875
  store.setQueryState(queryKey, {
@@ -830,103 +877,102 @@ function createRoomContext(client) {
830
877
  });
831
878
  try {
832
879
  const result = await promise;
833
- onSuccess(result);
834
- } catch (er) {
880
+ store.updateThreadsAndNotifications(
881
+ result.threads,
882
+ result.inboxNotifications,
883
+ result.deletedThreads,
884
+ result.deletedInboxNotifications,
885
+ queryKey
886
+ );
887
+ const lastRequestedAt = room[_core.kInternal].comments.lastRequestedAt;
888
+ if (lastRequestedAt === null || lastRequestedAt > result.meta.requestedAt) {
889
+ room[_core.kInternal].comments.lastRequestedAt = result.meta.requestedAt;
890
+ }
891
+ } catch (err) {
835
892
  store.setQueryState(queryKey, {
836
893
  isLoading: false,
837
- error: er
894
+ error: err
838
895
  });
839
896
  }
840
897
  poller.start(POLLING_INTERVAL);
841
898
  }
842
- async function getThreadsAndInboxNotifications(room, queryKey, options) {
843
- const roomId = room.id;
844
- return getOrInitRequest(
845
- queryKey,
846
- async () => {
847
- const room2 = client.getRoom(roomId);
848
- if (room2 === null) {
849
- return;
850
- }
851
- return room2.getThreads(options);
852
- },
853
- (result) => {
854
- if (result !== void 0) {
855
- store.updateThreadsAndNotifications(
856
- result.threads,
857
- result.inboxNotifications,
858
- queryKey
859
- );
860
- }
861
- }
862
- );
863
- }
864
- function useThreads(options = { query: { metadata: {} } }) {
899
+ function useThreads(options2 = { query: { metadata: {} } }) {
865
900
  const room = useRoom();
866
901
  const queryKey = React2.useMemo(
867
- () => generateQueryKey(room.id, options.query),
868
- [room, options]
902
+ () => generateQueryKey(room.id, options2.query),
903
+ [room, options2]
869
904
  );
870
905
  React2.useEffect(() => {
871
- void getThreadsAndInboxNotifications(room, queryKey, options);
906
+ void getThreadsAndInboxNotifications(room, queryKey, options2);
872
907
  incrementQuerySubscribers(queryKey);
873
908
  return () => decrementQuerySubscribers(queryKey);
874
909
  }, [room, queryKey]);
875
- return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
876
- store.subscribe,
877
- store.get,
878
- store.get,
910
+ const selector = React2.useCallback(
879
911
  (state) => {
880
- if (state.queries[queryKey] === void 0 || state.queries[queryKey].isLoading) {
912
+ const query = state.queries[queryKey];
913
+ if (query === void 0 || query.isLoading) {
881
914
  return {
882
915
  isLoading: true
883
916
  };
884
917
  }
885
918
  return {
886
- threads: selectedThreads(room.id, state, options),
919
+ threads: selectedThreads(room.id, state, options2),
887
920
  isLoading: false,
888
- error: state.queries[queryKey].error
921
+ error: query.error
889
922
  };
890
- }
923
+ },
924
+ [room, queryKey]
925
+ // eslint-disable-line react-hooks/exhaustive-deps
926
+ );
927
+ return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
928
+ store.subscribe,
929
+ store.get,
930
+ store.get,
931
+ selector
891
932
  );
892
933
  }
893
- function useThreadsSuspense(options = { query: { metadata: {} } }) {
934
+ function useThreadsSuspense(options2 = { query: { metadata: {} } }) {
894
935
  const room = useRoom();
895
936
  const queryKey = React2.useMemo(
896
- () => generateQueryKey(room.id, _optionalChain([options, 'optionalAccess', _4 => _4.query])),
897
- [room, options]
937
+ () => generateQueryKey(room.id, _optionalChain([options2, 'optionalAccess', _5 => _5.query])),
938
+ [room, options2]
898
939
  );
899
940
  const query = store.get().queries[queryKey];
900
941
  if (query === void 0 || query.isLoading) {
901
- throw getThreadsAndInboxNotifications(room, queryKey, options);
942
+ throw getThreadsAndInboxNotifications(room, queryKey, options2);
902
943
  }
903
944
  if (query.error) {
904
945
  throw query.error;
905
946
  }
947
+ const selector = React2.useCallback(
948
+ (state) => {
949
+ return {
950
+ threads: selectedThreads(room.id, state, options2),
951
+ isLoading: false
952
+ };
953
+ },
954
+ [room, queryKey]
955
+ // eslint-disable-line react-hooks/exhaustive-deps
956
+ );
906
957
  React2.useEffect(() => {
907
958
  incrementQuerySubscribers(queryKey);
908
959
  return () => {
909
960
  decrementQuerySubscribers(queryKey);
910
961
  };
911
- }, [room, queryKey]);
962
+ }, [queryKey]);
912
963
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
913
964
  store.subscribe,
914
965
  store.get,
915
966
  store.get,
916
- (state) => {
917
- return {
918
- threads: selectedThreads(room.id, state, options),
919
- isLoading: false
920
- };
921
- }
967
+ selector
922
968
  );
923
969
  }
924
970
  function useCreateThread() {
925
971
  const room = useRoom();
926
972
  return React2.useCallback(
927
- (options) => {
928
- const body = options.body;
929
- const metadata = "metadata" in options ? options.metadata : {};
973
+ (options2) => {
974
+ const body = options2.body;
975
+ const metadata = "metadata" in options2 ? options2.metadata : {};
930
976
  const threadId = createThreadId();
931
977
  const commentId = createCommentId();
932
978
  const now = /* @__PURE__ */ new Date();
@@ -987,12 +1033,12 @@ function createRoomContext(client) {
987
1033
  function useEditThreadMetadata() {
988
1034
  const room = useRoom();
989
1035
  return React2.useCallback(
990
- (options) => {
991
- if (!("metadata" in options)) {
1036
+ (options2) => {
1037
+ if (!("metadata" in options2)) {
992
1038
  return;
993
1039
  }
994
- const threadId = options.threadId;
995
- const metadata = options.metadata;
1040
+ const threadId = options2.threadId;
1041
+ const metadata = options2.metadata;
996
1042
  const optimisticUpdateId = _nanoid.nanoid.call(void 0, );
997
1043
  store.pushOptimisticUpdate({
998
1044
  type: "edit-thread-metadata",
@@ -1002,22 +1048,33 @@ function createRoomContext(client) {
1002
1048
  });
1003
1049
  room.editThreadMetadata({ metadata, threadId }).then(
1004
1050
  (metadata2) => {
1005
- store.set((state) => ({
1006
- ...state,
1007
- threads: {
1008
- ...state.threads,
1009
- [threadId]: {
1010
- ...state.threads[threadId],
1011
- metadata: {
1012
- ...state.threads[threadId].metadata,
1013
- ...metadata2
1051
+ store.set((state) => {
1052
+ const existingThread = state.threads[threadId];
1053
+ if (existingThread === void 0) {
1054
+ return {
1055
+ ...state,
1056
+ optimisticUpdates: state.optimisticUpdates.filter(
1057
+ (update) => update.id !== optimisticUpdateId
1058
+ )
1059
+ };
1060
+ }
1061
+ return {
1062
+ ...state,
1063
+ threads: {
1064
+ ...state.threads,
1065
+ [threadId]: {
1066
+ ...existingThread,
1067
+ metadata: {
1068
+ ...existingThread.metadata,
1069
+ ...metadata2
1070
+ }
1014
1071
  }
1015
- }
1016
- },
1017
- optimisticUpdates: state.optimisticUpdates.filter(
1018
- (update) => update.id !== optimisticUpdateId
1019
- )
1020
- }));
1072
+ },
1073
+ optimisticUpdates: state.optimisticUpdates.filter(
1074
+ (update) => update.id !== optimisticUpdateId
1075
+ )
1076
+ };
1077
+ });
1021
1078
  },
1022
1079
  (err) => onMutationFailure(
1023
1080
  err,
@@ -1051,41 +1108,52 @@ function createRoomContext(client) {
1051
1108
  });
1052
1109
  room.addReaction({ threadId, commentId, emoji }).then(
1053
1110
  (addedReaction) => {
1054
- store.set((state) => ({
1055
- ...state,
1056
- threads: {
1057
- ...state.threads,
1058
- [threadId]: {
1059
- ...state.threads[threadId],
1060
- comments: state.threads[threadId].comments.map(
1061
- (comment) => comment.id === commentId ? {
1062
- ...comment,
1063
- reactions: comment.reactions.some(
1064
- (reaction) => reaction.emoji === addedReaction.emoji
1065
- ) ? comment.reactions.map(
1066
- (reaction) => reaction.emoji === addedReaction.emoji ? {
1067
- ...reaction,
1068
- users: [
1069
- ...reaction.users,
1070
- { id: addedReaction.userId }
1071
- ]
1072
- } : reaction
1073
- ) : [
1074
- ...comment.reactions,
1075
- {
1076
- emoji: addedReaction.emoji,
1077
- createdAt: addedReaction.createdAt,
1078
- users: [{ id: addedReaction.userId }]
1079
- }
1080
- ]
1081
- } : comment
1111
+ store.set((state) => {
1112
+ const existingThread = state.threads[threadId];
1113
+ if (existingThread === void 0) {
1114
+ return {
1115
+ ...state,
1116
+ optimisticUpdates: state.optimisticUpdates.filter(
1117
+ (update) => update.id !== optimisticUpdateId
1082
1118
  )
1083
- }
1084
- },
1085
- optimisticUpdates: state.optimisticUpdates.filter(
1086
- (update) => update.id !== optimisticUpdateId
1087
- )
1088
- }));
1119
+ };
1120
+ }
1121
+ return {
1122
+ ...state,
1123
+ threads: {
1124
+ ...state.threads,
1125
+ [threadId]: {
1126
+ ...existingThread,
1127
+ comments: existingThread.comments.map(
1128
+ (comment) => comment.id === commentId ? {
1129
+ ...comment,
1130
+ reactions: comment.reactions.some(
1131
+ (reaction) => reaction.emoji === addedReaction.emoji
1132
+ ) ? comment.reactions.map(
1133
+ (reaction) => reaction.emoji === addedReaction.emoji ? {
1134
+ ...reaction,
1135
+ users: [
1136
+ ...reaction.users,
1137
+ { id: addedReaction.userId }
1138
+ ]
1139
+ } : reaction
1140
+ ) : [
1141
+ ...comment.reactions,
1142
+ {
1143
+ emoji: addedReaction.emoji,
1144
+ createdAt: addedReaction.createdAt,
1145
+ users: [{ id: addedReaction.userId }]
1146
+ }
1147
+ ]
1148
+ } : comment
1149
+ )
1150
+ }
1151
+ },
1152
+ optimisticUpdates: state.optimisticUpdates.filter(
1153
+ (update) => update.id !== optimisticUpdateId
1154
+ )
1155
+ };
1156
+ });
1089
1157
  },
1090
1158
  (err) => onMutationFailure(
1091
1159
  err,
@@ -1118,46 +1186,65 @@ function createRoomContext(client) {
1118
1186
  });
1119
1187
  room.removeReaction({ threadId, commentId, emoji }).then(
1120
1188
  () => {
1121
- store.set((state) => ({
1122
- ...state,
1123
- threads: {
1124
- ...state.threads,
1125
- [threadId]: {
1126
- ...state.threads[threadId],
1127
- comments: state.threads[threadId].comments.map((comment) => {
1128
- if (comment.id !== commentId) {
1129
- return comment;
1130
- }
1131
- const reactionIndex = comment.reactions.findIndex(
1132
- (reaction) => reaction.emoji === emoji
1133
- );
1134
- let reactions = comment.reactions;
1135
- if (reactionIndex >= 0 && comment.reactions[reactionIndex].users.some(
1136
- (user) => user.id === userId
1137
- )) {
1138
- if (comment.reactions[reactionIndex].users.length <= 1) {
1139
- reactions = [...comment.reactions];
1140
- reactions.splice(reactionIndex, 1);
1141
- } else {
1142
- reactions[reactionIndex] = {
1143
- ...reactions[reactionIndex],
1144
- users: reactions[reactionIndex].users.filter(
1145
- (user) => user.id !== userId
1189
+ store.set((state) => {
1190
+ const existingThread = state.threads[threadId];
1191
+ if (existingThread === void 0) {
1192
+ return {
1193
+ ...state,
1194
+ optimisticUpdates: state.optimisticUpdates.filter(
1195
+ (update) => update.id !== optimisticUpdateId
1196
+ )
1197
+ };
1198
+ }
1199
+ return {
1200
+ ...state,
1201
+ threads: {
1202
+ ...state.threads,
1203
+ [threadId]: {
1204
+ ...existingThread,
1205
+ comments: existingThread.comments.map((comment) => {
1206
+ if (comment.id !== commentId) {
1207
+ return comment;
1208
+ }
1209
+ const existingReaction = comment.reactions.find(
1210
+ (reaction) => reaction.emoji === emoji
1211
+ );
1212
+ if (existingReaction === void 0) {
1213
+ return comment;
1214
+ }
1215
+ const reactions = comment.reactions;
1216
+ if (!existingReaction.users.some(
1217
+ (user) => user.id === userId
1218
+ )) {
1219
+ return comment;
1220
+ }
1221
+ if (existingReaction.users.length <= 1) {
1222
+ return {
1223
+ ...comment,
1224
+ reactions: reactions.filter(
1225
+ (reaction) => reaction.emoji !== emoji
1146
1226
  )
1147
1227
  };
1148
1228
  }
1149
- }
1150
- return {
1151
- ...comment,
1152
- reactions
1153
- };
1154
- })
1155
- }
1156
- },
1157
- optimisticUpdates: state.optimisticUpdates.filter(
1158
- (update) => update.id !== optimisticUpdateId
1159
- )
1160
- }));
1229
+ return {
1230
+ ...comment,
1231
+ reactions: reactions.map(
1232
+ (reaction) => reaction.emoji !== emoji ? reaction : {
1233
+ ...reaction,
1234
+ users: reaction.users.filter(
1235
+ (user) => user.id !== userId
1236
+ )
1237
+ }
1238
+ )
1239
+ };
1240
+ })
1241
+ }
1242
+ },
1243
+ optimisticUpdates: state.optimisticUpdates.filter(
1244
+ (update) => update.id !== optimisticUpdateId
1245
+ )
1246
+ };
1247
+ });
1161
1248
  },
1162
1249
  (err) => onMutationFailure(
1163
1250
  err,
@@ -1198,7 +1285,7 @@ function createRoomContext(client) {
1198
1285
  type: "create-comment",
1199
1286
  comment,
1200
1287
  id: optimisticUpdateId,
1201
- inboxNotificationId: _optionalChain([inboxNotification, 'optionalAccess', _5 => _5.id])
1288
+ inboxNotificationId: _optionalChain([inboxNotification, 'optionalAccess', _6 => _6.id])
1202
1289
  });
1203
1290
  room.createComment({ threadId, commentId, body }).then(
1204
1291
  (newComment) => {
@@ -1288,32 +1375,40 @@ function createRoomContext(client) {
1288
1375
  });
1289
1376
  room.deleteComment({ threadId, commentId }).then(
1290
1377
  () => {
1291
- const newThreads = { ...store.get().threads };
1292
- const thread = newThreads[threadId];
1293
- if (thread === void 0)
1294
- return;
1295
- newThreads[thread.id] = {
1296
- ...thread,
1297
- comments: thread.comments.map(
1298
- (comment) => comment.id === commentId ? {
1299
- ...comment,
1300
- deletedAt: now,
1301
- body: void 0
1302
- } : comment
1303
- )
1304
- };
1305
- if (!newThreads[thread.id].comments.some(
1306
- (comment) => comment.deletedAt === void 0
1307
- )) {
1308
- delete newThreads[thread.id];
1309
- }
1310
- store.set((state) => ({
1311
- ...state,
1312
- threads: newThreads,
1313
- optimisticUpdates: state.optimisticUpdates.filter(
1314
- (update) => update.id !== optimisticUpdateId
1315
- )
1316
- }));
1378
+ store.set((state) => {
1379
+ const existingThread = state.threads[threadId];
1380
+ if (existingThread === void 0) {
1381
+ return {
1382
+ ...state,
1383
+ optimisticUpdates: state.optimisticUpdates.filter(
1384
+ (update) => update.id !== optimisticUpdateId
1385
+ )
1386
+ };
1387
+ }
1388
+ const newThread = {
1389
+ ...existingThread,
1390
+ comments: existingThread.comments.map(
1391
+ (comment) => comment.id === commentId ? {
1392
+ ...comment,
1393
+ deletedAt: now,
1394
+ body: void 0
1395
+ } : comment
1396
+ )
1397
+ };
1398
+ const newThreads = { ...state.threads, [threadId]: newThread };
1399
+ if (!newThread.comments.some(
1400
+ (comment) => comment.deletedAt === void 0
1401
+ )) {
1402
+ delete newThreads[threadId];
1403
+ }
1404
+ return {
1405
+ ...state,
1406
+ threads: newThreads,
1407
+ optimisticUpdates: state.optimisticUpdates.filter(
1408
+ (update) => update.id !== optimisticUpdateId
1409
+ )
1410
+ };
1411
+ });
1317
1412
  },
1318
1413
  (err) => onMutationFailure(
1319
1414
  err,
@@ -1359,7 +1454,7 @@ function createRoomContext(client) {
1359
1454
  );
1360
1455
  }
1361
1456
  } catch (error) {
1362
- _core.console.error(_optionalChain([error, 'optionalAccess', _6 => _6.message]));
1457
+ _core.console.error(_optionalChain([error, 'optionalAccess', _7 => _7.message]));
1363
1458
  }
1364
1459
  };
1365
1460
  if (mentionSuggestionsCache.has(mentionSuggestionsCacheKey)) {
@@ -1381,10 +1476,7 @@ function createRoomContext(client) {
1381
1476
  return mentionSuggestions;
1382
1477
  }
1383
1478
  function useThreadSubscription(threadId) {
1384
- return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1385
- store.subscribe,
1386
- store.get,
1387
- store.get,
1479
+ const selector = React2.useCallback(
1388
1480
  (state) => {
1389
1481
  const inboxNotification = selectedInboxNotifications(state).find(
1390
1482
  (inboxNotification2) => inboxNotification2.threadId === threadId
@@ -1399,7 +1491,14 @@ function createRoomContext(client) {
1399
1491
  status: "subscribed",
1400
1492
  unreadSince: inboxNotification.readAt
1401
1493
  };
1402
- }
1494
+ },
1495
+ [threadId]
1496
+ );
1497
+ return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1498
+ store.subscribe,
1499
+ store.get,
1500
+ store.get,
1501
+ selector
1403
1502
  );
1404
1503
  }
1405
1504
  function useMarkThreadAsRead() {
@@ -1450,34 +1549,28 @@ function createRoomContext(client) {
1450
1549
  return `${roomId}:NOTIFICATION_SETTINGS`;
1451
1550
  }
1452
1551
  async function getInboxNotificationSettings(room, queryKey) {
1453
- const roomId = room.id;
1454
- return getOrInitRequest(
1455
- queryKey,
1456
- async () => {
1457
- const room2 = client.getRoom(roomId);
1458
- if (room2 === null) {
1459
- return;
1460
- }
1461
- return room2.getRoomNotificationSettings();
1462
- },
1463
- (settings) => {
1464
- if (settings !== void 0) {
1465
- store.set((state) => ({
1466
- ...state,
1467
- notificationSettings: {
1468
- ...state.notificationSettings,
1469
- [room.id]: settings
1470
- },
1471
- queries: {
1472
- ...state.queries,
1473
- [queryKey]: {
1474
- isLoading: false
1475
- }
1476
- }
1477
- }));
1478
- }
1479
- }
1480
- );
1552
+ const requestInfo = requestsCache.get(queryKey);
1553
+ if (requestInfo !== void 0) {
1554
+ return requestInfo.promise;
1555
+ }
1556
+ const promise = room.getRoomNotificationSettings();
1557
+ requestsCache.set(queryKey, {
1558
+ promise,
1559
+ subscribers: 0
1560
+ });
1561
+ store.setQueryState(queryKey, {
1562
+ isLoading: true
1563
+ });
1564
+ try {
1565
+ const settings = await promise;
1566
+ store.updateRoomInboxNotificationSettings(room.id, settings, queryKey);
1567
+ } catch (err) {
1568
+ store.setQueryState(queryKey, {
1569
+ isLoading: false,
1570
+ error: err
1571
+ });
1572
+ }
1573
+ poller.start(POLLING_INTERVAL);
1481
1574
  }
1482
1575
  function useRoomNotificationSettings() {
1483
1576
  const room = useRoom();
@@ -1488,27 +1581,31 @@ function createRoomContext(client) {
1488
1581
  return () => decrementQuerySubscribers(queryKey);
1489
1582
  }, [room]);
1490
1583
  const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
1491
- return [
1492
- _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1493
- store.subscribe,
1494
- store.get,
1495
- store.get,
1496
- (state) => {
1497
- const query = state.queries[makeNotificationSettingsQueryKey(room.id)];
1498
- if (query === void 0 || query.isLoading) {
1499
- return { isLoading: true };
1500
- }
1501
- if (query.error !== void 0) {
1502
- return { isLoading: false, error: query.error };
1503
- }
1504
- return {
1505
- isLoading: false,
1506
- settings: selectNotificationSettings(room.id, state)
1507
- };
1584
+ const selector = React2.useCallback(
1585
+ (state) => {
1586
+ const query = state.queries[makeNotificationSettingsQueryKey(room.id)];
1587
+ if (query === void 0 || query.isLoading) {
1588
+ return { isLoading: true };
1508
1589
  }
1509
- ),
1510
- updateRoomNotificationSettings
1511
- ];
1590
+ if (query.error !== void 0) {
1591
+ return { isLoading: false, error: query.error };
1592
+ }
1593
+ return {
1594
+ isLoading: false,
1595
+ settings: selectNotificationSettings(room.id, state)
1596
+ };
1597
+ },
1598
+ [room]
1599
+ );
1600
+ const settings = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1601
+ store.subscribe,
1602
+ store.get,
1603
+ store.get,
1604
+ selector
1605
+ );
1606
+ return React2.useMemo(() => {
1607
+ return [settings, updateRoomNotificationSettings];
1608
+ }, [settings, updateRoomNotificationSettings]);
1512
1609
  }
1513
1610
  function useRoomNotificationSettingsSuspense() {
1514
1611
  const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
@@ -1526,20 +1623,24 @@ function createRoomContext(client) {
1526
1623
  incrementQuerySubscribers(queryKey2);
1527
1624
  return () => decrementQuerySubscribers(queryKey2);
1528
1625
  }, [room]);
1529
- return [
1530
- _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1531
- store.subscribe,
1532
- store.get,
1533
- store.get,
1534
- (state) => {
1535
- return {
1536
- isLoading: false,
1537
- settings: selectNotificationSettings(room.id, state)
1538
- };
1539
- }
1540
- ),
1541
- updateRoomNotificationSettings
1542
- ];
1626
+ const selector = React2.useCallback(
1627
+ (state) => {
1628
+ return {
1629
+ isLoading: false,
1630
+ settings: selectNotificationSettings(room.id, state)
1631
+ };
1632
+ },
1633
+ [room]
1634
+ );
1635
+ const settings = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1636
+ store.subscribe,
1637
+ store.get,
1638
+ store.get,
1639
+ selector
1640
+ );
1641
+ return React2.useMemo(() => {
1642
+ return [settings, updateRoomNotificationSettings];
1643
+ }, [settings, updateRoomNotificationSettings]);
1543
1644
  }
1544
1645
  function useUpdateRoomNotificationSettings() {
1545
1646
  const room = useRoom();
@@ -1686,7 +1787,7 @@ function getCurrentUserId(room) {
1686
1787
  }
1687
1788
  function handleApiError(err) {
1688
1789
  const message = `Request failed with status ${err.status}: ${err.message}`;
1689
- if (_optionalChain([err, 'access', _7 => _7.details, 'optionalAccess', _8 => _8.error]) === "FORBIDDEN") {
1790
+ if (_optionalChain([err, 'access', _8 => _8.details, 'optionalAccess', _9 => _9.error]) === "FORBIDDEN") {
1690
1791
  const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
1691
1792
  _core.console.error(detailedMessage);
1692
1793
  }
@@ -1750,7 +1851,7 @@ function createSharedContext(client) {
1750
1851
  );
1751
1852
  return {
1752
1853
  ...state,
1753
- user: _optionalChain([state, 'optionalAccess', _9 => _9.data])
1854
+ user: _optionalChain([state, 'optionalAccess', _10 => _10.data])
1754
1855
  };
1755
1856
  }
1756
1857
  function useRoomInfo(roomId) {
@@ -1778,19 +1879,19 @@ function createSharedContext(client) {
1778
1879
  );
1779
1880
  const roomInfoState = getRoomInfoState();
1780
1881
  if (!roomInfoState || roomInfoState.isLoading) {
1781
- throw usersStore.get(roomId);
1882
+ throw roomsInfoStore.get(roomId);
1782
1883
  }
1783
1884
  if (roomInfoState.error) {
1784
1885
  throw roomInfoState.error;
1785
1886
  }
1786
1887
  const state = _indexjs.useSyncExternalStore.call(void 0,
1787
- usersStore.subscribe,
1888
+ roomsInfoStore.subscribe,
1788
1889
  getRoomInfoState,
1789
1890
  getRoomInfoState
1790
1891
  );
1791
1892
  return {
1792
1893
  ...state,
1793
- info: _optionalChain([state, 'optionalAccess', _10 => _10.data])
1894
+ info: _optionalChain([state, 'optionalAccess', _11 => _11.data])
1794
1895
  };
1795
1896
  }
1796
1897
  const bundle = {
@@ -1813,6 +1914,8 @@ function useLiveblocksContextBundle() {
1813
1914
  }
1814
1915
  return bundle;
1815
1916
  }
1917
+ var POLLING_INTERVAL2 = 60 * 1e3;
1918
+ var INBOX_NOTIFICATIONS_QUERY = "INBOX_NOTIFICATIONS";
1816
1919
  function createLiveblocksContext(client) {
1817
1920
  const shared = createSharedContext(client);
1818
1921
  const store = client[_core.kInternal].cacheStore;
@@ -1827,15 +1930,17 @@ function createLiveblocksContext(client) {
1827
1930
  }
1828
1931
  let fetchInboxNotificationsRequest = null;
1829
1932
  let inboxNotificationsSubscribers = 0;
1830
- const INBOX_NOTIFICATIONS_QUERY = "INBOX_NOTIFICATIONS";
1831
- const POLLING_INTERVAL2 = 60 * 1e3;
1933
+ let lastRequestedAt;
1832
1934
  const poller = _core.makePoller.call(void 0, refreshThreadsAndNotifications);
1833
1935
  function refreshThreadsAndNotifications() {
1834
- return client.getInboxNotifications().then(
1835
- ({ threads, inboxNotifications }) => {
1936
+ return client.getInboxNotifications({ since: lastRequestedAt }).then(
1937
+ (result) => {
1938
+ lastRequestedAt = result.meta.requestedAt;
1836
1939
  store.updateThreadsAndNotifications(
1837
- threads,
1838
- inboxNotifications,
1940
+ result.threads,
1941
+ result.inboxNotifications,
1942
+ result.deletedThreads,
1943
+ result.deletedInboxNotifications,
1839
1944
  INBOX_NOTIFICATIONS_QUERY
1840
1945
  );
1841
1946
  },
@@ -1868,12 +1973,17 @@ function createLiveblocksContext(client) {
1868
1973
  });
1869
1974
  try {
1870
1975
  fetchInboxNotificationsRequest = client.getInboxNotifications();
1871
- const { inboxNotifications, threads } = await fetchInboxNotificationsRequest;
1976
+ const result = await fetchInboxNotificationsRequest;
1872
1977
  store.updateThreadsAndNotifications(
1873
- threads,
1874
- inboxNotifications,
1978
+ result.threads,
1979
+ result.inboxNotifications,
1980
+ result.deletedThreads,
1981
+ result.deletedInboxNotifications,
1875
1982
  INBOX_NOTIFICATIONS_QUERY
1876
1983
  );
1984
+ if (lastRequestedAt === void 0 || lastRequestedAt > result.meta.requestedAt) {
1985
+ lastRequestedAt = result.meta.requestedAt;
1986
+ }
1877
1987
  } catch (er) {
1878
1988
  store.setQueryState(INBOX_NOTIFICATIONS_QUERY, {
1879
1989
  isLoading: false,
@@ -1882,39 +1992,47 @@ function createLiveblocksContext(client) {
1882
1992
  }
1883
1993
  return;
1884
1994
  }
1995
+ function useInboxNotificationsSelectorCallback(state) {
1996
+ const query = state.queries[INBOX_NOTIFICATIONS_QUERY];
1997
+ if (query === void 0 || query.isLoading) {
1998
+ return {
1999
+ isLoading: true
2000
+ };
2001
+ }
2002
+ if (query.error !== void 0) {
2003
+ return {
2004
+ error: query.error,
2005
+ isLoading: false
2006
+ };
2007
+ }
2008
+ return {
2009
+ inboxNotifications: selectedInboxNotifications(state),
2010
+ isLoading: false
2011
+ };
2012
+ }
1885
2013
  function useInboxNotifications() {
1886
2014
  _react.useEffect.call(void 0, () => {
1887
2015
  void fetchInboxNotifications();
1888
2016
  incrementInboxNotificationsSubscribers();
1889
2017
  return () => decrementInboxNotificationsSubscribers();
1890
- });
2018
+ }, []);
1891
2019
  const result = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1892
2020
  store.subscribe,
1893
2021
  store.get,
1894
2022
  store.get,
1895
- (state) => {
1896
- const query = state.queries[INBOX_NOTIFICATIONS_QUERY];
1897
- if (query === void 0 || query.isLoading) {
1898
- return {
1899
- isLoading: true
1900
- };
1901
- }
1902
- if (query.error !== void 0) {
1903
- return {
1904
- error: query.error,
1905
- isLoading: false
1906
- };
1907
- }
1908
- return {
1909
- inboxNotifications: selectedInboxNotifications(state),
1910
- isLoading: false
1911
- };
1912
- }
2023
+ useInboxNotificationsSelectorCallback
1913
2024
  );
1914
2025
  return result;
1915
2026
  }
2027
+ function useInboxNotificationsSuspenseSelector(state) {
2028
+ return {
2029
+ inboxNotifications: selectedInboxNotifications(state),
2030
+ isLoading: false
2031
+ };
2032
+ }
1916
2033
  function useInboxNotificationsSuspense() {
1917
- if (store.get().queries[INBOX_NOTIFICATIONS_QUERY] === void 0 || store.get().queries[INBOX_NOTIFICATIONS_QUERY].isLoading) {
2034
+ const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
2035
+ if (query === void 0 || query.isLoading) {
1918
2036
  throw fetchInboxNotifications();
1919
2037
  }
1920
2038
  React.default.useEffect(() => {
@@ -1927,12 +2045,7 @@ function createLiveblocksContext(client) {
1927
2045
  store.subscribe,
1928
2046
  store.get,
1929
2047
  store.get,
1930
- (state) => {
1931
- return {
1932
- inboxNotifications: selectedInboxNotifications(state),
1933
- isLoading: false
1934
- };
1935
- }
2048
+ useInboxNotificationsSuspenseSelector
1936
2049
  );
1937
2050
  }
1938
2051
  function selectUnreadInboxNotificationsCount(state) {
@@ -1944,38 +2057,46 @@ function createLiveblocksContext(client) {
1944
2057
  }
1945
2058
  return count;
1946
2059
  }
2060
+ function useUnreadInboxNotificationsCountSelector(state) {
2061
+ const query = state.queries[INBOX_NOTIFICATIONS_QUERY];
2062
+ if (query === void 0 || query.isLoading) {
2063
+ return {
2064
+ isLoading: true
2065
+ };
2066
+ }
2067
+ if (query.error !== void 0) {
2068
+ return {
2069
+ error: query.error,
2070
+ isLoading: false
2071
+ };
2072
+ }
2073
+ return {
2074
+ isLoading: false,
2075
+ count: selectUnreadInboxNotificationsCount(state)
2076
+ };
2077
+ }
1947
2078
  function useUnreadInboxNotificationsCount() {
1948
2079
  _react.useEffect.call(void 0, () => {
1949
2080
  void fetchInboxNotifications();
1950
2081
  incrementInboxNotificationsSubscribers();
1951
2082
  return () => decrementInboxNotificationsSubscribers();
1952
- });
2083
+ }, []);
1953
2084
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1954
2085
  store.subscribe,
1955
2086
  store.get,
1956
2087
  store.get,
1957
- (state) => {
1958
- const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
1959
- if (query === void 0 || query.isLoading) {
1960
- return {
1961
- isLoading: true
1962
- };
1963
- }
1964
- if (query.error !== void 0) {
1965
- return {
1966
- error: query.error,
1967
- isLoading: false
1968
- };
1969
- }
1970
- return {
1971
- isLoading: false,
1972
- count: selectUnreadInboxNotificationsCount(state)
1973
- };
1974
- }
2088
+ useUnreadInboxNotificationsCountSelector
1975
2089
  );
1976
2090
  }
2091
+ function useUnreadInboxNotificationsCountSuspenseSelector(state) {
2092
+ return {
2093
+ isLoading: false,
2094
+ count: selectUnreadInboxNotificationsCount(state)
2095
+ };
2096
+ }
1977
2097
  function useUnreadInboxNotificationsCountSuspense() {
1978
- if (store.get().queries[INBOX_NOTIFICATIONS_QUERY] === void 0 || store.get().queries[INBOX_NOTIFICATIONS_QUERY].isLoading) {
2098
+ const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
2099
+ if (query === void 0 || query.isLoading) {
1979
2100
  throw fetchInboxNotifications();
1980
2101
  }
1981
2102
  React.default.useEffect(() => {
@@ -1988,12 +2109,7 @@ function createLiveblocksContext(client) {
1988
2109
  store.subscribe,
1989
2110
  store.get,
1990
2111
  store.get,
1991
- (state) => {
1992
- return {
1993
- isLoading: false,
1994
- count: selectUnreadInboxNotificationsCount(state)
1995
- };
1996
- }
2112
+ useUnreadInboxNotificationsCountSuspenseSelector
1997
2113
  );
1998
2114
  }
1999
2115
  function useMarkInboxNotificationAsRead() {
@@ -2008,20 +2124,30 @@ function createLiveblocksContext(client) {
2008
2124
  });
2009
2125
  client.markInboxNotificationAsRead(inboxNotificationId).then(
2010
2126
  () => {
2011
- store.set((state) => ({
2012
- ...state,
2013
- inboxNotifications: {
2014
- ...state.inboxNotifications,
2015
- [inboxNotificationId]: {
2016
- // TODO: Handle potential deleted inbox notification
2017
- ...state.inboxNotifications[inboxNotificationId],
2018
- readAt
2019
- }
2020
- },
2021
- optimisticUpdates: state.optimisticUpdates.filter(
2022
- (update) => update.id !== optimisticUpdateId
2023
- )
2024
- }));
2127
+ store.set((state) => {
2128
+ const existingNotification = state.inboxNotifications[inboxNotificationId];
2129
+ if (existingNotification === void 0) {
2130
+ return {
2131
+ ...state,
2132
+ optimisticUpdates: state.optimisticUpdates.filter(
2133
+ (update) => update.id !== optimisticUpdateId
2134
+ )
2135
+ };
2136
+ }
2137
+ return {
2138
+ ...state,
2139
+ inboxNotifications: {
2140
+ ...state.inboxNotifications,
2141
+ [inboxNotificationId]: {
2142
+ ...existingNotification,
2143
+ readAt
2144
+ }
2145
+ },
2146
+ optimisticUpdates: state.optimisticUpdates.filter(
2147
+ (update) => update.id !== optimisticUpdateId
2148
+ )
2149
+ };
2150
+ });
2025
2151
  },
2026
2152
  () => {
2027
2153
  store.set((state) => ({
@@ -2072,10 +2198,7 @@ function createLiveblocksContext(client) {
2072
2198
  }, []);
2073
2199
  }
2074
2200
  function useThreadFromCache(threadId) {
2075
- return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2076
- store.subscribe,
2077
- store.get,
2078
- store.get,
2201
+ const selector = _react.useCallback.call(void 0,
2079
2202
  (state) => {
2080
2203
  const thread = state.threads[threadId];
2081
2204
  if (thread === void 0) {
@@ -2084,7 +2207,14 @@ function createLiveblocksContext(client) {
2084
2207
  );
2085
2208
  }
2086
2209
  return thread;
2087
- }
2210
+ },
2211
+ [threadId]
2212
+ );
2213
+ return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2214
+ store.subscribe,
2215
+ store.get,
2216
+ store.get,
2217
+ selector
2088
2218
  );
2089
2219
  }
2090
2220
  const currentUserIdStore = client[_core.kInternal].currentUserIdStore;