@liveblocks/react 1.10.0-beta2 → 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.mjs CHANGED
@@ -5,7 +5,7 @@ import { detectDupes } from "@liveblocks/core";
5
5
 
6
6
  // src/version.ts
7
7
  var PKG_NAME = "@liveblocks/react";
8
- var PKG_VERSION = "1.10.0-beta2";
8
+ var PKG_VERSION = "1.10.0-beta3";
9
9
  var PKG_FORMAT = "esm";
10
10
 
11
11
  // src/ClientSideSuspense.tsx
@@ -34,7 +34,10 @@ import { useSyncExternalStoreWithSelector as useSyncExternalStoreWithSelector2 }
34
34
  import { applyOptimisticUpdates } from "@liveblocks/core";
35
35
  function selectedInboxNotifications(state) {
36
36
  const result = applyOptimisticUpdates(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
@@ -151,11 +154,12 @@ function createCommentId() {
151
154
 
152
155
  // src/comments/lib/select-notification-settings.ts
153
156
  import {
154
- applyOptimisticUpdates as applyOptimisticUpdates2
157
+ applyOptimisticUpdates as applyOptimisticUpdates2,
158
+ nn
155
159
  } from "@liveblocks/core";
156
160
  function selectNotificationSettings(roomId, state) {
157
161
  const { notificationSettings } = applyOptimisticUpdates2(state);
158
- return notificationSettings[roomId];
162
+ return nn(notificationSettings[roomId]);
159
163
  }
160
164
 
161
165
  // src/comments/lib/selected-threads.ts
@@ -167,6 +171,9 @@ function selectedThreads(roomId, state, options) {
167
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;
@@ -786,15 +793,46 @@ function createRoomContext(client, options) {
786
793
  const requestsCache = /* @__PURE__ */ new Map();
787
794
  const poller = makePoller(refreshThreadsAndNotifications);
788
795
  async function refreshThreadsAndNotifications() {
789
- await Promise.allSettled(
790
- Array.from(requestsCache.entries()).filter(([_, requestCache]) => requestCache.subscribers > 0).map(async ([_, requestCache]) => {
791
- return requestCache.requestFactory().then(
792
- (result) => requestCache.onSuccess(result),
793
- () => {
794
- }
796
+ const requests = [];
797
+ client[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
+ })
795
814
  );
796
- })
797
- );
815
+ }
816
+ const lastRequestedAt = room[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[kInternal].comments.lastRequestedAt = result.meta.requestedAt;
831
+ }).catch(() => {
832
+ })
833
+ );
834
+ });
835
+ await Promise.allSettled(requests);
798
836
  }
799
837
  function incrementQuerySubscribers(queryKey) {
800
838
  const requestCache = requestsCache.get(queryKey);
@@ -824,16 +862,14 @@ function createRoomContext(client, options) {
824
862
  poller.stop();
825
863
  }
826
864
  }
827
- async function getOrInitRequest(queryKey, requestFactory, onSuccess) {
865
+ async function getThreadsAndInboxNotifications(room, queryKey, options2) {
828
866
  const requestInfo = requestsCache.get(queryKey);
829
867
  if (requestInfo !== void 0) {
830
868
  return requestInfo.promise;
831
869
  }
832
- const promise = requestFactory();
870
+ const promise = room.getThreads(options2);
833
871
  requestsCache.set(queryKey, {
834
872
  promise,
835
- requestFactory,
836
- onSuccess,
837
873
  subscribers: 0
838
874
  });
839
875
  store.setQueryState(queryKey, {
@@ -841,37 +877,25 @@ function createRoomContext(client, options) {
841
877
  });
842
878
  try {
843
879
  const result = await promise;
844
- onSuccess(result);
845
- } catch (er) {
880
+ store.updateThreadsAndNotifications(
881
+ result.threads,
882
+ result.inboxNotifications,
883
+ result.deletedThreads,
884
+ result.deletedInboxNotifications,
885
+ queryKey
886
+ );
887
+ const lastRequestedAt = room[kInternal].comments.lastRequestedAt;
888
+ if (lastRequestedAt === null || lastRequestedAt > result.meta.requestedAt) {
889
+ room[kInternal].comments.lastRequestedAt = result.meta.requestedAt;
890
+ }
891
+ } catch (err) {
846
892
  store.setQueryState(queryKey, {
847
893
  isLoading: false,
848
- error: er
894
+ error: err
849
895
  });
850
896
  }
851
897
  poller.start(POLLING_INTERVAL);
852
898
  }
853
- async function getThreadsAndInboxNotifications(room, queryKey, options2) {
854
- const roomId = room.id;
855
- return getOrInitRequest(
856
- queryKey,
857
- async () => {
858
- const room2 = client.getRoom(roomId);
859
- if (room2 === null) {
860
- return;
861
- }
862
- return room2.getThreads(options2);
863
- },
864
- (result) => {
865
- if (result !== void 0) {
866
- store.updateThreadsAndNotifications(
867
- result.threads,
868
- result.inboxNotifications,
869
- queryKey
870
- );
871
- }
872
- }
873
- );
874
- }
875
899
  function useThreads(options2 = { query: { metadata: {} } }) {
876
900
  const room = useRoom();
877
901
  const queryKey = React2.useMemo(
@@ -885,7 +909,8 @@ function createRoomContext(client, options) {
885
909
  }, [room, queryKey]);
886
910
  const selector = React2.useCallback(
887
911
  (state) => {
888
- if (state.queries[queryKey] === void 0 || state.queries[queryKey].isLoading) {
912
+ const query = state.queries[queryKey];
913
+ if (query === void 0 || query.isLoading) {
889
914
  return {
890
915
  isLoading: true
891
916
  };
@@ -893,7 +918,7 @@ function createRoomContext(client, options) {
893
918
  return {
894
919
  threads: selectedThreads(room.id, state, options2),
895
920
  isLoading: false,
896
- error: state.queries[queryKey].error
921
+ error: query.error
897
922
  };
898
923
  },
899
924
  [room, queryKey]
@@ -934,7 +959,7 @@ function createRoomContext(client, options) {
934
959
  return () => {
935
960
  decrementQuerySubscribers(queryKey);
936
961
  };
937
- }, [room, queryKey]);
962
+ }, [queryKey]);
938
963
  return useSyncExternalStoreWithSelector(
939
964
  store.subscribe,
940
965
  store.get,
@@ -1023,22 +1048,33 @@ function createRoomContext(client, options) {
1023
1048
  });
1024
1049
  room.editThreadMetadata({ metadata, threadId }).then(
1025
1050
  (metadata2) => {
1026
- store.set((state) => ({
1027
- ...state,
1028
- threads: {
1029
- ...state.threads,
1030
- [threadId]: {
1031
- ...state.threads[threadId],
1032
- metadata: {
1033
- ...state.threads[threadId].metadata,
1034
- ...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
+ }
1035
1071
  }
1036
- }
1037
- },
1038
- optimisticUpdates: state.optimisticUpdates.filter(
1039
- (update) => update.id !== optimisticUpdateId
1040
- )
1041
- }));
1072
+ },
1073
+ optimisticUpdates: state.optimisticUpdates.filter(
1074
+ (update) => update.id !== optimisticUpdateId
1075
+ )
1076
+ };
1077
+ });
1042
1078
  },
1043
1079
  (err) => onMutationFailure(
1044
1080
  err,
@@ -1072,41 +1108,52 @@ function createRoomContext(client, options) {
1072
1108
  });
1073
1109
  room.addReaction({ threadId, commentId, emoji }).then(
1074
1110
  (addedReaction) => {
1075
- store.set((state) => ({
1076
- ...state,
1077
- threads: {
1078
- ...state.threads,
1079
- [threadId]: {
1080
- ...state.threads[threadId],
1081
- comments: state.threads[threadId].comments.map(
1082
- (comment) => comment.id === commentId ? {
1083
- ...comment,
1084
- reactions: comment.reactions.some(
1085
- (reaction) => reaction.emoji === addedReaction.emoji
1086
- ) ? comment.reactions.map(
1087
- (reaction) => reaction.emoji === addedReaction.emoji ? {
1088
- ...reaction,
1089
- users: [
1090
- ...reaction.users,
1091
- { id: addedReaction.userId }
1092
- ]
1093
- } : reaction
1094
- ) : [
1095
- ...comment.reactions,
1096
- {
1097
- emoji: addedReaction.emoji,
1098
- createdAt: addedReaction.createdAt,
1099
- users: [{ id: addedReaction.userId }]
1100
- }
1101
- ]
1102
- } : 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
1103
1118
  )
1104
- }
1105
- },
1106
- optimisticUpdates: state.optimisticUpdates.filter(
1107
- (update) => update.id !== optimisticUpdateId
1108
- )
1109
- }));
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
+ });
1110
1157
  },
1111
1158
  (err) => onMutationFailure(
1112
1159
  err,
@@ -1139,46 +1186,65 @@ function createRoomContext(client, options) {
1139
1186
  });
1140
1187
  room.removeReaction({ threadId, commentId, emoji }).then(
1141
1188
  () => {
1142
- store.set((state) => ({
1143
- ...state,
1144
- threads: {
1145
- ...state.threads,
1146
- [threadId]: {
1147
- ...state.threads[threadId],
1148
- comments: state.threads[threadId].comments.map((comment) => {
1149
- if (comment.id !== commentId) {
1150
- return comment;
1151
- }
1152
- const reactionIndex = comment.reactions.findIndex(
1153
- (reaction) => reaction.emoji === emoji
1154
- );
1155
- let reactions = comment.reactions;
1156
- if (reactionIndex >= 0 && comment.reactions[reactionIndex].users.some(
1157
- (user) => user.id === userId
1158
- )) {
1159
- if (comment.reactions[reactionIndex].users.length <= 1) {
1160
- reactions = [...comment.reactions];
1161
- reactions.splice(reactionIndex, 1);
1162
- } else {
1163
- reactions[reactionIndex] = {
1164
- ...reactions[reactionIndex],
1165
- users: reactions[reactionIndex].users.filter(
1166
- (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
1167
1226
  )
1168
1227
  };
1169
1228
  }
1170
- }
1171
- return {
1172
- ...comment,
1173
- reactions
1174
- };
1175
- })
1176
- }
1177
- },
1178
- optimisticUpdates: state.optimisticUpdates.filter(
1179
- (update) => update.id !== optimisticUpdateId
1180
- )
1181
- }));
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
+ });
1182
1248
  },
1183
1249
  (err) => onMutationFailure(
1184
1250
  err,
@@ -1309,32 +1375,40 @@ function createRoomContext(client, options) {
1309
1375
  });
1310
1376
  room.deleteComment({ threadId, commentId }).then(
1311
1377
  () => {
1312
- const newThreads = { ...store.get().threads };
1313
- const thread = newThreads[threadId];
1314
- if (thread === void 0)
1315
- return;
1316
- newThreads[thread.id] = {
1317
- ...thread,
1318
- comments: thread.comments.map(
1319
- (comment) => comment.id === commentId ? {
1320
- ...comment,
1321
- deletedAt: now,
1322
- body: void 0
1323
- } : comment
1324
- )
1325
- };
1326
- if (!newThreads[thread.id].comments.some(
1327
- (comment) => comment.deletedAt === void 0
1328
- )) {
1329
- delete newThreads[thread.id];
1330
- }
1331
- store.set((state) => ({
1332
- ...state,
1333
- threads: newThreads,
1334
- optimisticUpdates: state.optimisticUpdates.filter(
1335
- (update) => update.id !== optimisticUpdateId
1336
- )
1337
- }));
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
+ });
1338
1412
  },
1339
1413
  (err) => onMutationFailure(
1340
1414
  err,
@@ -1402,10 +1476,7 @@ function createRoomContext(client, options) {
1402
1476
  return mentionSuggestions;
1403
1477
  }
1404
1478
  function useThreadSubscription(threadId) {
1405
- return useSyncExternalStoreWithSelector(
1406
- store.subscribe,
1407
- store.get,
1408
- store.get,
1479
+ const selector = React2.useCallback(
1409
1480
  (state) => {
1410
1481
  const inboxNotification = selectedInboxNotifications(state).find(
1411
1482
  (inboxNotification2) => inboxNotification2.threadId === threadId
@@ -1420,7 +1491,14 @@ function createRoomContext(client, options) {
1420
1491
  status: "subscribed",
1421
1492
  unreadSince: inboxNotification.readAt
1422
1493
  };
1423
- }
1494
+ },
1495
+ [threadId]
1496
+ );
1497
+ return useSyncExternalStoreWithSelector(
1498
+ store.subscribe,
1499
+ store.get,
1500
+ store.get,
1501
+ selector
1424
1502
  );
1425
1503
  }
1426
1504
  function useMarkThreadAsRead() {
@@ -1471,34 +1549,28 @@ function createRoomContext(client, options) {
1471
1549
  return `${roomId}:NOTIFICATION_SETTINGS`;
1472
1550
  }
1473
1551
  async function getInboxNotificationSettings(room, queryKey) {
1474
- const roomId = room.id;
1475
- return getOrInitRequest(
1476
- queryKey,
1477
- async () => {
1478
- const room2 = client.getRoom(roomId);
1479
- if (room2 === null) {
1480
- return;
1481
- }
1482
- return room2.getRoomNotificationSettings();
1483
- },
1484
- (settings) => {
1485
- if (settings !== void 0) {
1486
- store.set((state) => ({
1487
- ...state,
1488
- notificationSettings: {
1489
- ...state.notificationSettings,
1490
- [room.id]: settings
1491
- },
1492
- queries: {
1493
- ...state.queries,
1494
- [queryKey]: {
1495
- isLoading: false
1496
- }
1497
- }
1498
- }));
1499
- }
1500
- }
1501
- );
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);
1502
1574
  }
1503
1575
  function useRoomNotificationSettings() {
1504
1576
  const room = useRoom();
@@ -1509,27 +1581,31 @@ function createRoomContext(client, options) {
1509
1581
  return () => decrementQuerySubscribers(queryKey);
1510
1582
  }, [room]);
1511
1583
  const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
1512
- return [
1513
- useSyncExternalStoreWithSelector(
1514
- store.subscribe,
1515
- store.get,
1516
- store.get,
1517
- (state) => {
1518
- const query = state.queries[makeNotificationSettingsQueryKey(room.id)];
1519
- if (query === void 0 || query.isLoading) {
1520
- return { isLoading: true };
1521
- }
1522
- if (query.error !== void 0) {
1523
- return { isLoading: false, error: query.error };
1524
- }
1525
- return {
1526
- isLoading: false,
1527
- settings: selectNotificationSettings(room.id, state)
1528
- };
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 };
1529
1589
  }
1530
- ),
1531
- updateRoomNotificationSettings
1532
- ];
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 = useSyncExternalStoreWithSelector(
1601
+ store.subscribe,
1602
+ store.get,
1603
+ store.get,
1604
+ selector
1605
+ );
1606
+ return React2.useMemo(() => {
1607
+ return [settings, updateRoomNotificationSettings];
1608
+ }, [settings, updateRoomNotificationSettings]);
1533
1609
  }
1534
1610
  function useRoomNotificationSettingsSuspense() {
1535
1611
  const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
@@ -1547,20 +1623,24 @@ function createRoomContext(client, options) {
1547
1623
  incrementQuerySubscribers(queryKey2);
1548
1624
  return () => decrementQuerySubscribers(queryKey2);
1549
1625
  }, [room]);
1550
- return [
1551
- useSyncExternalStoreWithSelector(
1552
- store.subscribe,
1553
- store.get,
1554
- store.get,
1555
- (state) => {
1556
- return {
1557
- isLoading: false,
1558
- settings: selectNotificationSettings(room.id, state)
1559
- };
1560
- }
1561
- ),
1562
- updateRoomNotificationSettings
1563
- ];
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 = useSyncExternalStoreWithSelector(
1636
+ store.subscribe,
1637
+ store.get,
1638
+ store.get,
1639
+ selector
1640
+ );
1641
+ return React2.useMemo(() => {
1642
+ return [settings, updateRoomNotificationSettings];
1643
+ }, [settings, updateRoomNotificationSettings]);
1564
1644
  }
1565
1645
  function useUpdateRoomNotificationSettings() {
1566
1646
  const room = useRoom();
@@ -1799,13 +1879,13 @@ function createSharedContext(client) {
1799
1879
  );
1800
1880
  const roomInfoState = getRoomInfoState();
1801
1881
  if (!roomInfoState || roomInfoState.isLoading) {
1802
- throw usersStore.get(roomId);
1882
+ throw roomsInfoStore.get(roomId);
1803
1883
  }
1804
1884
  if (roomInfoState.error) {
1805
1885
  throw roomInfoState.error;
1806
1886
  }
1807
1887
  const state = useSyncExternalStore2(
1808
- usersStore.subscribe,
1888
+ roomsInfoStore.subscribe,
1809
1889
  getRoomInfoState,
1810
1890
  getRoomInfoState
1811
1891
  );
@@ -1834,6 +1914,8 @@ function useLiveblocksContextBundle() {
1834
1914
  }
1835
1915
  return bundle;
1836
1916
  }
1917
+ var POLLING_INTERVAL2 = 60 * 1e3;
1918
+ var INBOX_NOTIFICATIONS_QUERY = "INBOX_NOTIFICATIONS";
1837
1919
  function createLiveblocksContext(client) {
1838
1920
  const shared = createSharedContext(client);
1839
1921
  const store = client[kInternal3].cacheStore;
@@ -1848,15 +1930,17 @@ function createLiveblocksContext(client) {
1848
1930
  }
1849
1931
  let fetchInboxNotificationsRequest = null;
1850
1932
  let inboxNotificationsSubscribers = 0;
1851
- const INBOX_NOTIFICATIONS_QUERY = "INBOX_NOTIFICATIONS";
1852
- const POLLING_INTERVAL2 = 60 * 1e3;
1933
+ let lastRequestedAt;
1853
1934
  const poller = makePoller2(refreshThreadsAndNotifications);
1854
1935
  function refreshThreadsAndNotifications() {
1855
- return client.getInboxNotifications().then(
1856
- ({ threads, inboxNotifications }) => {
1936
+ return client.getInboxNotifications({ since: lastRequestedAt }).then(
1937
+ (result) => {
1938
+ lastRequestedAt = result.meta.requestedAt;
1857
1939
  store.updateThreadsAndNotifications(
1858
- threads,
1859
- inboxNotifications,
1940
+ result.threads,
1941
+ result.inboxNotifications,
1942
+ result.deletedThreads,
1943
+ result.deletedInboxNotifications,
1860
1944
  INBOX_NOTIFICATIONS_QUERY
1861
1945
  );
1862
1946
  },
@@ -1889,12 +1973,17 @@ function createLiveblocksContext(client) {
1889
1973
  });
1890
1974
  try {
1891
1975
  fetchInboxNotificationsRequest = client.getInboxNotifications();
1892
- const { inboxNotifications, threads } = await fetchInboxNotificationsRequest;
1976
+ const result = await fetchInboxNotificationsRequest;
1893
1977
  store.updateThreadsAndNotifications(
1894
- threads,
1895
- inboxNotifications,
1978
+ result.threads,
1979
+ result.inboxNotifications,
1980
+ result.deletedThreads,
1981
+ result.deletedInboxNotifications,
1896
1982
  INBOX_NOTIFICATIONS_QUERY
1897
1983
  );
1984
+ if (lastRequestedAt === void 0 || lastRequestedAt > result.meta.requestedAt) {
1985
+ lastRequestedAt = result.meta.requestedAt;
1986
+ }
1898
1987
  } catch (er) {
1899
1988
  store.setQueryState(INBOX_NOTIFICATIONS_QUERY, {
1900
1989
  isLoading: false,
@@ -1903,39 +1992,47 @@ function createLiveblocksContext(client) {
1903
1992
  }
1904
1993
  return;
1905
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
+ }
1906
2013
  function useInboxNotifications() {
1907
2014
  useEffect5(() => {
1908
2015
  void fetchInboxNotifications();
1909
2016
  incrementInboxNotificationsSubscribers();
1910
2017
  return () => decrementInboxNotificationsSubscribers();
1911
- });
2018
+ }, []);
1912
2019
  const result = useSyncExternalStoreWithSelector2(
1913
2020
  store.subscribe,
1914
2021
  store.get,
1915
2022
  store.get,
1916
- (state) => {
1917
- const query = state.queries[INBOX_NOTIFICATIONS_QUERY];
1918
- if (query === void 0 || query.isLoading) {
1919
- return {
1920
- isLoading: true
1921
- };
1922
- }
1923
- if (query.error !== void 0) {
1924
- return {
1925
- error: query.error,
1926
- isLoading: false
1927
- };
1928
- }
1929
- return {
1930
- inboxNotifications: selectedInboxNotifications(state),
1931
- isLoading: false
1932
- };
1933
- }
2023
+ useInboxNotificationsSelectorCallback
1934
2024
  );
1935
2025
  return result;
1936
2026
  }
2027
+ function useInboxNotificationsSuspenseSelector(state) {
2028
+ return {
2029
+ inboxNotifications: selectedInboxNotifications(state),
2030
+ isLoading: false
2031
+ };
2032
+ }
1937
2033
  function useInboxNotificationsSuspense() {
1938
- 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) {
1939
2036
  throw fetchInboxNotifications();
1940
2037
  }
1941
2038
  React3.useEffect(() => {
@@ -1948,12 +2045,7 @@ function createLiveblocksContext(client) {
1948
2045
  store.subscribe,
1949
2046
  store.get,
1950
2047
  store.get,
1951
- (state) => {
1952
- return {
1953
- inboxNotifications: selectedInboxNotifications(state),
1954
- isLoading: false
1955
- };
1956
- }
2048
+ useInboxNotificationsSuspenseSelector
1957
2049
  );
1958
2050
  }
1959
2051
  function selectUnreadInboxNotificationsCount(state) {
@@ -1965,38 +2057,46 @@ function createLiveblocksContext(client) {
1965
2057
  }
1966
2058
  return count;
1967
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
+ }
1968
2078
  function useUnreadInboxNotificationsCount() {
1969
2079
  useEffect5(() => {
1970
2080
  void fetchInboxNotifications();
1971
2081
  incrementInboxNotificationsSubscribers();
1972
2082
  return () => decrementInboxNotificationsSubscribers();
1973
- });
2083
+ }, []);
1974
2084
  return useSyncExternalStoreWithSelector2(
1975
2085
  store.subscribe,
1976
2086
  store.get,
1977
2087
  store.get,
1978
- (state) => {
1979
- const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
1980
- if (query === void 0 || query.isLoading) {
1981
- return {
1982
- isLoading: true
1983
- };
1984
- }
1985
- if (query.error !== void 0) {
1986
- return {
1987
- error: query.error,
1988
- isLoading: false
1989
- };
1990
- }
1991
- return {
1992
- isLoading: false,
1993
- count: selectUnreadInboxNotificationsCount(state)
1994
- };
1995
- }
2088
+ useUnreadInboxNotificationsCountSelector
1996
2089
  );
1997
2090
  }
2091
+ function useUnreadInboxNotificationsCountSuspenseSelector(state) {
2092
+ return {
2093
+ isLoading: false,
2094
+ count: selectUnreadInboxNotificationsCount(state)
2095
+ };
2096
+ }
1998
2097
  function useUnreadInboxNotificationsCountSuspense() {
1999
- 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) {
2000
2100
  throw fetchInboxNotifications();
2001
2101
  }
2002
2102
  React3.useEffect(() => {
@@ -2009,12 +2109,7 @@ function createLiveblocksContext(client) {
2009
2109
  store.subscribe,
2010
2110
  store.get,
2011
2111
  store.get,
2012
- (state) => {
2013
- return {
2014
- isLoading: false,
2015
- count: selectUnreadInboxNotificationsCount(state)
2016
- };
2017
- }
2112
+ useUnreadInboxNotificationsCountSuspenseSelector
2018
2113
  );
2019
2114
  }
2020
2115
  function useMarkInboxNotificationAsRead() {
@@ -2029,20 +2124,30 @@ function createLiveblocksContext(client) {
2029
2124
  });
2030
2125
  client.markInboxNotificationAsRead(inboxNotificationId).then(
2031
2126
  () => {
2032
- store.set((state) => ({
2033
- ...state,
2034
- inboxNotifications: {
2035
- ...state.inboxNotifications,
2036
- [inboxNotificationId]: {
2037
- // TODO: Handle potential deleted inbox notification
2038
- ...state.inboxNotifications[inboxNotificationId],
2039
- readAt
2040
- }
2041
- },
2042
- optimisticUpdates: state.optimisticUpdates.filter(
2043
- (update) => update.id !== optimisticUpdateId
2044
- )
2045
- }));
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
+ });
2046
2151
  },
2047
2152
  () => {
2048
2153
  store.set((state) => ({
@@ -2093,10 +2198,7 @@ function createLiveblocksContext(client) {
2093
2198
  }, []);
2094
2199
  }
2095
2200
  function useThreadFromCache(threadId) {
2096
- return useSyncExternalStoreWithSelector2(
2097
- store.subscribe,
2098
- store.get,
2099
- store.get,
2201
+ const selector = useCallback3(
2100
2202
  (state) => {
2101
2203
  const thread = state.threads[threadId];
2102
2204
  if (thread === void 0) {
@@ -2105,7 +2207,14 @@ function createLiveblocksContext(client) {
2105
2207
  );
2106
2208
  }
2107
2209
  return thread;
2108
- }
2210
+ },
2211
+ [threadId]
2212
+ );
2213
+ return useSyncExternalStoreWithSelector2(
2214
+ store.subscribe,
2215
+ store.get,
2216
+ store.get,
2217
+ selector
2109
2218
  );
2110
2219
  }
2111
2220
  const currentUserIdStore = client[kInternal3].currentUserIdStore;