@liveblocks/react 2.7.0-versions2 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/version.ts
2
2
  var PKG_NAME = "@liveblocks/react";
3
- var PKG_VERSION = "2.7.0-versions2";
3
+ var PKG_VERSION = "2.7.1";
4
4
  var PKG_FORMAT = "cjs";
5
5
 
6
6
  // src/ClientSideSuspense.tsx
7
- var _react = require('react'); var React = _interopRequireWildcard(_react); var React4 = _interopRequireWildcard(_react); var React3 = _interopRequireWildcard(_react);
7
+ var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react); var React5 = _interopRequireWildcard(_react); var React4 = _interopRequireWildcard(_react);
8
8
  function ClientSideSuspense(props) {
9
9
  const [mounted, setMounted] = React.useState(false);
10
10
  React.useEffect(() => {
@@ -13,169 +13,18 @@ function ClientSideSuspense(props) {
13
13
  return /* @__PURE__ */ React.createElement(React.Suspense, { fallback: props.fallback }, mounted ? typeof props.children === "function" ? props.children() : props.children : props.fallback);
14
14
  }
15
15
 
16
- // src/comments/lib/selected-threads.ts
16
+ // src/contexts.ts
17
17
 
18
-
19
- var _core = require('@liveblocks/core');
20
- function selectedUserThreads(state) {
21
- const result = _core.applyOptimisticUpdates.call(void 0, state);
22
- const threads = Object.values(result.threads).filter(
23
- (thread) => {
24
- if (thread.deletedAt !== void 0) {
25
- return false;
26
- }
27
- return true;
28
- }
29
- );
30
- return threads.sort(
31
- (a, b) => (_nullishCoalesce(b.updatedAt, () => ( b.createdAt))).getTime() - (_nullishCoalesce(a.updatedAt, () => ( a.createdAt))).getTime()
32
- );
18
+ var RoomContext = React2.createContext(null);
19
+ function useRoomOrNull() {
20
+ return React2.useContext(RoomContext);
33
21
  }
34
- function selectedThreads(roomId, state, options) {
35
- const result = _core.applyOptimisticUpdates.call(void 0, state);
36
- const threads = Object.values(result.threads).filter(
37
- (thread) => {
38
- if (thread.roomId !== roomId) return false;
39
- if (thread.deletedAt !== void 0) {
40
- return false;
41
- }
42
- const query = options.query;
43
- if (!query) return true;
44
- if (query.resolved !== void 0 && thread.resolved !== query.resolved) {
45
- return false;
46
- }
47
- for (const key in query.metadata) {
48
- const metadataValue = thread.metadata[key];
49
- const filterValue = query.metadata[key];
50
- if (assertFilterIsStartsWithOperator(filterValue) && assertMetadataValueIsString(metadataValue)) {
51
- if (metadataValue.startsWith(filterValue.startsWith)) {
52
- return true;
53
- }
54
- }
55
- if (metadataValue !== filterValue) {
56
- return false;
57
- }
58
- }
59
- return true;
60
- }
61
- );
62
- return threads.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
22
+ function useIsInsideRoom() {
23
+ const room = useRoomOrNull();
24
+ return room !== null;
63
25
  }
64
- var assertFilterIsStartsWithOperator = (filter) => {
65
- if (typeof filter === "object" && typeof filter.startsWith === "string") {
66
- return true;
67
- } else {
68
- return false;
69
- }
70
- };
71
- var assertMetadataValueIsString = (value) => {
72
- return typeof value === "string";
73
- };
74
-
75
- // src/comments/errors.ts
76
- var CreateThreadError = class extends Error {
77
- constructor(cause, context) {
78
- super("Create thread failed.");
79
- this.cause = cause;
80
- this.context = context;
81
- this.name = "CreateThreadError";
82
- }
83
- };
84
- var DeleteThreadError = class extends Error {
85
- constructor(cause, context) {
86
- super("Delete thread failed.");
87
- this.cause = cause;
88
- this.context = context;
89
- this.name = "DeleteThreadError";
90
- }
91
- };
92
- var EditThreadMetadataError = class extends Error {
93
- constructor(cause, context) {
94
- super("Edit thread metadata failed.");
95
- this.cause = cause;
96
- this.context = context;
97
- this.name = "EditThreadMetadataError";
98
- }
99
- };
100
- var MarkThreadAsResolvedError = class extends Error {
101
- constructor(cause, context) {
102
- super("Mark thread as resolved failed.");
103
- this.cause = cause;
104
- this.context = context;
105
- this.name = "MarkThreadAsResolvedError";
106
- }
107
- };
108
- var MarkThreadAsUnresolvedError = class extends Error {
109
- constructor(cause, context) {
110
- super("Mark thread as unresolved failed.");
111
- this.cause = cause;
112
- this.context = context;
113
- this.name = "MarkThreadAsUnresolvedError";
114
- }
115
- };
116
- var CreateCommentError = class extends Error {
117
- constructor(cause, context) {
118
- super("Create comment failed.");
119
- this.cause = cause;
120
- this.context = context;
121
- this.name = "CreateCommentError";
122
- }
123
- };
124
- var EditCommentError = class extends Error {
125
- constructor(cause, context) {
126
- super("Edit comment failed.");
127
- this.cause = cause;
128
- this.context = context;
129
- this.name = "EditCommentError";
130
- }
131
- };
132
- var DeleteCommentError = class extends Error {
133
- constructor(cause, context) {
134
- super("Delete comment failed.");
135
- this.cause = cause;
136
- this.context = context;
137
- this.name = "DeleteCommentError";
138
- }
139
- };
140
- var AddReactionError = class extends Error {
141
- constructor(cause, context) {
142
- super("Add reaction failed.");
143
- this.cause = cause;
144
- this.context = context;
145
- this.name = "AddReactionError";
146
- }
147
- };
148
- var RemoveReactionError = class extends Error {
149
- constructor(cause, context) {
150
- super("Remove reaction failed.");
151
- this.cause = cause;
152
- this.context = context;
153
- this.name = "RemoveReactionError";
154
- }
155
- };
156
- var MarkInboxNotificationAsReadError = class extends Error {
157
- constructor(cause, context) {
158
- super("Mark inbox notification as read failed.");
159
- this.cause = cause;
160
- this.context = context;
161
- this.name = "MarkInboxNotificationAsReadError";
162
- }
163
- };
164
- var UpdateNotificationSettingsError = class extends Error {
165
- constructor(cause, context) {
166
- super("Update notification settings failed.");
167
- this.cause = cause;
168
- this.context = context;
169
- this.name = "UpdateNotificationSettingsError";
170
- }
171
- };
172
-
173
- // src/room.tsx
174
- var _client = require('@liveblocks/client');
175
-
176
-
177
-
178
26
 
27
+ // src/liveblocks.tsx
179
28
 
180
29
 
181
30
 
@@ -185,6 +34,7 @@ var _client = require('@liveblocks/client');
185
34
 
186
35
 
187
36
 
37
+ var _core = require('@liveblocks/core');
188
38
 
189
39
 
190
40
 
@@ -192,27 +42,52 @@ var _client = require('@liveblocks/client');
192
42
 
193
43
 
194
44
 
45
+ var _indexjs = require('use-sync-external-store/shim/index.js');
195
46
  var _withselectorjs = require('use-sync-external-store/shim/with-selector.js');
196
47
 
197
- // src/comments/lib/select-notification-settings.ts
198
-
199
-
48
+ // src/lib/compare.ts
49
+ function byFirstCreated(a, b) {
50
+ return a.createdAt.getTime() - b.createdAt.getTime();
51
+ }
52
+ function isMoreRecentlyUpdated(a, b) {
53
+ return byMostRecentlyUpdated(a, b) < 0;
54
+ }
55
+ function byMostRecentlyUpdated(a, b) {
56
+ return (_nullishCoalesce(b.updatedAt, () => ( b.createdAt))).getTime() - (_nullishCoalesce(a.updatedAt, () => ( a.createdAt))).getTime();
57
+ }
200
58
 
59
+ // src/lib/guards.ts
201
60
 
202
- function selectNotificationSettings(roomId, state) {
203
- const { notificationSettings } = _core.applyOptimisticUpdates.call(void 0, state);
204
- return _core.nn.call(void 0, notificationSettings[roomId]);
61
+ function isStartsWith(blob) {
62
+ return _core.isPlainObject.call(void 0, blob) && isString(blob.startsWith);
63
+ }
64
+ function isString(value) {
65
+ return typeof value === "string";
205
66
  }
206
67
 
207
- // src/comments/lib/selected-inbox-notifications.ts
208
-
209
- function selectedInboxNotifications(state) {
210
- const result = _core.applyOptimisticUpdates.call(void 0, state);
211
- return Object.values(result.inboxNotifications).sort(
212
- // Sort so that the most recent notifications are first
213
- (a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime()
68
+ // src/lib/querying.ts
69
+ function makeThreadsFilter(query) {
70
+ return (thread) => matchesQuery(thread, query) && matchesMetadata(thread, query);
71
+ }
72
+ function matchesQuery(thread, q) {
73
+ return q.resolved === void 0 || thread.resolved === q.resolved;
74
+ }
75
+ function matchesMetadata(thread, q) {
76
+ const metadata = thread.metadata;
77
+ return q.metadata === void 0 || Object.entries(q.metadata).every(
78
+ ([key, op]) => (
79
+ // Boolean logic: op? => value matches the operator
80
+ op === void 0 || matchesOperator(metadata[key], op)
81
+ )
214
82
  );
215
83
  }
84
+ function matchesOperator(value, op) {
85
+ if (isStartsWith(op)) {
86
+ return isString(value) && value.startsWith(op.startsWith);
87
+ } else {
88
+ return value === op;
89
+ }
90
+ }
216
91
 
217
92
  // src/lib/retry-error.ts
218
93
 
@@ -243,6 +118,21 @@ async function autoRetry(promiseFn, maxTries, backoff) {
243
118
  }
244
119
  }
245
120
 
121
+ // src/lib/shallow2.ts
122
+
123
+ function shallow2(a, b) {
124
+ if (!_core.isPlainObject.call(void 0, a) || !_core.isPlainObject.call(void 0, b)) {
125
+ return _core.shallow.call(void 0, a, b);
126
+ }
127
+ const keysA = Object.keys(a);
128
+ if (keysA.length !== Object.keys(b).length) {
129
+ return false;
130
+ }
131
+ return keysA.every(
132
+ (key) => Object.prototype.hasOwnProperty.call(b, key) && _core.shallow.call(void 0, a[key], b[key])
133
+ );
134
+ }
135
+
246
136
  // src/lib/use-initial.ts
247
137
 
248
138
 
@@ -300,12 +190,7 @@ var use = (
300
190
  }
301
191
  );
302
192
 
303
- // src/liveblocks.tsx
304
-
305
-
306
-
307
-
308
-
193
+ // src/umbrella-store.ts
309
194
 
310
195
 
311
196
 
@@ -313,13 +198,810 @@ var use = (
313
198
 
314
199
 
315
200
 
201
+ var UmbrellaStore = class {
202
+ constructor() {
203
+ this._prevState = null;
204
+ this._stateCached = null;
205
+ this._store = _core.createStore.call(void 0, {
206
+ rawThreadsById: {},
207
+ queries: {},
208
+ optimisticUpdates: [],
209
+ inboxNotificationsById: {},
210
+ notificationSettingsByRoomId: {},
211
+ versionsByRoomId: {}
212
+ });
213
+ this.getThreads = this.getThreads.bind(this);
214
+ this.getInboxNotifications = this.getInboxNotifications.bind(this);
215
+ this.getNotificationSettings = this.getNotificationSettings.bind(this);
216
+ this.getVersions = this.getVersions.bind(this);
217
+ this.subscribeThreads = this.subscribeThreads.bind(this);
218
+ this.subscribeInboxNotifications = this.subscribeInboxNotifications.bind(this);
219
+ this.subscribeNotificationSettings = this.subscribeNotificationSettings.bind(this);
220
+ this.subscribeVersions = this.subscribeVersions.bind(this);
221
+ this._hasOptimisticUpdates = this._hasOptimisticUpdates.bind(this);
222
+ this._subscribeOptimisticUpdates = this._subscribeOptimisticUpdates.bind(this);
223
+ }
224
+ get() {
225
+ const rawState = this._store.get();
226
+ if (this._prevState !== rawState || this._stateCached === null) {
227
+ this._prevState = rawState;
228
+ this._stateCached = applyOptimisticUpdates(rawState);
229
+ }
230
+ return this._stateCached;
231
+ }
232
+ getThreads() {
233
+ return this.get();
234
+ }
235
+ getInboxNotifications() {
236
+ return this.get();
237
+ }
238
+ getNotificationSettings() {
239
+ return this.get();
240
+ }
241
+ getVersions() {
242
+ return this.get();
243
+ }
244
+ /**
245
+ * @private Only used by the E2E test suite.
246
+ */
247
+ _hasOptimisticUpdates() {
248
+ return this._store.get().optimisticUpdates.length > 0;
249
+ }
250
+ subscribe(callback) {
251
+ return this._store.subscribe(callback);
252
+ }
253
+ /**
254
+ * @private Only used by the E2E test suite.
255
+ */
256
+ _subscribeOptimisticUpdates(callback) {
257
+ return this.subscribe(callback);
258
+ }
259
+ subscribeThreads(callback) {
260
+ return this.subscribe(callback);
261
+ }
262
+ subscribeInboxNotifications(callback) {
263
+ return this.subscribe(callback);
264
+ }
265
+ subscribeNotificationSettings(callback) {
266
+ return this.subscribe(callback);
267
+ }
268
+ subscribeVersions(callback) {
269
+ return this.subscribe(callback);
270
+ }
271
+ // Direct low-level cache mutations ------------------------------------------------- {{{
272
+ updateThreadsCache(mapFn) {
273
+ this._store.set((state) => {
274
+ const threads = mapFn(state.rawThreadsById);
275
+ return threads !== state.rawThreadsById ? { ...state, rawThreadsById: threads } : state;
276
+ });
277
+ }
278
+ updateInboxNotificationsCache(mapFn) {
279
+ this._store.set((state) => {
280
+ const inboxNotifications = mapFn(state.inboxNotificationsById);
281
+ return inboxNotifications !== state.inboxNotificationsById ? { ...state, inboxNotificationsById: inboxNotifications } : state;
282
+ });
283
+ }
284
+ setNotificationSettings(roomId, settings) {
285
+ this._store.set((state) => ({
286
+ ...state,
287
+ notificationSettingsByRoomId: {
288
+ ...state.notificationSettingsByRoomId,
289
+ [roomId]: settings
290
+ }
291
+ }));
292
+ }
293
+ setVersions(roomId, versions) {
294
+ this._store.set((state) => ({
295
+ ...state,
296
+ versionsByRoomId: {
297
+ ...state.versionsByRoomId,
298
+ [roomId]: versions
299
+ }
300
+ }));
301
+ }
302
+ setQueryState(queryKey, queryState) {
303
+ this._store.set((state) => ({
304
+ ...state,
305
+ queries: {
306
+ ...state.queries,
307
+ [queryKey]: queryState
308
+ }
309
+ }));
310
+ }
311
+ updateOptimisticUpdatesCache(mapFn) {
312
+ this._store.set((state) => ({
313
+ ...state,
314
+ optimisticUpdates: mapFn(state.optimisticUpdates)
315
+ }));
316
+ }
317
+ // ---------------------------------------------------------------------------------- }}}
318
+ /** @internal - Only call this method from unit tests. */
319
+ force_set(callback) {
320
+ return this._store.set(callback);
321
+ }
322
+ /**
323
+ * Updates an existing inbox notification with a new value, replacing the
324
+ * corresponding optimistic update.
325
+ *
326
+ * This will not update anything if the inbox notification ID isn't found in
327
+ * the cache.
328
+ */
329
+ updateInboxNotification(inboxNotificationId, optimisticUpdateId, callback) {
330
+ this._store.batch(() => {
331
+ this.removeOptimisticUpdate(optimisticUpdateId);
332
+ this.updateInboxNotificationsCache((cache) => {
333
+ const existing = cache[inboxNotificationId];
334
+ if (!existing) {
335
+ return cache;
336
+ }
337
+ const inboxNotifications = {
338
+ ...cache,
339
+ [inboxNotificationId]: callback(existing)
340
+ };
341
+ return inboxNotifications;
342
+ });
343
+ });
344
+ }
345
+ /**
346
+ * Updates *all* inbox notifications by running a mapper function over all of
347
+ * them, replacing the corresponding optimistic update.
348
+ */
349
+ updateAllInboxNotifications(optimisticUpdateId, mapFn) {
350
+ this._store.batch(() => {
351
+ this.removeOptimisticUpdate(optimisticUpdateId);
352
+ this.updateInboxNotificationsCache((cache) => _core.mapValues.call(void 0, cache, mapFn));
353
+ });
354
+ }
355
+ /**
356
+ * Deletes an existing inbox notification, replacing the corresponding
357
+ * optimistic update.
358
+ */
359
+ deleteInboxNotification(inboxNotificationId, optimisticUpdateId) {
360
+ this._store.batch(() => {
361
+ this.removeOptimisticUpdate(optimisticUpdateId);
362
+ this.updateInboxNotificationsCache((cache) => {
363
+ const { [inboxNotificationId]: removed, ...newCache } = cache;
364
+ return removed === void 0 ? cache : newCache;
365
+ });
366
+ });
367
+ }
368
+ /**
369
+ * Deletes *all* inbox notifications, replacing the corresponding optimistic
370
+ * update.
371
+ */
372
+ deleteAllInboxNotifications(optimisticUpdateId) {
373
+ this._store.batch(() => {
374
+ this.removeOptimisticUpdate(optimisticUpdateId);
375
+ this.updateInboxNotificationsCache(() => ({}));
376
+ });
377
+ }
378
+ /**
379
+ * Creates an new thread, replacing the corresponding optimistic update.
380
+ */
381
+ createThread(optimisticUpdateId, thread) {
382
+ this._store.batch(() => {
383
+ this.removeOptimisticUpdate(optimisticUpdateId);
384
+ this.updateThreadsCache((cache) => ({ ...cache, [thread.id]: thread }));
385
+ });
386
+ }
387
+ /**
388
+ * Updates an existing thread with a new value, replacing the corresponding
389
+ * optimistic update.
390
+ *
391
+ * This will not update anything if:
392
+ * - The thread ID isn't found in the cache; or
393
+ * - The thread ID was already deleted from the cache; or
394
+ * - The thread ID in the cache was updated more recently than the optimistic
395
+ * update's timestamp (if given)
396
+ */
397
+ updateThread(threadId, optimisticUpdateId, callback, updatedAt) {
398
+ this._store.batch(() => {
399
+ if (optimisticUpdateId !== null) {
400
+ this.removeOptimisticUpdate(optimisticUpdateId);
401
+ }
402
+ this.updateThreadsCache((cache) => {
403
+ const existing = cache[threadId];
404
+ if (!existing) {
405
+ return cache;
406
+ }
407
+ if (existing.deletedAt !== void 0) {
408
+ return cache;
409
+ }
410
+ if (!!updatedAt && !!existing.updatedAt && existing.updatedAt > updatedAt) {
411
+ return cache;
412
+ }
413
+ return { ...cache, [threadId]: callback(existing) };
414
+ });
415
+ });
416
+ }
417
+ patchThread(threadId, optimisticUpdateId, patch, updatedAt) {
418
+ return this.updateThread(
419
+ threadId,
420
+ optimisticUpdateId,
421
+ (thread) => ({ ...thread, ..._core.compactObject.call(void 0, patch) }),
422
+ updatedAt
423
+ );
424
+ }
425
+ addReaction(threadId, optimisticUpdateId, commentId, reaction, createdAt) {
426
+ this.updateThread(
427
+ threadId,
428
+ optimisticUpdateId,
429
+ (thread) => applyAddReaction(thread, commentId, reaction),
430
+ createdAt
431
+ );
432
+ }
433
+ removeReaction(threadId, optimisticUpdateId, commentId, emoji, userId, removedAt) {
434
+ this.updateThread(
435
+ threadId,
436
+ optimisticUpdateId,
437
+ (thread) => applyRemoveReaction(thread, commentId, emoji, userId, removedAt),
438
+ removedAt
439
+ );
440
+ }
441
+ /**
442
+ * Soft-deletes an existing thread by setting its `deletedAt` value,
443
+ * replacing the corresponding optimistic update.
444
+ *
445
+ * This will not update anything if:
446
+ * - The thread ID isn't found in the cache; or
447
+ * - The thread ID was already deleted from the cache
448
+ */
449
+ deleteThread(threadId, optimisticUpdateId) {
450
+ return this.updateThread(
451
+ threadId,
452
+ optimisticUpdateId,
453
+ // A deletion is actually an update of the deletedAt property internally
454
+ (thread) => ({ ...thread, updatedAt: /* @__PURE__ */ new Date(), deletedAt: /* @__PURE__ */ new Date() })
455
+ );
456
+ }
457
+ /**
458
+ * Creates an existing comment and ensures the associated notification is
459
+ * updated correctly, replacing the corresponding optimistic update.
460
+ */
461
+ createComment(newComment, optimisticUpdateId) {
462
+ this._store.batch(() => {
463
+ this.removeOptimisticUpdate(optimisticUpdateId);
464
+ const existingThread = this._store.get().rawThreadsById[newComment.threadId];
465
+ if (!existingThread) {
466
+ return;
467
+ }
468
+ this.updateThreadsCache((cache) => ({
469
+ ...cache,
470
+ [newComment.threadId]: applyUpsertComment(existingThread, newComment)
471
+ }));
472
+ this.updateInboxNotificationsCache((cache) => {
473
+ const existingNotification = Object.values(cache).find(
474
+ (notification) => notification.kind === "thread" && notification.threadId === newComment.threadId
475
+ );
476
+ if (!existingNotification) {
477
+ return cache;
478
+ }
479
+ return {
480
+ ...cache,
481
+ [existingNotification.id]: {
482
+ ...existingNotification,
483
+ notifiedAt: newComment.createdAt,
484
+ readAt: newComment.createdAt
485
+ }
486
+ };
487
+ });
488
+ });
489
+ }
490
+ editComment(threadId, optimisticUpdateId, editedComment) {
491
+ return this.updateThread(
492
+ threadId,
493
+ optimisticUpdateId,
494
+ (thread) => applyUpsertComment(thread, editedComment)
495
+ );
496
+ }
497
+ deleteComment(threadId, optimisticUpdateId, commentId, deletedAt) {
498
+ return this.updateThread(
499
+ threadId,
500
+ optimisticUpdateId,
501
+ (thread) => applyDeleteComment(thread, commentId, deletedAt),
502
+ deletedAt
503
+ );
504
+ }
505
+ updateThreadAndNotification(thread, inboxNotification) {
506
+ this._store.batch(() => {
507
+ this.updateThreadsCache((cache) => {
508
+ const existingThread = cache[thread.id];
509
+ return existingThread === void 0 || isMoreRecentlyUpdated(thread, existingThread) ? { ...cache, [thread.id]: thread } : cache;
510
+ });
511
+ if (inboxNotification !== void 0) {
512
+ this.updateInboxNotificationsCache((cache) => ({
513
+ ...cache,
514
+ [inboxNotification.id]: inboxNotification
515
+ }));
516
+ }
517
+ });
518
+ }
519
+ updateThreadsAndNotifications(threads, inboxNotifications, deletedThreads, deletedInboxNotifications, queryKey) {
520
+ this._store.batch(() => {
521
+ this.updateThreadsCache(
522
+ (cache) => applyThreadUpdates(cache, {
523
+ newThreads: threads,
524
+ deletedThreads
525
+ })
526
+ );
527
+ this.updateInboxNotificationsCache(
528
+ (cache) => applyNotificationsUpdates(cache, {
529
+ newInboxNotifications: inboxNotifications,
530
+ deletedNotifications: deletedInboxNotifications
531
+ })
532
+ );
533
+ if (queryKey !== void 0) {
534
+ this.setQueryOK(queryKey);
535
+ }
536
+ });
537
+ }
538
+ /**
539
+ * Updates existing notification setting for a room with a new value,
540
+ * replacing the corresponding optimistic update.
541
+ */
542
+ updateRoomInboxNotificationSettings2(roomId, optimisticUpdateId, settings) {
543
+ this._store.batch(() => {
544
+ this.removeOptimisticUpdate(optimisticUpdateId);
545
+ this.setNotificationSettings(roomId, settings);
546
+ });
547
+ }
548
+ updateRoomInboxNotificationSettings(roomId, settings, queryKey) {
549
+ this._store.batch(() => {
550
+ this.setQueryOK(queryKey);
551
+ this.setNotificationSettings(roomId, settings);
552
+ });
553
+ }
554
+ updateRoomVersions(roomId, versions, queryKey) {
555
+ this._store.batch(() => {
556
+ this.setVersions(roomId, versions);
557
+ if (queryKey !== void 0) {
558
+ this.setQueryOK(queryKey);
559
+ }
560
+ });
561
+ }
562
+ addOptimisticUpdate(optimisticUpdate) {
563
+ const id = _core.nanoid.call(void 0, );
564
+ const newUpdate = { ...optimisticUpdate, id };
565
+ this.updateOptimisticUpdatesCache((cache) => [...cache, newUpdate]);
566
+ return id;
567
+ }
568
+ removeOptimisticUpdate(optimisticUpdateId) {
569
+ this.updateOptimisticUpdatesCache(
570
+ (cache) => cache.filter((ou) => ou.id !== optimisticUpdateId)
571
+ );
572
+ }
573
+ //
574
+ // Query State APIs
575
+ //
576
+ setQueryLoading(queryKey) {
577
+ this.setQueryState(queryKey, { isLoading: true });
578
+ }
579
+ setQueryOK(queryKey) {
580
+ this.setQueryState(queryKey, { isLoading: false, data: void 0 });
581
+ }
582
+ setQueryError(queryKey, error) {
583
+ this.setQueryState(queryKey, { isLoading: false, error });
584
+ }
585
+ };
586
+ function applyOptimisticUpdates(state) {
587
+ const output = {
588
+ threads: { ...state.rawThreadsById },
589
+ inboxNotifications: { ...state.inboxNotificationsById },
590
+ notificationSettings: { ...state.notificationSettingsByRoomId }
591
+ };
592
+ for (const optimisticUpdate of state.optimisticUpdates) {
593
+ switch (optimisticUpdate.type) {
594
+ case "create-thread": {
595
+ output.threads[optimisticUpdate.thread.id] = optimisticUpdate.thread;
596
+ break;
597
+ }
598
+ case "edit-thread-metadata": {
599
+ const thread = output.threads[optimisticUpdate.threadId];
600
+ if (thread === void 0) {
601
+ break;
602
+ }
603
+ if (thread.deletedAt !== void 0) {
604
+ break;
605
+ }
606
+ if (thread.updatedAt !== void 0 && thread.updatedAt > optimisticUpdate.updatedAt) {
607
+ break;
608
+ }
609
+ output.threads[thread.id] = {
610
+ ...thread,
611
+ updatedAt: optimisticUpdate.updatedAt,
612
+ metadata: {
613
+ ...thread.metadata,
614
+ ...optimisticUpdate.metadata
615
+ }
616
+ };
617
+ break;
618
+ }
619
+ case "mark-thread-as-resolved": {
620
+ const thread = output.threads[optimisticUpdate.threadId];
621
+ if (thread === void 0) {
622
+ break;
623
+ }
624
+ if (thread.deletedAt !== void 0) {
625
+ break;
626
+ }
627
+ output.threads[thread.id] = {
628
+ ...thread,
629
+ resolved: true
630
+ };
631
+ break;
632
+ }
633
+ case "mark-thread-as-unresolved": {
634
+ const thread = output.threads[optimisticUpdate.threadId];
635
+ if (thread === void 0) {
636
+ break;
637
+ }
638
+ if (thread.deletedAt !== void 0) {
639
+ break;
640
+ }
641
+ output.threads[thread.id] = {
642
+ ...thread,
643
+ resolved: false
644
+ };
645
+ break;
646
+ }
647
+ case "create-comment": {
648
+ const thread = output.threads[optimisticUpdate.comment.threadId];
649
+ if (thread === void 0) {
650
+ break;
651
+ }
652
+ output.threads[thread.id] = applyUpsertComment(
653
+ thread,
654
+ optimisticUpdate.comment
655
+ );
656
+ const inboxNotification = Object.values(output.inboxNotifications).find(
657
+ (notification) => notification.kind === "thread" && notification.threadId === thread.id
658
+ );
659
+ if (inboxNotification === void 0) {
660
+ break;
661
+ }
662
+ output.inboxNotifications[inboxNotification.id] = {
663
+ ...inboxNotification,
664
+ notifiedAt: optimisticUpdate.comment.createdAt,
665
+ readAt: optimisticUpdate.comment.createdAt
666
+ };
667
+ break;
668
+ }
669
+ case "edit-comment": {
670
+ const thread = output.threads[optimisticUpdate.comment.threadId];
671
+ if (thread === void 0) {
672
+ break;
673
+ }
674
+ output.threads[thread.id] = applyUpsertComment(
675
+ thread,
676
+ optimisticUpdate.comment
677
+ );
678
+ break;
679
+ }
680
+ case "delete-comment": {
681
+ const thread = output.threads[optimisticUpdate.threadId];
682
+ if (thread === void 0) {
683
+ break;
684
+ }
685
+ output.threads[thread.id] = applyDeleteComment(
686
+ thread,
687
+ optimisticUpdate.commentId,
688
+ optimisticUpdate.deletedAt
689
+ );
690
+ break;
691
+ }
692
+ case "delete-thread": {
693
+ const thread = output.threads[optimisticUpdate.threadId];
694
+ if (thread === void 0) {
695
+ break;
696
+ }
697
+ output.threads[optimisticUpdate.threadId] = {
698
+ ...output.threads[optimisticUpdate.threadId],
699
+ deletedAt: optimisticUpdate.deletedAt,
700
+ updatedAt: optimisticUpdate.deletedAt,
701
+ comments: []
702
+ };
703
+ break;
704
+ }
705
+ case "add-reaction": {
706
+ const thread = output.threads[optimisticUpdate.threadId];
707
+ if (thread === void 0) {
708
+ break;
709
+ }
710
+ output.threads[thread.id] = applyAddReaction(
711
+ thread,
712
+ optimisticUpdate.commentId,
713
+ optimisticUpdate.reaction
714
+ );
715
+ break;
716
+ }
717
+ case "remove-reaction": {
718
+ const thread = output.threads[optimisticUpdate.threadId];
719
+ if (thread === void 0) {
720
+ break;
721
+ }
722
+ output.threads[thread.id] = applyRemoveReaction(
723
+ thread,
724
+ optimisticUpdate.commentId,
725
+ optimisticUpdate.emoji,
726
+ optimisticUpdate.userId,
727
+ optimisticUpdate.removedAt
728
+ );
729
+ break;
730
+ }
731
+ case "mark-inbox-notification-as-read": {
732
+ output.inboxNotifications[optimisticUpdate.inboxNotificationId] = {
733
+ ...state.inboxNotificationsById[optimisticUpdate.inboxNotificationId],
734
+ readAt: optimisticUpdate.readAt
735
+ };
736
+ break;
737
+ }
738
+ case "mark-all-inbox-notifications-as-read": {
739
+ for (const id in output.inboxNotifications) {
740
+ output.inboxNotifications[id] = {
741
+ ...output.inboxNotifications[id],
742
+ readAt: optimisticUpdate.readAt
743
+ };
744
+ }
745
+ break;
746
+ }
747
+ case "delete-inbox-notification": {
748
+ const {
749
+ [optimisticUpdate.inboxNotificationId]: _,
750
+ ...inboxNotifications
751
+ } = output.inboxNotifications;
752
+ output.inboxNotifications = inboxNotifications;
753
+ break;
754
+ }
755
+ case "delete-all-inbox-notifications": {
756
+ output.inboxNotifications = {};
757
+ break;
758
+ }
759
+ case "update-notification-settings": {
760
+ output.notificationSettings[optimisticUpdate.roomId] = {
761
+ ...output.notificationSettings[optimisticUpdate.roomId],
762
+ ...optimisticUpdate.settings
763
+ };
764
+ }
765
+ }
766
+ }
767
+ const cleanedThreads = (
768
+ // Don't expose any soft-deleted threads
769
+ Object.values(output.threads).filter(
770
+ (thread) => !thread.deletedAt
771
+ )
772
+ );
773
+ const cleanedNotifications = (
774
+ // Sort so that the most recent notifications are first
775
+ Object.values(output.inboxNotifications).sort(
776
+ (a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime()
777
+ )
778
+ );
779
+ return {
780
+ inboxNotifications: cleanedNotifications,
781
+ inboxNotificationsById: output.inboxNotifications,
782
+ notificationSettingsByRoomId: output.notificationSettings,
783
+ queries: state.queries,
784
+ threads: cleanedThreads,
785
+ threadsById: output.threads,
786
+ versionsByRoomId: state.versionsByRoomId
787
+ };
788
+ }
789
+ function applyThreadUpdates(existingThreads, updates) {
790
+ const updatedThreads = { ...existingThreads };
791
+ updates.newThreads.forEach((thread) => {
792
+ const existingThread = updatedThreads[thread.id];
793
+ if (existingThread) {
794
+ if (isMoreRecentlyUpdated(existingThread, thread)) {
795
+ return;
796
+ }
797
+ }
798
+ updatedThreads[thread.id] = thread;
799
+ });
800
+ updates.deletedThreads.forEach(({ id, deletedAt }) => {
801
+ const existingThread = updatedThreads[id];
802
+ if (existingThread === void 0) return;
803
+ existingThread.deletedAt = deletedAt;
804
+ existingThread.updatedAt = deletedAt;
805
+ existingThread.comments = [];
806
+ });
807
+ return updatedThreads;
808
+ }
809
+ function applyNotificationsUpdates(existingInboxNotifications, updates) {
810
+ const updatedInboxNotifications = { ...existingInboxNotifications };
811
+ updates.newInboxNotifications.forEach((notification) => {
812
+ const existingNotification = updatedInboxNotifications[notification.id];
813
+ if (existingNotification) {
814
+ const result = compareInboxNotifications(
815
+ existingNotification,
816
+ notification
817
+ );
818
+ if (result === 1) return;
819
+ }
820
+ updatedInboxNotifications[notification.id] = notification;
821
+ });
822
+ updates.deletedNotifications.forEach(
823
+ ({ id }) => delete updatedInboxNotifications[id]
824
+ );
825
+ return updatedInboxNotifications;
826
+ }
827
+ function compareInboxNotifications(inboxNotificationA, inboxNotificationB) {
828
+ if (inboxNotificationA.notifiedAt > inboxNotificationB.notifiedAt) {
829
+ return 1;
830
+ } else if (inboxNotificationA.notifiedAt < inboxNotificationB.notifiedAt) {
831
+ return -1;
832
+ }
833
+ if (inboxNotificationA.readAt && inboxNotificationB.readAt) {
834
+ return inboxNotificationA.readAt > inboxNotificationB.readAt ? 1 : inboxNotificationA.readAt < inboxNotificationB.readAt ? -1 : 0;
835
+ } else if (inboxNotificationA.readAt || inboxNotificationB.readAt) {
836
+ return inboxNotificationA.readAt ? 1 : -1;
837
+ }
838
+ return 0;
839
+ }
840
+ function applyUpsertComment(thread, comment) {
841
+ if (thread.deletedAt !== void 0) {
842
+ return thread;
843
+ }
844
+ if (comment.threadId !== thread.id) {
845
+ _core.console.warn(
846
+ `Comment ${comment.id} does not belong to thread ${thread.id}`
847
+ );
848
+ return thread;
849
+ }
850
+ const existingComment = thread.comments.find(
851
+ (existingComment2) => existingComment2.id === comment.id
852
+ );
853
+ if (existingComment === void 0) {
854
+ const updatedAt = new Date(
855
+ Math.max(_optionalChain([thread, 'access', _2 => _2.updatedAt, 'optionalAccess', _3 => _3.getTime, 'call', _4 => _4()]) || 0, comment.createdAt.getTime())
856
+ );
857
+ const updatedThread = {
858
+ ...thread,
859
+ updatedAt,
860
+ comments: [...thread.comments, comment]
861
+ };
862
+ return updatedThread;
863
+ }
864
+ if (existingComment.deletedAt !== void 0) {
865
+ return thread;
866
+ }
867
+ if (existingComment.editedAt === void 0 || comment.editedAt === void 0 || existingComment.editedAt <= comment.editedAt) {
868
+ const updatedComments = thread.comments.map(
869
+ (existingComment2) => existingComment2.id === comment.id ? comment : existingComment2
870
+ );
871
+ const updatedThread = {
872
+ ...thread,
873
+ updatedAt: new Date(
874
+ Math.max(
875
+ _optionalChain([thread, 'access', _5 => _5.updatedAt, 'optionalAccess', _6 => _6.getTime, 'call', _7 => _7()]) || 0,
876
+ _optionalChain([comment, 'access', _8 => _8.editedAt, 'optionalAccess', _9 => _9.getTime, 'call', _10 => _10()]) || comment.createdAt.getTime()
877
+ )
878
+ ),
879
+ comments: updatedComments
880
+ };
881
+ return updatedThread;
882
+ }
883
+ return thread;
884
+ }
885
+ function applyDeleteComment(thread, commentId, deletedAt) {
886
+ if (thread.deletedAt !== void 0) {
887
+ return thread;
888
+ }
889
+ const existingComment = thread.comments.find(
890
+ (comment) => comment.id === commentId
891
+ );
892
+ if (existingComment === void 0) {
893
+ return thread;
894
+ }
895
+ if (existingComment.deletedAt !== void 0) {
896
+ return thread;
897
+ }
898
+ const updatedComments = thread.comments.map(
899
+ (comment) => comment.id === commentId ? {
900
+ ...comment,
901
+ deletedAt,
902
+ body: void 0
903
+ } : comment
904
+ );
905
+ if (!updatedComments.some((comment) => comment.deletedAt === void 0)) {
906
+ return {
907
+ ...thread,
908
+ deletedAt,
909
+ updatedAt: deletedAt,
910
+ comments: []
911
+ };
912
+ }
913
+ return {
914
+ ...thread,
915
+ updatedAt: deletedAt,
916
+ comments: updatedComments
917
+ };
918
+ }
919
+ function applyAddReaction(thread, commentId, reaction) {
920
+ if (thread.deletedAt !== void 0) {
921
+ return thread;
922
+ }
923
+ const existingComment = thread.comments.find(
924
+ (comment) => comment.id === commentId
925
+ );
926
+ if (existingComment === void 0) {
927
+ return thread;
928
+ }
929
+ if (existingComment.deletedAt !== void 0) {
930
+ return thread;
931
+ }
932
+ const updatedComments = thread.comments.map(
933
+ (comment) => comment.id === commentId ? {
934
+ ...comment,
935
+ reactions: upsertReaction(comment.reactions, reaction)
936
+ } : comment
937
+ );
938
+ return {
939
+ ...thread,
940
+ updatedAt: new Date(
941
+ Math.max(reaction.createdAt.getTime(), _optionalChain([thread, 'access', _11 => _11.updatedAt, 'optionalAccess', _12 => _12.getTime, 'call', _13 => _13()]) || 0)
942
+ ),
943
+ comments: updatedComments
944
+ };
945
+ }
946
+ function applyRemoveReaction(thread, commentId, emoji, userId, removedAt) {
947
+ if (thread.deletedAt !== void 0) {
948
+ return thread;
949
+ }
950
+ const existingComment = thread.comments.find(
951
+ (comment) => comment.id === commentId
952
+ );
953
+ if (existingComment === void 0) {
954
+ return thread;
955
+ }
956
+ if (existingComment.deletedAt !== void 0) {
957
+ return thread;
958
+ }
959
+ const updatedComments = thread.comments.map(
960
+ (comment) => comment.id === commentId ? {
961
+ ...comment,
962
+ reactions: comment.reactions.map(
963
+ (reaction) => reaction.emoji === emoji ? {
964
+ ...reaction,
965
+ users: reaction.users.filter((user) => user.id !== userId)
966
+ } : reaction
967
+ ).filter((reaction) => reaction.users.length > 0)
968
+ // Remove reactions with no users left
969
+ } : comment
970
+ );
971
+ return {
972
+ ...thread,
973
+ updatedAt: new Date(
974
+ Math.max(removedAt.getTime(), _optionalChain([thread, 'access', _14 => _14.updatedAt, 'optionalAccess', _15 => _15.getTime, 'call', _16 => _16()]) || 0)
975
+ ),
976
+ comments: updatedComments
977
+ };
978
+ }
979
+ function upsertReaction(reactions, reaction) {
980
+ const existingReaction = reactions.find(
981
+ (existingReaction2) => existingReaction2.emoji === reaction.emoji
982
+ );
983
+ if (existingReaction === void 0) {
984
+ return [
985
+ ...reactions,
986
+ {
987
+ emoji: reaction.emoji,
988
+ createdAt: reaction.createdAt,
989
+ users: [{ id: reaction.userId }]
990
+ }
991
+ ];
992
+ }
993
+ if (existingReaction.users.some((user) => user.id === reaction.userId) === false) {
994
+ return reactions.map(
995
+ (existingReaction2) => existingReaction2.emoji === reaction.emoji ? {
996
+ ...existingReaction2,
997
+ users: [...existingReaction2.users, { id: reaction.userId }]
998
+ } : existingReaction2
999
+ );
1000
+ }
1001
+ return reactions;
1002
+ }
316
1003
 
317
-
318
-
319
-
320
-
321
- var _indexjs = require('use-sync-external-store/shim/index.js');
322
-
1004
+ // src/liveblocks.tsx
323
1005
  var ClientContext = _react.createContext.call(void 0, null);
324
1006
  function missingUserError(userId) {
325
1007
  return new Error(`resolveUsers didn't return anything for user '${userId}'`);
@@ -329,6 +1011,7 @@ function missingRoomInfoError(roomId) {
329
1011
  `resolveRoomsInfo didn't return anything for room '${roomId}'`
330
1012
  );
331
1013
  }
1014
+ var _umbrellaStores = /* @__PURE__ */ new WeakMap();
332
1015
  var _extras = /* @__PURE__ */ new WeakMap();
333
1016
  var _bundles = /* @__PURE__ */ new WeakMap();
334
1017
  var POLLING_INTERVAL = 60 * 1e3;
@@ -348,32 +1031,13 @@ function selectorFor_useInboxNotifications(state) {
348
1031
  };
349
1032
  }
350
1033
  return {
351
- inboxNotifications: selectedInboxNotifications(state),
352
- isLoading: false
353
- };
354
- }
355
- function selectorFor_useUserThreads(state) {
356
- const query = state.queries[USER_THREADS_QUERY];
357
- if (query === void 0 || query.isLoading) {
358
- return {
359
- isLoading: true
360
- };
361
- }
362
- if (query.error !== void 0) {
363
- return {
364
- threads: [],
365
- error: query.error,
366
- isLoading: false
367
- };
368
- }
369
- return {
370
- threads: selectedUserThreads(state),
1034
+ inboxNotifications: state.inboxNotifications,
371
1035
  isLoading: false
372
1036
  };
373
1037
  }
374
1038
  function selectUnreadInboxNotificationsCount(state) {
375
1039
  let count = 0;
376
- for (const notification of selectedInboxNotifications(state)) {
1040
+ for (const notification of state.inboxNotifications) {
377
1041
  if (notification.readAt === null || notification.readAt < notification.notifiedAt) {
378
1042
  count++;
379
1043
  }
@@ -399,7 +1063,7 @@ function selectorFor_useUnreadInboxNotificationsCount(state) {
399
1063
  };
400
1064
  }
401
1065
  function selectorFor_useUser(state, userId) {
402
- if (state === void 0 || _optionalChain([state, 'optionalAccess', _2 => _2.isLoading])) {
1066
+ if (state === void 0 || _optionalChain([state, 'optionalAccess', _17 => _17.isLoading])) {
403
1067
  return _nullishCoalesce(state, () => ( { isLoading: true }));
404
1068
  }
405
1069
  if (state.error) {
@@ -417,7 +1081,7 @@ function selectorFor_useUser(state, userId) {
417
1081
  };
418
1082
  }
419
1083
  function selectorFor_useRoomInfo(state, roomId) {
420
- if (state === void 0 || _optionalChain([state, 'optionalAccess', _3 => _3.isLoading])) {
1084
+ if (state === void 0 || _optionalChain([state, 'optionalAccess', _18 => _18.isLoading])) {
421
1085
  return _nullishCoalesce(state, () => ( { isLoading: true }));
422
1086
  }
423
1087
  if (state.error) {
@@ -434,6 +1098,19 @@ function selectorFor_useRoomInfo(state, roomId) {
434
1098
  info: state.data
435
1099
  };
436
1100
  }
1101
+ function selectThreads(state, options) {
1102
+ let threads = state.threads;
1103
+ if (options.roomId !== null) {
1104
+ threads = threads.filter((thread) => thread.roomId === options.roomId);
1105
+ }
1106
+ const query = options.query;
1107
+ if (query) {
1108
+ threads = threads.filter(makeThreadsFilter(query));
1109
+ }
1110
+ return threads.sort(
1111
+ options.orderBy === "last-update" ? byMostRecentlyUpdated : byFirstCreated
1112
+ );
1113
+ }
437
1114
  function getOrCreateContextBundle(client) {
438
1115
  let bundle = _bundles.get(client);
439
1116
  if (!bundle) {
@@ -442,6 +1119,14 @@ function getOrCreateContextBundle(client) {
442
1119
  }
443
1120
  return bundle;
444
1121
  }
1122
+ function getUmbrellaStoreForClient(client) {
1123
+ let store = _umbrellaStores.get(client);
1124
+ if (!store) {
1125
+ store = new UmbrellaStore();
1126
+ _umbrellaStores.set(client, store);
1127
+ }
1128
+ return store;
1129
+ }
445
1130
  function getExtrasForClient(client) {
446
1131
  let extras = _extras.get(client);
447
1132
  if (!extras) {
@@ -451,8 +1136,7 @@ function getExtrasForClient(client) {
451
1136
  return extras;
452
1137
  }
453
1138
  function makeExtrasForClient(client) {
454
- const internals = client[_core.kInternal];
455
- const store = internals.cacheStore;
1139
+ const store = getUmbrellaStoreForClient(client);
456
1140
  let lastRequestedAt;
457
1141
  async function fetchInboxNotifications() {
458
1142
  if (lastRequestedAt === void 0) {
@@ -491,9 +1175,7 @@ function makeExtrasForClient(client) {
491
1175
  }
492
1176
  });
493
1177
  const waitUntilInboxNotificationsLoaded = _core.memoizeOnSuccess.call(void 0, async () => {
494
- store.setQueryState(INBOX_NOTIFICATIONS_QUERY, {
495
- isLoading: true
496
- });
1178
+ store.setQueryLoading(INBOX_NOTIFICATIONS_QUERY);
497
1179
  try {
498
1180
  await autoRetry(
499
1181
  () => fetchInboxNotifications(),
@@ -501,10 +1183,7 @@ function makeExtrasForClient(client) {
501
1183
  [5e3, 5e3, 1e4, 15e3]
502
1184
  );
503
1185
  } catch (err) {
504
- store.setQueryState(INBOX_NOTIFICATIONS_QUERY, {
505
- isLoading: false,
506
- error: err
507
- });
1186
+ store.setQueryError(INBOX_NOTIFICATIONS_QUERY, err);
508
1187
  throw err;
509
1188
  }
510
1189
  });
@@ -530,87 +1209,94 @@ function makeExtrasForClient(client) {
530
1209
  };
531
1210
  }, []);
532
1211
  }
533
- let userThreadsPollerSubscribers = 0;
534
- const userThreadsPoller = _core.makePoller.call(void 0, async () => {
1212
+ const userThreadsPoller = _core.makePoller.call(void 0, refreshUserThreads);
1213
+ let isFetchingUserThreadsUpdates = false;
1214
+ async function refreshUserThreads() {
1215
+ const since = userThreadslastRequestedAt;
1216
+ if (since === void 0 || isFetchingUserThreadsUpdates) {
1217
+ return;
1218
+ }
535
1219
  try {
536
- await waitUntilUserThreadsLoaded();
537
- await fetchUserThreads();
1220
+ isFetchingUserThreadsUpdates = true;
1221
+ const updates = await client[_core.kInternal].getThreadsSince({
1222
+ since
1223
+ });
1224
+ isFetchingUserThreadsUpdates = false;
1225
+ store.updateThreadsAndNotifications(
1226
+ updates.threads.updated,
1227
+ [],
1228
+ updates.threads.deleted,
1229
+ [],
1230
+ USER_THREADS_QUERY
1231
+ );
1232
+ userThreadslastRequestedAt = updates.requestedAt;
538
1233
  } catch (err) {
539
- console.warn(`Polling new user threads failed: ${String(err)}`);
1234
+ isFetchingUserThreadsUpdates = false;
1235
+ return;
540
1236
  }
541
- });
542
- let userThreadslastRequestedAt;
543
- function loadUserThreads() {
544
- void waitUntilUserThreadsLoaded().catch(() => {
545
- });
546
1237
  }
547
- const waitUntilUserThreadsLoaded = _core.memoizeOnSuccess.call(void 0, async () => {
548
- store.setQueryState(USER_THREADS_QUERY, {
549
- isLoading: true
550
- });
1238
+ const userThreadsSubscribersByQuery = /* @__PURE__ */ new Map();
1239
+ const userThreadsRequestsByQuery = /* @__PURE__ */ new Map();
1240
+ function incrementUserThreadsQuerySubscribers(queryKey) {
1241
+ const subscribers = _nullishCoalesce(userThreadsSubscribersByQuery.get(queryKey), () => ( 0));
1242
+ userThreadsSubscribersByQuery.set(queryKey, subscribers + 1);
1243
+ userThreadsPoller.start(POLLING_INTERVAL);
1244
+ return () => {
1245
+ const subscribers2 = userThreadsSubscribersByQuery.get(queryKey);
1246
+ if (subscribers2 === void 0 || subscribers2 <= 0) {
1247
+ console.warn(
1248
+ `Internal unexpected behavior. Cannot decrease subscriber count for query "${queryKey}"`
1249
+ );
1250
+ return;
1251
+ }
1252
+ userThreadsSubscribersByQuery.set(queryKey, subscribers2 - 1);
1253
+ let totalSubscribers = 0;
1254
+ for (const subscribers3 of userThreadsSubscribersByQuery.values()) {
1255
+ totalSubscribers += subscribers3;
1256
+ }
1257
+ if (totalSubscribers <= 0) {
1258
+ userThreadsPoller.stop();
1259
+ }
1260
+ };
1261
+ }
1262
+ let userThreadslastRequestedAt;
1263
+ async function getUserThreads(queryKey, options, { retryCount } = { retryCount: 0 }) {
1264
+ const existingRequest = userThreadsRequestsByQuery.get(queryKey);
1265
+ if (existingRequest !== void 0) return existingRequest;
1266
+ const request = client[_core.kInternal].getThreads(options);
1267
+ userThreadsRequestsByQuery.set(queryKey, request);
1268
+ store.setQueryLoading(queryKey);
551
1269
  try {
552
- await autoRetry(() => fetchUserThreads(), 5, [5e3, 5e3, 1e4, 15e3]);
553
- } catch (err) {
554
- store.setQueryState(USER_THREADS_QUERY, {
555
- isLoading: false,
556
- error: err
557
- });
558
- throw err;
559
- }
560
- });
561
- async function fetchUserThreads() {
562
- if (userThreadslastRequestedAt === void 0) {
563
- const result = await client[_core.kInternal].getThreads();
1270
+ const result = await request;
564
1271
  store.updateThreadsAndNotifications(
565
1272
  result.threads,
566
1273
  result.inboxNotifications,
567
1274
  [],
568
1275
  [],
569
- USER_THREADS_QUERY
570
- );
571
- userThreadslastRequestedAt = result.requestedAt;
572
- } else {
573
- const result = await client[_core.kInternal].getThreadsSince({
574
- since: userThreadslastRequestedAt
575
- });
576
- store.updateThreadsAndNotifications(
577
- result.threads.updated,
578
- result.inboxNotifications.updated,
579
- result.threads.deleted,
580
- result.inboxNotifications.deleted,
581
- USER_THREADS_QUERY
1276
+ queryKey
582
1277
  );
583
- if (userThreadslastRequestedAt < result.requestedAt) {
584
- userThreadslastRequestedAt = result.requestedAt;
585
- }
586
- }
587
- }
588
- function useEnableUserThreadsPolling() {
589
- _react.useEffect.call(void 0, () => {
590
- userThreadsPollerSubscribers++;
591
- userThreadsPoller.start(POLLING_INTERVAL);
592
- return () => {
593
- if (userThreadsPollerSubscribers <= 0) {
594
- console.warn(
595
- `Internal unexpected behavior. Cannot decrease subscriber count for query "${USER_THREADS_QUERY}"`
596
- );
597
- return;
598
- }
599
- userThreadsPollerSubscribers--;
600
- if (userThreadsPollerSubscribers <= 0) {
601
- userThreadsPoller.stop();
602
- }
603
- };
604
- }, []);
1278
+ if (userThreadslastRequestedAt === void 0 || userThreadslastRequestedAt < result.requestedAt) {
1279
+ userThreadslastRequestedAt = result.requestedAt;
1280
+ }
1281
+ userThreadsPoller.start(POLLING_INTERVAL);
1282
+ } catch (err) {
1283
+ userThreadsRequestsByQuery.delete(queryKey);
1284
+ retryError(() => {
1285
+ void getUserThreads(queryKey, options, {
1286
+ retryCount: retryCount + 1
1287
+ });
1288
+ }, retryCount);
1289
+ store.setQueryError(queryKey, err);
1290
+ }
1291
+ return;
605
1292
  }
606
1293
  return {
607
1294
  store,
608
1295
  useEnableInboxNotificationsPolling,
609
1296
  waitUntilInboxNotificationsLoaded,
610
1297
  loadInboxNotifications,
611
- useEnableUserThreadsPolling,
612
- waitUntilUserThreadsLoaded,
613
- loadUserThreads
1298
+ incrementUserThreadsQuerySubscribers,
1299
+ getUserThreads
614
1300
  };
615
1301
  }
616
1302
  function makeLiveblocksContextBundle(client) {
@@ -633,7 +1319,7 @@ function makeLiveblocksContextBundle(client) {
633
1319
  useDeleteInboxNotification: useDeleteInboxNotification2,
634
1320
  useDeleteAllInboxNotifications: useDeleteAllInboxNotifications2,
635
1321
  useInboxNotificationThread: useInboxNotificationThread2,
636
- useUserThreads_experimental: () => useUserThreads_withClient(client),
1322
+ useUserThreads_experimental,
637
1323
  ...shared.classic,
638
1324
  suspense: {
639
1325
  LiveblocksProvider: LiveblocksProvider2,
@@ -644,34 +1330,12 @@ function makeLiveblocksContextBundle(client) {
644
1330
  useDeleteInboxNotification: useDeleteInboxNotification2,
645
1331
  useDeleteAllInboxNotifications: useDeleteAllInboxNotifications2,
646
1332
  useInboxNotificationThread: useInboxNotificationThread2,
647
- useUserThreads_experimental: () => useUserThreadsSuspense_withClient(client),
1333
+ useUserThreads_experimental: useUserThreadsSuspense_experimental,
648
1334
  ...shared.suspense
649
1335
  }
650
1336
  };
651
1337
  return bundle;
652
1338
  }
653
- function useUserThreads_withClient(client) {
654
- const { loadUserThreads, store, useEnableUserThreadsPolling } = getExtrasForClient(client);
655
- _react.useEffect.call(void 0, () => {
656
- loadUserThreads();
657
- }, [loadUserThreads]);
658
- useEnableUserThreadsPolling();
659
- return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
660
- store.subscribe,
661
- store.get,
662
- store.get,
663
- selectorFor_useUserThreads,
664
- _core.shallow
665
- );
666
- }
667
- function useUserThreadsSuspense_withClient(client) {
668
- const { waitUntilUserThreadsLoaded } = getExtrasForClient(client);
669
- use(waitUntilUserThreadsLoaded());
670
- const result = useUserThreads_withClient(client);
671
- _core.assert.call(void 0, !result.error, "Did not expect error");
672
- _core.assert.call(void 0, !result.isLoading, "Did not expect loading");
673
- return result;
674
- }
675
1339
  function useInboxNotifications_withClient(client) {
676
1340
  const { loadInboxNotifications, store, useEnableInboxNotificationsPolling } = getExtrasForClient(client);
677
1341
  _react.useEffect.call(void 0, () => {
@@ -679,9 +1343,9 @@ function useInboxNotifications_withClient(client) {
679
1343
  }, [loadInboxNotifications]);
680
1344
  useEnableInboxNotificationsPolling();
681
1345
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
682
- store.subscribe,
683
- store.get,
684
- store.get,
1346
+ store.subscribeInboxNotifications,
1347
+ store.getInboxNotifications,
1348
+ store.getInboxNotifications,
685
1349
  selectorFor_useInboxNotifications,
686
1350
  _core.shallow
687
1351
  );
@@ -701,9 +1365,9 @@ function useUnreadInboxNotificationsCount_withClient(client) {
701
1365
  }, [loadInboxNotifications]);
702
1366
  useEnableInboxNotificationsPolling();
703
1367
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
704
- store.subscribe,
705
- store.get,
706
- store.get,
1368
+ store.subscribeInboxNotifications,
1369
+ store.getInboxNotifications,
1370
+ store.getInboxNotifications,
707
1371
  selectorFor_useUnreadInboxNotificationsCount,
708
1372
  _core.shallow
709
1373
  );
@@ -720,48 +1384,22 @@ function useMarkInboxNotificationAsRead_withClient(client) {
720
1384
  return _react.useCallback.call(void 0,
721
1385
  (inboxNotificationId) => {
722
1386
  const { store } = getExtrasForClient(client);
723
- const optimisticUpdateId = _core.nanoid.call(void 0, );
724
1387
  const readAt = /* @__PURE__ */ new Date();
725
- store.pushOptimisticUpdate({
1388
+ const optimisticUpdateId = store.addOptimisticUpdate({
726
1389
  type: "mark-inbox-notification-as-read",
727
- id: optimisticUpdateId,
728
1390
  inboxNotificationId,
729
1391
  readAt
730
1392
  });
731
1393
  client.markInboxNotificationAsRead(inboxNotificationId).then(
732
1394
  () => {
733
- store.set((state) => {
734
- const existingNotification = state.inboxNotifications[inboxNotificationId];
735
- if (existingNotification === void 0) {
736
- return {
737
- ...state,
738
- optimisticUpdates: state.optimisticUpdates.filter(
739
- (update) => update.id !== optimisticUpdateId
740
- )
741
- };
742
- }
743
- return {
744
- ...state,
745
- inboxNotifications: {
746
- ...state.inboxNotifications,
747
- [inboxNotificationId]: {
748
- ...existingNotification,
749
- readAt
750
- }
751
- },
752
- optimisticUpdates: state.optimisticUpdates.filter(
753
- (update) => update.id !== optimisticUpdateId
754
- )
755
- };
756
- });
1395
+ store.updateInboxNotification(
1396
+ inboxNotificationId,
1397
+ optimisticUpdateId,
1398
+ (inboxNotification) => ({ ...inboxNotification, readAt })
1399
+ );
757
1400
  },
758
1401
  () => {
759
- store.set((state) => ({
760
- ...state,
761
- optimisticUpdates: state.optimisticUpdates.filter(
762
- (update) => update.id !== optimisticUpdateId
763
- )
764
- }));
1402
+ store.removeOptimisticUpdate(optimisticUpdateId);
765
1403
  }
766
1404
  );
767
1405
  },
@@ -771,37 +1409,20 @@ function useMarkInboxNotificationAsRead_withClient(client) {
771
1409
  function useMarkAllInboxNotificationsAsRead_withClient(client) {
772
1410
  return _react.useCallback.call(void 0, () => {
773
1411
  const { store } = getExtrasForClient(client);
774
- const optimisticUpdateId = _core.nanoid.call(void 0, );
775
1412
  const readAt = /* @__PURE__ */ new Date();
776
- store.pushOptimisticUpdate({
1413
+ const optimisticUpdateId = store.addOptimisticUpdate({
777
1414
  type: "mark-all-inbox-notifications-as-read",
778
- id: optimisticUpdateId,
779
1415
  readAt
780
1416
  });
781
1417
  client.markAllInboxNotificationsAsRead().then(
782
1418
  () => {
783
- store.set((state) => ({
784
- ...state,
785
- inboxNotifications: Object.fromEntries(
786
- Array.from(Object.entries(state.inboxNotifications)).map(
787
- ([id, inboxNotification]) => [
788
- id,
789
- { ...inboxNotification, readAt }
790
- ]
791
- )
792
- ),
793
- optimisticUpdates: state.optimisticUpdates.filter(
794
- (update) => update.id !== optimisticUpdateId
795
- )
796
- }));
1419
+ store.updateAllInboxNotifications(
1420
+ optimisticUpdateId,
1421
+ (inboxNotification) => ({ ...inboxNotification, readAt })
1422
+ );
797
1423
  },
798
1424
  () => {
799
- store.set((state) => ({
800
- ...state,
801
- optimisticUpdates: state.optimisticUpdates.filter(
802
- (update) => update.id !== optimisticUpdateId
803
- )
804
- }));
1425
+ store.removeOptimisticUpdate(optimisticUpdateId);
805
1426
  }
806
1427
  );
807
1428
  }, [client]);
@@ -810,43 +1431,21 @@ function useDeleteInboxNotification_withClient(client) {
810
1431
  return _react.useCallback.call(void 0,
811
1432
  (inboxNotificationId) => {
812
1433
  const { store } = getExtrasForClient(client);
813
- const optimisticUpdateId = _core.nanoid.call(void 0, );
814
1434
  const deletedAt = /* @__PURE__ */ new Date();
815
- store.pushOptimisticUpdate({
1435
+ const optimisticUpdateId = store.addOptimisticUpdate({
816
1436
  type: "delete-inbox-notification",
817
- id: optimisticUpdateId,
818
1437
  inboxNotificationId,
819
1438
  deletedAt
820
1439
  });
821
1440
  client.deleteInboxNotification(inboxNotificationId).then(
822
1441
  () => {
823
- store.set((state) => {
824
- const existingNotification = state.inboxNotifications[inboxNotificationId];
825
- if (existingNotification === void 0) {
826
- return {
827
- ...state,
828
- optimisticUpdates: state.optimisticUpdates.filter(
829
- (update) => update.id !== optimisticUpdateId
830
- )
831
- };
832
- }
833
- const { [inboxNotificationId]: _, ...inboxNotifications } = state.inboxNotifications;
834
- return {
835
- ...state,
836
- inboxNotifications,
837
- optimisticUpdates: state.optimisticUpdates.filter(
838
- (update) => update.id !== optimisticUpdateId
839
- )
840
- };
841
- });
1442
+ store.deleteInboxNotification(
1443
+ inboxNotificationId,
1444
+ optimisticUpdateId
1445
+ );
842
1446
  },
843
1447
  () => {
844
- store.set((state) => ({
845
- ...state,
846
- optimisticUpdates: state.optimisticUpdates.filter(
847
- (update) => update.id !== optimisticUpdateId
848
- )
849
- }));
1448
+ store.removeOptimisticUpdate(optimisticUpdateId);
850
1449
  }
851
1450
  );
852
1451
  },
@@ -856,30 +1455,17 @@ function useDeleteInboxNotification_withClient(client) {
856
1455
  function useDeleteAllInboxNotifications_withClient(client) {
857
1456
  return _react.useCallback.call(void 0, () => {
858
1457
  const { store } = getExtrasForClient(client);
859
- const optimisticUpdateId = _core.nanoid.call(void 0, );
860
1458
  const deletedAt = /* @__PURE__ */ new Date();
861
- store.pushOptimisticUpdate({
1459
+ const optimisticUpdateId = store.addOptimisticUpdate({
862
1460
  type: "delete-all-inbox-notifications",
863
- id: optimisticUpdateId,
864
1461
  deletedAt
865
1462
  });
866
1463
  client.deleteAllInboxNotifications().then(
867
1464
  () => {
868
- store.set((state) => ({
869
- ...state,
870
- inboxNotifications: {},
871
- optimisticUpdates: state.optimisticUpdates.filter(
872
- (update) => update.id !== optimisticUpdateId
873
- )
874
- }));
1465
+ store.deleteAllInboxNotifications(optimisticUpdateId);
875
1466
  },
876
1467
  () => {
877
- store.set((state) => ({
878
- ...state,
879
- optimisticUpdates: state.optimisticUpdates.filter(
880
- (update) => update.id !== optimisticUpdateId
881
- )
882
- }));
1468
+ store.removeOptimisticUpdate(optimisticUpdateId);
883
1469
  }
884
1470
  );
885
1471
  }, [client]);
@@ -888,13 +1474,13 @@ function useInboxNotificationThread_withClient(client, inboxNotificationId) {
888
1474
  const { store } = getExtrasForClient(client);
889
1475
  const selector = _react.useCallback.call(void 0,
890
1476
  (state) => {
891
- const inboxNotification = _nullishCoalesce(state.inboxNotifications[inboxNotificationId], () => ( _core.raise.call(void 0, `Inbox notification with ID "${inboxNotificationId}" not found`)));
1477
+ const inboxNotification = _nullishCoalesce(state.inboxNotificationsById[inboxNotificationId], () => ( _core.raise.call(void 0, `Inbox notification with ID "${inboxNotificationId}" not found`)));
892
1478
  if (inboxNotification.kind !== "thread") {
893
1479
  _core.raise.call(void 0,
894
1480
  `Inbox notification with ID "${inboxNotificationId}" is not of kind "thread"`
895
1481
  );
896
1482
  }
897
- const thread = _nullishCoalesce(state.threads[inboxNotification.threadId], () => ( _core.raise.call(void 0,
1483
+ const thread = _nullishCoalesce(state.threadsById[inboxNotification.threadId], () => ( _core.raise.call(void 0,
898
1484
  `Thread with ID "${inboxNotification.threadId}" not found, this inbox notification might not be of kind "thread"`
899
1485
  )));
900
1486
  return thread;
@@ -902,9 +1488,9 @@ function useInboxNotificationThread_withClient(client, inboxNotificationId) {
902
1488
  [inboxNotificationId]
903
1489
  );
904
1490
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
905
- store.subscribe,
906
- store.get,
907
- store.get,
1491
+ store.subscribeInboxNotifications,
1492
+ store.getInboxNotifications,
1493
+ store.getInboxNotifications,
908
1494
  selector
909
1495
  );
910
1496
  }
@@ -1018,19 +1604,19 @@ function createSharedContext(client) {
1018
1604
  useClient: useClient2,
1019
1605
  useUser: (userId) => useUser_withClient(client, userId),
1020
1606
  useRoomInfo: (roomId) => useRoomInfo_withClient(client, roomId),
1021
- useIsInsideRoom: _useIsInsideRoom
1607
+ useIsInsideRoom
1022
1608
  },
1023
1609
  suspense: {
1024
1610
  useClient: useClient2,
1025
1611
  useUser: (userId) => useUserSuspense_withClient(client, userId),
1026
1612
  useRoomInfo: (roomId) => useRoomInfoSuspense_withClient(client, roomId),
1027
- useIsInsideRoom: _useIsInsideRoom
1613
+ useIsInsideRoom
1028
1614
  }
1029
1615
  };
1030
1616
  }
1031
1617
  function useEnsureNoLiveblocksProvider(options) {
1032
1618
  const existing = useClientOrNull();
1033
- if (!_optionalChain([options, 'optionalAccess', _4 => _4.allowNesting]) && existing !== null) {
1619
+ if (!_optionalChain([options, 'optionalAccess', _19 => _19.allowNesting]) && existing !== null) {
1034
1620
  throw new Error(
1035
1621
  "You cannot nest multiple LiveblocksProvider instances in the same React tree."
1036
1622
  );
@@ -1077,11 +1663,101 @@ function LiveblocksProvider(props) {
1077
1663
  function createLiveblocksContext(client) {
1078
1664
  return getOrCreateContextBundle(client);
1079
1665
  }
1080
- function useUserThreads_experimental() {
1081
- return useUserThreads_withClient(useClient());
1666
+ function useUserThreads_experimental(options = {
1667
+ query: {
1668
+ metadata: {}
1669
+ }
1670
+ }) {
1671
+ const queryKey = React.default.useMemo(
1672
+ () => makeUserThreadsQueryKey(options.query),
1673
+ [options]
1674
+ );
1675
+ const client = useClient();
1676
+ const { store, incrementUserThreadsQuerySubscribers, getUserThreads } = getExtrasForClient(client);
1677
+ _react.useEffect.call(void 0, () => {
1678
+ void getUserThreads(queryKey, options);
1679
+ return incrementUserThreadsQuerySubscribers(queryKey);
1680
+ }, [queryKey, incrementUserThreadsQuerySubscribers, getUserThreads, options]);
1681
+ const selector = _react.useCallback.call(void 0,
1682
+ (state) => {
1683
+ const query = state.queries[queryKey];
1684
+ if (query === void 0 || query.isLoading) {
1685
+ return {
1686
+ isLoading: true
1687
+ };
1688
+ }
1689
+ if (query.error !== void 0) {
1690
+ return {
1691
+ threads: [],
1692
+ error: query.error,
1693
+ isLoading: false
1694
+ };
1695
+ }
1696
+ return {
1697
+ threads: selectThreads(state, {
1698
+ roomId: null,
1699
+ // Do _not_ filter by roomId
1700
+ query: options.query,
1701
+ orderBy: "last-update"
1702
+ }),
1703
+ isLoading: false
1704
+ };
1705
+ },
1706
+ [queryKey, options]
1707
+ );
1708
+ return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1709
+ store.subscribeThreads,
1710
+ store.getThreads,
1711
+ store.getThreads,
1712
+ selector,
1713
+ shallow2
1714
+ // NOTE: Using 2-level-deep shallow check here, because the result of selectThreads() is not stable!
1715
+ );
1082
1716
  }
1083
- function useUserThreadsSuspense_experimental() {
1084
- return useUserThreadsSuspense_withClient(useClient());
1717
+ function useUserThreadsSuspense_experimental(options = {
1718
+ query: {
1719
+ metadata: {}
1720
+ }
1721
+ }) {
1722
+ const queryKey = React.default.useMemo(
1723
+ () => makeUserThreadsQueryKey(options.query),
1724
+ [options]
1725
+ );
1726
+ const client = useClient();
1727
+ const { store, getUserThreads } = getExtrasForClient(client);
1728
+ React.default.useEffect(() => {
1729
+ const { incrementUserThreadsQuerySubscribers } = getExtrasForClient(client);
1730
+ return incrementUserThreadsQuerySubscribers(queryKey);
1731
+ }, [client, queryKey]);
1732
+ const query = store.getThreads().queries[queryKey];
1733
+ if (query === void 0 || query.isLoading) {
1734
+ throw getUserThreads(queryKey, options);
1735
+ }
1736
+ if (query.error) {
1737
+ throw query.error;
1738
+ }
1739
+ const selector = _react.useCallback.call(void 0,
1740
+ (state) => {
1741
+ return {
1742
+ threads: selectThreads(state, {
1743
+ roomId: null,
1744
+ // Do _not_ filter by roomId
1745
+ query: options.query,
1746
+ orderBy: "last-update"
1747
+ }),
1748
+ isLoading: false
1749
+ };
1750
+ },
1751
+ [options]
1752
+ );
1753
+ return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1754
+ store.subscribeThreads,
1755
+ store.getThreads,
1756
+ store.getThreads,
1757
+ selector,
1758
+ shallow2
1759
+ // NOTE: Using 2-level-deep shallow check here, because the result of selectThreads() is not stable!
1760
+ );
1085
1761
  }
1086
1762
  function useInboxNotifications() {
1087
1763
  return useInboxNotifications_withClient(useClient());
@@ -1132,6 +1808,125 @@ var _useUser = useUser;
1132
1808
  var _useUserSuspense = useUserSuspense;
1133
1809
  var _useUserThreads_experimental = useUserThreads_experimental;
1134
1810
  var _useUserThreadsSuspense_experimental = useUserThreadsSuspense_experimental;
1811
+ var makeUserThreadsQueryKey = (options) => `${USER_THREADS_QUERY}:${_core.stringify.call(void 0, options)}`;
1812
+
1813
+ // src/types/errors.ts
1814
+ var CreateThreadError = class extends Error {
1815
+ constructor(cause, context) {
1816
+ super("Create thread failed.");
1817
+ this.cause = cause;
1818
+ this.context = context;
1819
+ this.name = "CreateThreadError";
1820
+ }
1821
+ };
1822
+ var DeleteThreadError = class extends Error {
1823
+ constructor(cause, context) {
1824
+ super("Delete thread failed.");
1825
+ this.cause = cause;
1826
+ this.context = context;
1827
+ this.name = "DeleteThreadError";
1828
+ }
1829
+ };
1830
+ var EditThreadMetadataError = class extends Error {
1831
+ constructor(cause, context) {
1832
+ super("Edit thread metadata failed.");
1833
+ this.cause = cause;
1834
+ this.context = context;
1835
+ this.name = "EditThreadMetadataError";
1836
+ }
1837
+ };
1838
+ var MarkThreadAsResolvedError = class extends Error {
1839
+ constructor(cause, context) {
1840
+ super("Mark thread as resolved failed.");
1841
+ this.cause = cause;
1842
+ this.context = context;
1843
+ this.name = "MarkThreadAsResolvedError";
1844
+ }
1845
+ };
1846
+ var MarkThreadAsUnresolvedError = class extends Error {
1847
+ constructor(cause, context) {
1848
+ super("Mark thread as unresolved failed.");
1849
+ this.cause = cause;
1850
+ this.context = context;
1851
+ this.name = "MarkThreadAsUnresolvedError";
1852
+ }
1853
+ };
1854
+ var CreateCommentError = class extends Error {
1855
+ constructor(cause, context) {
1856
+ super("Create comment failed.");
1857
+ this.cause = cause;
1858
+ this.context = context;
1859
+ this.name = "CreateCommentError";
1860
+ }
1861
+ };
1862
+ var EditCommentError = class extends Error {
1863
+ constructor(cause, context) {
1864
+ super("Edit comment failed.");
1865
+ this.cause = cause;
1866
+ this.context = context;
1867
+ this.name = "EditCommentError";
1868
+ }
1869
+ };
1870
+ var DeleteCommentError = class extends Error {
1871
+ constructor(cause, context) {
1872
+ super("Delete comment failed.");
1873
+ this.cause = cause;
1874
+ this.context = context;
1875
+ this.name = "DeleteCommentError";
1876
+ }
1877
+ };
1878
+ var AddReactionError = class extends Error {
1879
+ constructor(cause, context) {
1880
+ super("Add reaction failed.");
1881
+ this.cause = cause;
1882
+ this.context = context;
1883
+ this.name = "AddReactionError";
1884
+ }
1885
+ };
1886
+ var RemoveReactionError = class extends Error {
1887
+ constructor(cause, context) {
1888
+ super("Remove reaction failed.");
1889
+ this.cause = cause;
1890
+ this.context = context;
1891
+ this.name = "RemoveReactionError";
1892
+ }
1893
+ };
1894
+ var MarkInboxNotificationAsReadError = class extends Error {
1895
+ constructor(cause, context) {
1896
+ super("Mark inbox notification as read failed.");
1897
+ this.cause = cause;
1898
+ this.context = context;
1899
+ this.name = "MarkInboxNotificationAsReadError";
1900
+ }
1901
+ };
1902
+ var UpdateNotificationSettingsError = class extends Error {
1903
+ constructor(cause, context) {
1904
+ super("Update notification settings failed.");
1905
+ this.cause = cause;
1906
+ this.context = context;
1907
+ this.name = "UpdateNotificationSettingsError";
1908
+ }
1909
+ };
1910
+
1911
+ // src/room.tsx
1912
+ var _client = require('@liveblocks/client');
1913
+
1914
+
1915
+
1916
+
1917
+
1918
+
1919
+
1920
+
1921
+
1922
+
1923
+
1924
+
1925
+
1926
+
1927
+
1928
+
1929
+
1135
1930
 
1136
1931
  // src/use-scroll-to-comment-on-load-effect.ts
1137
1932
 
@@ -1153,7 +1948,7 @@ function handleScrollToCommentOnLoad(shouldScrollOnLoad, state) {
1153
1948
  comment.scrollIntoView();
1154
1949
  }
1155
1950
  function useScrollToCommentOnLoadEffect(shouldScrollOnLoad, state) {
1156
- React3.useEffect(
1951
+ React4.useEffect(
1157
1952
  () => {
1158
1953
  handleScrollToCommentOnLoad(shouldScrollOnLoad, state);
1159
1954
  },
@@ -1196,6 +1991,10 @@ function alwaysNull() {
1196
1991
  function selectorFor_useOthersConnectionIds(others) {
1197
1992
  return others.map((user) => user.connectionId);
1198
1993
  }
1994
+ function selectNotificationSettings(roomId, state) {
1995
+ const notificationSettings = state.notificationSettingsByRoomId;
1996
+ return _core.nn.call(void 0, notificationSettings[roomId]);
1997
+ }
1199
1998
  function makeMutationContext(room) {
1200
1999
  const cannotUseUntil = "This mutation cannot be used until";
1201
2000
  const needsPresence = `${cannotUseUntil} connected to the Liveblocks room`;
@@ -1235,7 +2034,7 @@ function getCurrentUserId(room) {
1235
2034
  }
1236
2035
  function handleApiError(err) {
1237
2036
  const message = `Request failed with status ${err.status}: ${err.message}`;
1238
- if (_optionalChain([err, 'access', _5 => _5.details, 'optionalAccess', _6 => _6.error]) === "FORBIDDEN") {
2037
+ if (_optionalChain([err, 'access', _20 => _20.details, 'optionalAccess', _21 => _21.error]) === "FORBIDDEN") {
1239
2038
  const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
1240
2039
  _core.console.error(detailedMessage);
1241
2040
  }
@@ -1260,7 +2059,7 @@ function getExtrasForClient2(client) {
1260
2059
  return extras;
1261
2060
  }
1262
2061
  function makeExtrasForClient2(client) {
1263
- const store = client[_core.kInternal].cacheStore;
2062
+ const store = getUmbrellaStoreForClient(client);
1264
2063
  const DEFAULT_DEDUPING_INTERVAL = 2e3;
1265
2064
  const lastRequestedAtByRoom = /* @__PURE__ */ new Map();
1266
2065
  const requestsByQuery = /* @__PURE__ */ new Map();
@@ -1329,9 +2128,7 @@ function makeExtrasForClient2(client) {
1329
2128
  if (existingRequest !== void 0) return existingRequest;
1330
2129
  const request = room[_core.kInternal].listTextVersions();
1331
2130
  requestsByQuery.set(queryKey, request);
1332
- store.setQueryState(queryKey, {
1333
- isLoading: true
1334
- });
2131
+ store.setQueryLoading(queryKey);
1335
2132
  try {
1336
2133
  const result = await request;
1337
2134
  const data = await result.json();
@@ -1350,10 +2147,7 @@ function makeExtrasForClient2(client) {
1350
2147
  retryCount: retryCount + 1
1351
2148
  });
1352
2149
  }, retryCount);
1353
- store.setQueryState(queryKey, {
1354
- isLoading: false,
1355
- error: err
1356
- });
2150
+ store.setQueryError(queryKey, err);
1357
2151
  }
1358
2152
  return;
1359
2153
  }
@@ -1362,9 +2156,7 @@ function makeExtrasForClient2(client) {
1362
2156
  if (existingRequest !== void 0) return existingRequest;
1363
2157
  const request = room.getThreads(options);
1364
2158
  requestsByQuery.set(queryKey, request);
1365
- store.setQueryState(queryKey, {
1366
- isLoading: true
1367
- });
2159
+ store.setQueryLoading(queryKey);
1368
2160
  try {
1369
2161
  const result = await request;
1370
2162
  store.updateThreadsAndNotifications(
@@ -1387,10 +2179,7 @@ function makeExtrasForClient2(client) {
1387
2179
  retryCount: retryCount + 1
1388
2180
  });
1389
2181
  }, retryCount);
1390
- store.setQueryState(queryKey, {
1391
- isLoading: false,
1392
- error: err
1393
- });
2182
+ store.setQueryError(queryKey, err);
1394
2183
  }
1395
2184
  return;
1396
2185
  }
@@ -1400,9 +2189,7 @@ function makeExtrasForClient2(client) {
1400
2189
  try {
1401
2190
  const request = room.getNotificationSettings();
1402
2191
  requestsByQuery.set(queryKey, request);
1403
- store.setQueryState(queryKey, {
1404
- isLoading: true
1405
- });
2192
+ store.setQueryLoading(queryKey);
1406
2193
  const settings = await request;
1407
2194
  store.updateRoomInboxNotificationSettings(room.id, settings, queryKey);
1408
2195
  } catch (err) {
@@ -1412,21 +2199,13 @@ function makeExtrasForClient2(client) {
1412
2199
  retryCount: retryCount + 1
1413
2200
  });
1414
2201
  }, retryCount);
1415
- store.setQueryState(queryKey, {
1416
- isLoading: false,
1417
- error: err
1418
- });
2202
+ store.setQueryError(queryKey, err);
1419
2203
  }
1420
2204
  return;
1421
2205
  }
1422
2206
  const commentsErrorEventSource = _core.makeEventSource.call(void 0, );
1423
2207
  function onMutationFailure(innerError, optimisticUpdateId, createPublicError) {
1424
- store.set((state) => ({
1425
- ...state,
1426
- optimisticUpdates: state.optimisticUpdates.filter(
1427
- (update) => update.id !== optimisticUpdateId
1428
- )
1429
- }));
2208
+ store.removeOptimisticUpdate(optimisticUpdateId);
1430
2209
  if (innerError instanceof _core.CommentsApiError) {
1431
2210
  const error = handleApiError(innerError);
1432
2211
  commentsErrorEventSource.notify(createPublicError(error));
@@ -1449,10 +2228,9 @@ function makeExtrasForClient2(client) {
1449
2228
  onMutationFailure
1450
2229
  };
1451
2230
  }
1452
- var RoomContext = React4.createContext(null);
1453
2231
  function makeRoomContextBundle(client) {
1454
2232
  function RoomProvider_withImplicitLiveblocksProvider(props) {
1455
- return /* @__PURE__ */ React4.createElement(LiveblocksProviderWithClient, { client, allowNesting: true }, /* @__PURE__ */ React4.createElement(RoomProvider, { ...props }));
2233
+ return /* @__PURE__ */ React5.createElement(LiveblocksProviderWithClient, { client, allowNesting: true }, /* @__PURE__ */ React5.createElement(RoomProvider, { ...props }));
1456
2234
  }
1457
2235
  const shared = createSharedContext(client);
1458
2236
  const bundle = {
@@ -1554,10 +2332,10 @@ function makeRoomContextBundle(client) {
1554
2332
  }
1555
2333
  function RoomProvider(props) {
1556
2334
  const client = useClient();
1557
- const [cache] = React4.useState(
2335
+ const [cache] = React5.useState(
1558
2336
  () => /* @__PURE__ */ new Map()
1559
2337
  );
1560
- const stableEnterRoom = React4.useCallback(
2338
+ const stableEnterRoom = React5.useCallback(
1561
2339
  (roomId, options) => {
1562
2340
  const cached = cache.get(roomId);
1563
2341
  if (cached) return cached;
@@ -1572,7 +2350,7 @@ function RoomProvider(props) {
1572
2350
  },
1573
2351
  [client, cache]
1574
2352
  );
1575
- return /* @__PURE__ */ React4.createElement(
2353
+ return /* @__PURE__ */ React5.createElement(
1576
2354
  RoomProviderInner,
1577
2355
  {
1578
2356
  ...props,
@@ -1589,10 +2367,10 @@ function RoomProviderInner(props) {
1589
2367
  "RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required"
1590
2368
  );
1591
2369
  }
1592
- if (typeof roomId !== "string") {
2370
+ if (!isString(roomId)) {
1593
2371
  throw new Error("RoomProvider id property should be a string.");
1594
2372
  }
1595
- const majorReactVersion = parseInt(React4.version) || 1;
2373
+ const majorReactVersion = parseInt(React5.version) || 1;
1596
2374
  const oldReactVersion = majorReactVersion < 18;
1597
2375
  _core.errorIf.call(void 0,
1598
2376
  oldReactVersion && props.unstable_batchedUpdates === void 0,
@@ -1609,27 +2387,27 @@ function RoomProviderInner(props) {
1609
2387
  unstable_batchedUpdates: props.unstable_batchedUpdates,
1610
2388
  autoConnect: _nullishCoalesce(props.autoConnect, () => ( typeof window !== "undefined"))
1611
2389
  });
1612
- const [{ room }, setRoomLeavePair] = React4.useState(
2390
+ const [{ room }, setRoomLeavePair] = React5.useState(
1613
2391
  () => stableEnterRoom(roomId, {
1614
2392
  ...frozenProps,
1615
2393
  autoConnect: false
1616
2394
  // Deliberately using false here on the first render, see below
1617
2395
  })
1618
2396
  );
1619
- React4.useEffect(() => {
2397
+ React5.useEffect(() => {
1620
2398
  const { store } = getExtrasForClient2(client);
1621
2399
  async function handleCommentEvent(message) {
1622
2400
  if (message.type === _core.ServerMsgCode.THREAD_DELETED) {
1623
- store.deleteThread(message.threadId);
2401
+ store.deleteThread(message.threadId, null);
1624
2402
  return;
1625
2403
  }
1626
2404
  const info = await room.getThread(message.threadId);
1627
2405
  if (!info.thread) {
1628
- store.deleteThread(message.threadId);
2406
+ store.deleteThread(message.threadId, null);
1629
2407
  return;
1630
2408
  }
1631
2409
  const { thread, inboxNotification } = info;
1632
- const existingThread = store.get().threads[message.threadId];
2410
+ const existingThread = store.getThreads().threadsById[message.threadId];
1633
2411
  switch (message.type) {
1634
2412
  case _core.ServerMsgCode.COMMENT_EDITED:
1635
2413
  case _core.ServerMsgCode.THREAD_METADATA_UPDATED:
@@ -1651,11 +2429,11 @@ function RoomProviderInner(props) {
1651
2429
  (message) => void handleCommentEvent(message)
1652
2430
  );
1653
2431
  }, [client, room]);
1654
- React4.useEffect(() => {
2432
+ React5.useEffect(() => {
1655
2433
  const { getThreadsUpdates } = getExtrasForClient2(client);
1656
2434
  void getThreadsUpdates(room.id);
1657
2435
  }, [client, room.id]);
1658
- React4.useEffect(() => {
2436
+ React5.useEffect(() => {
1659
2437
  function handleIsOnline() {
1660
2438
  const { getThreadsUpdates } = getExtrasForClient2(client);
1661
2439
  void getThreadsUpdates(room.id);
@@ -1665,7 +2443,7 @@ function RoomProviderInner(props) {
1665
2443
  window.removeEventListener("online", handleIsOnline);
1666
2444
  };
1667
2445
  }, [client, room.id]);
1668
- React4.useEffect(() => {
2446
+ React5.useEffect(() => {
1669
2447
  const pair = stableEnterRoom(roomId, frozenProps);
1670
2448
  setRoomLeavePair(pair);
1671
2449
  const { room: room2, leave } = pair;
@@ -1676,7 +2454,7 @@ function RoomProviderInner(props) {
1676
2454
  leave();
1677
2455
  };
1678
2456
  }, [roomId, frozenProps, stableEnterRoom]);
1679
- return /* @__PURE__ */ React4.createElement(RoomContext.Provider, { value: room }, props.children);
2457
+ return /* @__PURE__ */ React5.createElement(RoomContext.Provider, { value: room }, props.children);
1680
2458
  }
1681
2459
  function useRoom() {
1682
2460
  const room = useRoomOrNull();
@@ -1685,10 +2463,6 @@ function useRoom() {
1685
2463
  }
1686
2464
  return room;
1687
2465
  }
1688
- function useIsInsideRoom() {
1689
- const room = useRoomOrNull();
1690
- return room !== null;
1691
- }
1692
2466
  function useStatus() {
1693
2467
  const room = useRoom();
1694
2468
  const subscribe = room.events.status.subscribe;
@@ -1697,7 +2471,7 @@ function useStatus() {
1697
2471
  return useSyncExternalStore2(subscribe, getSnapshot, getServerSnapshot);
1698
2472
  }
1699
2473
  function useStorageStatus(options) {
1700
- const smooth = useInitial(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _7 => _7.smooth]), () => ( false)));
2474
+ const smooth = useInitial(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _22 => _22.smooth]), () => ( false)));
1701
2475
  if (smooth) {
1702
2476
  return useStorageStatusSmooth();
1703
2477
  } else {
@@ -1713,9 +2487,9 @@ function useStorageStatusImmediate() {
1713
2487
  }
1714
2488
  function useStorageStatusSmooth() {
1715
2489
  const room = useRoom();
1716
- const [status, setStatus] = React4.useState(room.getStorageStatus);
2490
+ const [status, setStatus] = React5.useState(room.getStorageStatus);
1717
2491
  const oldStatus = useLatest(room.getStorageStatus());
1718
- React4.useEffect(() => {
2492
+ React5.useEffect(() => {
1719
2493
  let timeoutId;
1720
2494
  const unsub = room.events.storageStatus.subscribe((newStatus) => {
1721
2495
  if (oldStatus.current === "synchronizing" && newStatus === "synchronized") {
@@ -1737,7 +2511,7 @@ function useBatch() {
1737
2511
  }
1738
2512
  function useBroadcastEvent() {
1739
2513
  const room = useRoom();
1740
- return React4.useCallback(
2514
+ return React5.useCallback(
1741
2515
  (event, options = { shouldQueueEventIfNotReady: false }) => {
1742
2516
  room.broadcastEvent(event, options);
1743
2517
  },
@@ -1747,7 +2521,7 @@ function useBroadcastEvent() {
1747
2521
  function useOthersListener(callback) {
1748
2522
  const room = useRoom();
1749
2523
  const savedCallback = useLatest(callback);
1750
- React4.useEffect(
2524
+ React5.useEffect(
1751
2525
  () => room.events.others.subscribe((event) => savedCallback.current(event)),
1752
2526
  [room, savedCallback]
1753
2527
  );
@@ -1755,7 +2529,7 @@ function useOthersListener(callback) {
1755
2529
  function useLostConnectionListener(callback) {
1756
2530
  const room = useRoom();
1757
2531
  const savedCallback = useLatest(callback);
1758
- React4.useEffect(
2532
+ React5.useEffect(
1759
2533
  () => room.events.lostConnection.subscribe(
1760
2534
  (event) => savedCallback.current(event)
1761
2535
  ),
@@ -1765,7 +2539,7 @@ function useLostConnectionListener(callback) {
1765
2539
  function useErrorListener(callback) {
1766
2540
  const room = useRoom();
1767
2541
  const savedCallback = useLatest(callback);
1768
- React4.useEffect(
2542
+ React5.useEffect(
1769
2543
  () => room.events.error.subscribe((e) => savedCallback.current(e)),
1770
2544
  [room, savedCallback]
1771
2545
  );
@@ -1773,7 +2547,7 @@ function useErrorListener(callback) {
1773
2547
  function useEventListener(callback) {
1774
2548
  const room = useRoom();
1775
2549
  const savedCallback = useLatest(callback);
1776
- React4.useEffect(() => {
2550
+ React5.useEffect(() => {
1777
2551
  const listener = (eventData) => {
1778
2552
  savedCallback.current(eventData);
1779
2553
  };
@@ -1806,7 +2580,7 @@ function useSelf(maybeSelector, isEqual) {
1806
2580
  const subscribe = room.events.self.subscribe;
1807
2581
  const getSnapshot = room.getSelf;
1808
2582
  const selector = _nullishCoalesce(maybeSelector, () => ( identity));
1809
- const wrappedSelector = React4.useCallback(
2583
+ const wrappedSelector = React5.useCallback(
1810
2584
  (me) => me !== null ? selector(me) : null,
1811
2585
  [selector]
1812
2586
  );
@@ -1844,11 +2618,11 @@ function useOthers(selector, isEqual) {
1844
2618
  );
1845
2619
  }
1846
2620
  function useOthersMapped(itemSelector, itemIsEqual) {
1847
- const wrappedSelector = React4.useCallback(
2621
+ const wrappedSelector = React5.useCallback(
1848
2622
  (others) => others.map((other) => [other.connectionId, itemSelector(other)]),
1849
2623
  [itemSelector]
1850
2624
  );
1851
- const wrappedIsEqual = React4.useCallback(
2625
+ const wrappedIsEqual = React5.useCallback(
1852
2626
  (a, b) => {
1853
2627
  const eq = _nullishCoalesce(itemIsEqual, () => ( Object.is));
1854
2628
  return a.length === b.length && a.every((atuple, index) => {
@@ -1865,14 +2639,14 @@ function useOthersConnectionIds() {
1865
2639
  }
1866
2640
  var NOT_FOUND = Symbol();
1867
2641
  function useOther(connectionId, selector, isEqual) {
1868
- const wrappedSelector = React4.useCallback(
2642
+ const wrappedSelector = React5.useCallback(
1869
2643
  (others) => {
1870
2644
  const other2 = others.find((other3) => other3.connectionId === connectionId);
1871
2645
  return other2 !== void 0 ? selector(other2) : NOT_FOUND;
1872
2646
  },
1873
2647
  [connectionId, selector]
1874
2648
  );
1875
- const wrappedIsEqual = React4.useCallback(
2649
+ const wrappedIsEqual = React5.useCallback(
1876
2650
  (prev, curr) => {
1877
2651
  if (prev === NOT_FOUND || curr === NOT_FOUND) {
1878
2652
  return prev === curr;
@@ -1903,15 +2677,15 @@ function useStorageRoot() {
1903
2677
  function useStorage(selector, isEqual) {
1904
2678
  const room = useRoom();
1905
2679
  const rootOrNull = useMutableStorageRoot();
1906
- const wrappedSelector = React4.useCallback(
2680
+ const wrappedSelector = React5.useCallback(
1907
2681
  (rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
1908
2682
  [selector]
1909
2683
  );
1910
- const subscribe = React4.useCallback(
2684
+ const subscribe = React5.useCallback(
1911
2685
  (onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop2,
1912
2686
  [room, rootOrNull]
1913
2687
  );
1914
- const getSnapshot = React4.useCallback(() => {
2688
+ const getSnapshot = React5.useCallback(() => {
1915
2689
  if (rootOrNull === null) {
1916
2690
  return null;
1917
2691
  } else {
@@ -1931,7 +2705,7 @@ function useStorage(selector, isEqual) {
1931
2705
  }
1932
2706
  function useMutation(callback, deps) {
1933
2707
  const room = useRoom();
1934
- return React4.useMemo(
2708
+ return React5.useMemo(
1935
2709
  () => {
1936
2710
  return (...args) => (
1937
2711
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
@@ -1956,16 +2730,16 @@ function useThreads(options = {
1956
2730
  const { scrollOnLoad = true } = options;
1957
2731
  const client = useClient();
1958
2732
  const room = useRoom();
1959
- const queryKey = React4.useMemo(
2733
+ const queryKey = React5.useMemo(
1960
2734
  () => generateQueryKey(room.id, options.query),
1961
2735
  [room, options]
1962
2736
  );
1963
2737
  const { store, getThreadsAndInboxNotifications, incrementQuerySubscribers } = getExtrasForClient2(client);
1964
- React4.useEffect(() => {
2738
+ React5.useEffect(() => {
1965
2739
  void getThreadsAndInboxNotifications(room, queryKey, options);
1966
2740
  return incrementQuerySubscribers(queryKey);
1967
2741
  }, [room, queryKey]);
1968
- const selector = React4.useCallback(
2742
+ const selector = React5.useCallback(
1969
2743
  (state2) => {
1970
2744
  const query = state2.queries[queryKey];
1971
2745
  if (query === void 0 || query.isLoading) {
@@ -1974,7 +2748,11 @@ function useThreads(options = {
1974
2748
  };
1975
2749
  }
1976
2750
  return {
1977
- threads: selectedThreads(room.id, state2, options),
2751
+ threads: selectThreads(state2, {
2752
+ roomId: room.id,
2753
+ query: options.query,
2754
+ orderBy: "age"
2755
+ }),
1978
2756
  isLoading: false,
1979
2757
  error: query.error
1980
2758
  };
@@ -1983,9 +2761,9 @@ function useThreads(options = {
1983
2761
  // eslint-disable-line react-hooks/exhaustive-deps
1984
2762
  );
1985
2763
  const state = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1986
- store.subscribe,
1987
- store.get,
1988
- store.get,
2764
+ store.subscribeThreads,
2765
+ store.getThreads,
2766
+ store.getThreads,
1989
2767
  selector
1990
2768
  );
1991
2769
  useScrollToCommentOnLoadEffect(scrollOnLoad, state);
@@ -1995,14 +2773,14 @@ function useCommentsErrorListener(callback) {
1995
2773
  const client = useClient();
1996
2774
  const savedCallback = useLatest(callback);
1997
2775
  const { commentsErrorEventSource } = getExtrasForClient2(client);
1998
- React4.useEffect(() => {
2776
+ React5.useEffect(() => {
1999
2777
  return commentsErrorEventSource.subscribe(savedCallback.current);
2000
2778
  }, [savedCallback, commentsErrorEventSource]);
2001
2779
  }
2002
2780
  function useCreateThread() {
2003
2781
  const client = useClient();
2004
2782
  const room = useRoom();
2005
- return React4.useCallback(
2783
+ return React5.useCallback(
2006
2784
  (options) => {
2007
2785
  const body = options.body;
2008
2786
  const metadata = _nullishCoalesce(options.metadata, () => ( {}));
@@ -2029,26 +2807,15 @@ function useCreateThread() {
2029
2807
  comments: [newComment],
2030
2808
  resolved: false
2031
2809
  };
2032
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2033
2810
  const { store, onMutationFailure } = getExtrasForClient2(client);
2034
- store.pushOptimisticUpdate({
2811
+ const optimisticUpdateId = store.addOptimisticUpdate({
2035
2812
  type: "create-thread",
2036
2813
  thread: newThread,
2037
- id: optimisticUpdateId,
2038
2814
  roomId: room.id
2039
2815
  });
2040
2816
  room.createThread({ threadId, commentId, body, metadata }).then(
2041
2817
  (thread) => {
2042
- store.set((state) => ({
2043
- ...state,
2044
- threads: {
2045
- ...state.threads,
2046
- [threadId]: thread
2047
- },
2048
- optimisticUpdates: state.optimisticUpdates.filter(
2049
- (update) => update.id !== optimisticUpdateId
2050
- )
2051
- }));
2818
+ store.createThread(optimisticUpdateId, thread);
2052
2819
  },
2053
2820
  (err) => onMutationFailure(
2054
2821
  err,
@@ -2070,44 +2837,23 @@ function useCreateThread() {
2070
2837
  function useDeleteThread() {
2071
2838
  const client = useClient();
2072
2839
  const room = useRoom();
2073
- return React4.useCallback(
2840
+ return React5.useCallback(
2074
2841
  (threadId) => {
2075
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2076
2842
  const { store, onMutationFailure } = getExtrasForClient2(client);
2077
- const thread = store.get().threads[threadId];
2843
+ const thread = store.getThreads().threadsById[threadId];
2078
2844
  const userId = getCurrentUserId(room);
2079
- if (_optionalChain([thread, 'optionalAccess', _8 => _8.comments, 'optionalAccess', _9 => _9[0], 'optionalAccess', _10 => _10.userId]) !== userId) {
2845
+ if (_optionalChain([thread, 'optionalAccess', _23 => _23.comments, 'optionalAccess', _24 => _24[0], 'optionalAccess', _25 => _25.userId]) !== userId) {
2080
2846
  throw new Error("Only the thread creator can delete the thread");
2081
2847
  }
2082
- store.pushOptimisticUpdate({
2848
+ const optimisticUpdateId = store.addOptimisticUpdate({
2083
2849
  type: "delete-thread",
2084
- id: optimisticUpdateId,
2085
2850
  roomId: room.id,
2086
2851
  threadId,
2087
2852
  deletedAt: /* @__PURE__ */ new Date()
2088
2853
  });
2089
2854
  room.deleteThread(threadId).then(
2090
2855
  () => {
2091
- store.set((state) => {
2092
- const existingThread = state.threads[threadId];
2093
- if (existingThread === void 0) {
2094
- return state;
2095
- }
2096
- return {
2097
- ...state,
2098
- threads: {
2099
- ...state.threads,
2100
- [threadId]: {
2101
- ...existingThread,
2102
- updatedAt: /* @__PURE__ */ new Date(),
2103
- deletedAt: /* @__PURE__ */ new Date()
2104
- }
2105
- },
2106
- optimisticUpdates: state.optimisticUpdates.filter(
2107
- (update) => update.id !== optimisticUpdateId
2108
- )
2109
- };
2110
- });
2856
+ store.deleteThread(threadId, optimisticUpdateId);
2111
2857
  },
2112
2858
  (err) => onMutationFailure(
2113
2859
  err,
@@ -2122,7 +2868,7 @@ function useDeleteThread() {
2122
2868
  function useEditThreadMetadata() {
2123
2869
  const client = useClient();
2124
2870
  const room = useRoom();
2125
- return React4.useCallback(
2871
+ return React5.useCallback(
2126
2872
  (options) => {
2127
2873
  if (!options.metadata) {
2128
2874
  return;
@@ -2130,53 +2876,23 @@ function useEditThreadMetadata() {
2130
2876
  const threadId = options.threadId;
2131
2877
  const metadata = options.metadata;
2132
2878
  const updatedAt = /* @__PURE__ */ new Date();
2133
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2134
2879
  const { store, onMutationFailure } = getExtrasForClient2(client);
2135
- store.pushOptimisticUpdate({
2880
+ const optimisticUpdateId = store.addOptimisticUpdate({
2136
2881
  type: "edit-thread-metadata",
2137
2882
  metadata,
2138
- id: optimisticUpdateId,
2139
2883
  threadId,
2140
2884
  updatedAt
2141
2885
  });
2142
- room.editThreadMetadata({ metadata, threadId }).then(
2143
- (metadata2) => {
2144
- store.set((state) => {
2145
- const existingThread = state.threads[threadId];
2146
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2147
- (update) => update.id !== optimisticUpdateId
2148
- );
2149
- if (existingThread === void 0) {
2150
- return {
2151
- ...state,
2152
- optimisticUpdates: updatedOptimisticUpdates
2153
- };
2154
- }
2155
- if (existingThread.deletedAt !== void 0) {
2156
- return {
2157
- ...state,
2158
- optimisticUpdates: updatedOptimisticUpdates
2159
- };
2160
- }
2161
- if (existingThread.updatedAt && existingThread.updatedAt > updatedAt) {
2162
- return {
2163
- ...state,
2164
- optimisticUpdates: updatedOptimisticUpdates
2165
- };
2166
- }
2167
- return {
2168
- ...state,
2169
- threads: {
2170
- ...state.threads,
2171
- [threadId]: {
2172
- ...existingThread,
2173
- metadata: metadata2
2174
- }
2175
- },
2176
- optimisticUpdates: updatedOptimisticUpdates
2177
- };
2178
- });
2179
- },
2886
+ room.editThreadMetadata({ threadId, metadata }).then(
2887
+ (metadata2) => (
2888
+ // Replace the optimistic update by the real thing
2889
+ store.patchThread(
2890
+ threadId,
2891
+ optimisticUpdateId,
2892
+ { metadata: metadata2 },
2893
+ updatedAt
2894
+ )
2895
+ ),
2180
2896
  (err) => onMutationFailure(
2181
2897
  err,
2182
2898
  optimisticUpdateId,
@@ -2194,7 +2910,7 @@ function useEditThreadMetadata() {
2194
2910
  function useCreateComment() {
2195
2911
  const client = useClient();
2196
2912
  const room = useRoom();
2197
- return React4.useCallback(
2913
+ return React5.useCallback(
2198
2914
  ({ threadId, body }) => {
2199
2915
  const commentId = _core.createCommentId.call(void 0, );
2200
2916
  const createdAt = /* @__PURE__ */ new Date();
@@ -2208,50 +2924,14 @@ function useCreateComment() {
2208
2924
  body,
2209
2925
  reactions: []
2210
2926
  };
2211
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2212
2927
  const { store, onMutationFailure } = getExtrasForClient2(client);
2213
- store.pushOptimisticUpdate({
2928
+ const optimisticUpdateId = store.addOptimisticUpdate({
2214
2929
  type: "create-comment",
2215
- comment,
2216
- id: optimisticUpdateId
2930
+ comment
2217
2931
  });
2218
2932
  room.createComment({ threadId, commentId, body }).then(
2219
2933
  (newComment) => {
2220
- store.set((state) => {
2221
- const existingThread = state.threads[threadId];
2222
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2223
- (update) => update.id !== optimisticUpdateId
2224
- );
2225
- if (existingThread === void 0) {
2226
- return {
2227
- ...state,
2228
- optimisticUpdates: updatedOptimisticUpdates
2229
- };
2230
- }
2231
- const inboxNotification = Object.values(
2232
- state.inboxNotifications
2233
- ).find(
2234
- (notification) => notification.kind === "thread" && notification.threadId === threadId
2235
- );
2236
- const updatedInboxNotifications = inboxNotification !== void 0 ? {
2237
- ...state.inboxNotifications,
2238
- [inboxNotification.id]: {
2239
- ...inboxNotification,
2240
- notifiedAt: newComment.createdAt,
2241
- readAt: newComment.createdAt
2242
- }
2243
- } : state.inboxNotifications;
2244
- return {
2245
- ...state,
2246
- threads: {
2247
- ...state.threads,
2248
- [threadId]: _core.upsertComment.call(void 0, existingThread, newComment)
2249
- // Upsert the new comment into the thread comments list (if applicable)
2250
- },
2251
- inboxNotifications: updatedInboxNotifications,
2252
- optimisticUpdates: updatedOptimisticUpdates
2253
- };
2254
- });
2934
+ store.createComment(newComment, optimisticUpdateId);
2255
2935
  },
2256
2936
  (err) => onMutationFailure(
2257
2937
  err,
@@ -2272,12 +2952,11 @@ function useCreateComment() {
2272
2952
  function useEditComment() {
2273
2953
  const client = useClient();
2274
2954
  const room = useRoom();
2275
- return React4.useCallback(
2955
+ return React5.useCallback(
2276
2956
  ({ threadId, commentId, body }) => {
2277
2957
  const editedAt = /* @__PURE__ */ new Date();
2278
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2279
2958
  const { store, onMutationFailure } = getExtrasForClient2(client);
2280
- const thread = store.get().threads[threadId];
2959
+ const thread = store.getThreads().threadsById[threadId];
2281
2960
  if (thread === void 0) {
2282
2961
  _core.console.warn(
2283
2962
  `Internal unexpected behavior. Cannot edit comment in thread "${threadId}" because the thread does not exist in the cache.`
@@ -2293,38 +2972,17 @@ function useEditComment() {
2293
2972
  );
2294
2973
  return;
2295
2974
  }
2296
- store.pushOptimisticUpdate({
2975
+ const optimisticUpdateId = store.addOptimisticUpdate({
2297
2976
  type: "edit-comment",
2298
2977
  comment: {
2299
2978
  ...comment,
2300
2979
  editedAt,
2301
2980
  body
2302
- },
2303
- id: optimisticUpdateId
2981
+ }
2304
2982
  });
2305
2983
  room.editComment({ threadId, commentId, body }).then(
2306
2984
  (editedComment) => {
2307
- store.set((state) => {
2308
- const existingThread = state.threads[threadId];
2309
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2310
- (update) => update.id !== optimisticUpdateId
2311
- );
2312
- if (existingThread === void 0) {
2313
- return {
2314
- ...state,
2315
- optimisticUpdates: updatedOptimisticUpdates
2316
- };
2317
- }
2318
- return {
2319
- ...state,
2320
- threads: {
2321
- ...state.threads,
2322
- [threadId]: _core.upsertComment.call(void 0, existingThread, editedComment)
2323
- // Upsert the edited comment into the thread comments list (if applicable)
2324
- },
2325
- optimisticUpdates: updatedOptimisticUpdates
2326
- };
2327
- });
2985
+ store.editComment(threadId, optimisticUpdateId, editedComment);
2328
2986
  },
2329
2987
  (err) => onMutationFailure(
2330
2988
  err,
@@ -2344,41 +3002,25 @@ function useEditComment() {
2344
3002
  function useDeleteComment() {
2345
3003
  const client = useClient();
2346
3004
  const room = useRoom();
2347
- return React4.useCallback(
3005
+ return React5.useCallback(
2348
3006
  ({ threadId, commentId }) => {
2349
3007
  const deletedAt = /* @__PURE__ */ new Date();
2350
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2351
3008
  const { store, onMutationFailure } = getExtrasForClient2(client);
2352
- store.pushOptimisticUpdate({
3009
+ const optimisticUpdateId = store.addOptimisticUpdate({
2353
3010
  type: "delete-comment",
2354
3011
  threadId,
2355
3012
  commentId,
2356
3013
  deletedAt,
2357
- id: optimisticUpdateId,
2358
3014
  roomId: room.id
2359
3015
  });
2360
3016
  room.deleteComment({ threadId, commentId }).then(
2361
3017
  () => {
2362
- store.set((state) => {
2363
- const existingThread = state.threads[threadId];
2364
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2365
- (update) => update.id !== optimisticUpdateId
2366
- );
2367
- if (existingThread === void 0) {
2368
- return {
2369
- ...state,
2370
- optimisticUpdates: updatedOptimisticUpdates
2371
- };
2372
- }
2373
- return {
2374
- ...state,
2375
- threads: {
2376
- ...state.threads,
2377
- [threadId]: _core.deleteComment.call(void 0, existingThread, commentId, deletedAt)
2378
- },
2379
- optimisticUpdates: updatedOptimisticUpdates
2380
- };
2381
- });
3018
+ store.deleteComment(
3019
+ threadId,
3020
+ optimisticUpdateId,
3021
+ commentId,
3022
+ deletedAt
3023
+ );
2382
3024
  },
2383
3025
  (err) => onMutationFailure(
2384
3026
  err,
@@ -2397,13 +3039,12 @@ function useDeleteComment() {
2397
3039
  function useAddReaction() {
2398
3040
  const client = useClient();
2399
3041
  const room = useRoom();
2400
- return React4.useCallback(
3042
+ return React5.useCallback(
2401
3043
  ({ threadId, commentId, emoji }) => {
2402
3044
  const createdAt = /* @__PURE__ */ new Date();
2403
3045
  const userId = getCurrentUserId(room);
2404
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2405
3046
  const { store, onMutationFailure } = getExtrasForClient2(client);
2406
- store.pushOptimisticUpdate({
3047
+ const optimisticUpdateId = store.addOptimisticUpdate({
2407
3048
  type: "add-reaction",
2408
3049
  threadId,
2409
3050
  commentId,
@@ -2411,35 +3052,17 @@ function useAddReaction() {
2411
3052
  emoji,
2412
3053
  userId,
2413
3054
  createdAt
2414
- },
2415
- id: optimisticUpdateId
3055
+ }
2416
3056
  });
2417
3057
  room.addReaction({ threadId, commentId, emoji }).then(
2418
3058
  (addedReaction) => {
2419
- store.set((state) => {
2420
- const existingThread = state.threads[threadId];
2421
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2422
- (update) => update.id !== optimisticUpdateId
2423
- );
2424
- if (existingThread === void 0) {
2425
- return {
2426
- ...state,
2427
- optimisticUpdates: updatedOptimisticUpdates
2428
- };
2429
- }
2430
- return {
2431
- ...state,
2432
- threads: {
2433
- ...state.threads,
2434
- [threadId]: _core.addReaction.call(void 0,
2435
- existingThread,
2436
- commentId,
2437
- addedReaction
2438
- )
2439
- },
2440
- optimisticUpdates: updatedOptimisticUpdates
2441
- };
2442
- });
3059
+ store.addReaction(
3060
+ threadId,
3061
+ optimisticUpdateId,
3062
+ commentId,
3063
+ addedReaction,
3064
+ createdAt
3065
+ );
2443
3066
  },
2444
3067
  (err) => onMutationFailure(
2445
3068
  err,
@@ -2459,49 +3082,29 @@ function useAddReaction() {
2459
3082
  function useRemoveReaction() {
2460
3083
  const client = useClient();
2461
3084
  const room = useRoom();
2462
- return React4.useCallback(
3085
+ return React5.useCallback(
2463
3086
  ({ threadId, commentId, emoji }) => {
2464
3087
  const userId = getCurrentUserId(room);
2465
3088
  const removedAt = /* @__PURE__ */ new Date();
2466
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2467
3089
  const { store, onMutationFailure } = getExtrasForClient2(client);
2468
- store.pushOptimisticUpdate({
3090
+ const optimisticUpdateId = store.addOptimisticUpdate({
2469
3091
  type: "remove-reaction",
2470
3092
  threadId,
2471
3093
  commentId,
2472
3094
  emoji,
2473
3095
  userId,
2474
- removedAt,
2475
- id: optimisticUpdateId
3096
+ removedAt
2476
3097
  });
2477
3098
  room.removeReaction({ threadId, commentId, emoji }).then(
2478
3099
  () => {
2479
- store.set((state) => {
2480
- const existingThread = state.threads[threadId];
2481
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2482
- (update) => update.id !== optimisticUpdateId
2483
- );
2484
- if (existingThread === void 0) {
2485
- return {
2486
- ...state,
2487
- optimisticUpdates: updatedOptimisticUpdates
2488
- };
2489
- }
2490
- return {
2491
- ...state,
2492
- threads: {
2493
- ...state.threads,
2494
- [threadId]: _core.removeReaction.call(void 0,
2495
- existingThread,
2496
- commentId,
2497
- emoji,
2498
- userId,
2499
- removedAt
2500
- )
2501
- },
2502
- optimisticUpdates: updatedOptimisticUpdates
2503
- };
2504
- });
3100
+ store.removeReaction(
3101
+ threadId,
3102
+ optimisticUpdateId,
3103
+ commentId,
3104
+ emoji,
3105
+ userId,
3106
+ removedAt
3107
+ );
2505
3108
  },
2506
3109
  (err) => onMutationFailure(
2507
3110
  err,
@@ -2521,38 +3124,28 @@ function useRemoveReaction() {
2521
3124
  function useMarkThreadAsRead() {
2522
3125
  const client = useClient();
2523
3126
  const room = useRoom();
2524
- return React4.useCallback(
3127
+ return React5.useCallback(
2525
3128
  (threadId) => {
2526
3129
  const { store, onMutationFailure } = getExtrasForClient2(client);
2527
3130
  const inboxNotification = Object.values(
2528
- store.get().inboxNotifications
3131
+ store.getInboxNotifications().inboxNotificationsById
2529
3132
  ).find(
2530
3133
  (inboxNotification2) => inboxNotification2.kind === "thread" && inboxNotification2.threadId === threadId
2531
3134
  );
2532
3135
  if (!inboxNotification) return;
2533
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2534
3136
  const now = /* @__PURE__ */ new Date();
2535
- store.pushOptimisticUpdate({
3137
+ const optimisticUpdateId = store.addOptimisticUpdate({
2536
3138
  type: "mark-inbox-notification-as-read",
2537
- id: optimisticUpdateId,
2538
3139
  inboxNotificationId: inboxNotification.id,
2539
3140
  readAt: now
2540
3141
  });
2541
3142
  room.markInboxNotificationAsRead(inboxNotification.id).then(
2542
3143
  () => {
2543
- store.set((state) => ({
2544
- ...state,
2545
- inboxNotifications: {
2546
- ...state.inboxNotifications,
2547
- [inboxNotification.id]: {
2548
- ...inboxNotification,
2549
- readAt: now
2550
- }
2551
- },
2552
- optimisticUpdates: state.optimisticUpdates.filter(
2553
- (update) => update.id !== optimisticUpdateId
2554
- )
2555
- }));
3144
+ store.updateInboxNotification(
3145
+ inboxNotification.id,
3146
+ optimisticUpdateId,
3147
+ (inboxNotification2) => ({ ...inboxNotification2, readAt: now })
3148
+ );
2556
3149
  },
2557
3150
  (err) => {
2558
3151
  onMutationFailure(
@@ -2572,54 +3165,23 @@ function useMarkThreadAsRead() {
2572
3165
  function useMarkThreadAsResolved() {
2573
3166
  const client = useClient();
2574
3167
  const room = useRoom();
2575
- return React4.useCallback(
3168
+ return React5.useCallback(
2576
3169
  (threadId) => {
2577
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2578
3170
  const updatedAt = /* @__PURE__ */ new Date();
2579
3171
  const { store, onMutationFailure } = getExtrasForClient2(client);
2580
- store.pushOptimisticUpdate({
3172
+ const optimisticUpdateId = store.addOptimisticUpdate({
2581
3173
  type: "mark-thread-as-resolved",
2582
- id: optimisticUpdateId,
2583
3174
  threadId,
2584
3175
  updatedAt
2585
3176
  });
2586
3177
  room.markThreadAsResolved(threadId).then(
2587
3178
  () => {
2588
- store.set((state) => {
2589
- const existingThread = state.threads[threadId];
2590
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2591
- (update) => update.id !== optimisticUpdateId
2592
- );
2593
- if (existingThread === void 0) {
2594
- return {
2595
- ...state,
2596
- optimisticUpdates: updatedOptimisticUpdates
2597
- };
2598
- }
2599
- if (existingThread.deletedAt !== void 0) {
2600
- return {
2601
- ...state,
2602
- optimisticUpdates: updatedOptimisticUpdates
2603
- };
2604
- }
2605
- if (existingThread.updatedAt && existingThread.updatedAt > updatedAt) {
2606
- return {
2607
- ...state,
2608
- optimisticUpdates: updatedOptimisticUpdates
2609
- };
2610
- }
2611
- return {
2612
- ...state,
2613
- threads: {
2614
- ...state.threads,
2615
- [threadId]: {
2616
- ...existingThread,
2617
- resolved: true
2618
- }
2619
- },
2620
- optimisticUpdates: updatedOptimisticUpdates
2621
- };
2622
- });
3179
+ store.patchThread(
3180
+ threadId,
3181
+ optimisticUpdateId,
3182
+ { resolved: true },
3183
+ updatedAt
3184
+ );
2623
3185
  },
2624
3186
  (err) => onMutationFailure(
2625
3187
  err,
@@ -2637,54 +3199,23 @@ function useMarkThreadAsResolved() {
2637
3199
  function useMarkThreadAsUnresolved() {
2638
3200
  const client = useClient();
2639
3201
  const room = useRoom();
2640
- return React4.useCallback(
3202
+ return React5.useCallback(
2641
3203
  (threadId) => {
2642
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2643
3204
  const updatedAt = /* @__PURE__ */ new Date();
2644
3205
  const { store, onMutationFailure } = getExtrasForClient2(client);
2645
- store.pushOptimisticUpdate({
3206
+ const optimisticUpdateId = store.addOptimisticUpdate({
2646
3207
  type: "mark-thread-as-unresolved",
2647
- id: optimisticUpdateId,
2648
3208
  threadId,
2649
3209
  updatedAt
2650
3210
  });
2651
3211
  room.markThreadAsUnresolved(threadId).then(
2652
3212
  () => {
2653
- store.set((state) => {
2654
- const existingThread = state.threads[threadId];
2655
- const updatedOptimisticUpdates = state.optimisticUpdates.filter(
2656
- (update) => update.id !== optimisticUpdateId
2657
- );
2658
- if (existingThread === void 0) {
2659
- return {
2660
- ...state,
2661
- optimisticUpdates: updatedOptimisticUpdates
2662
- };
2663
- }
2664
- if (existingThread.deletedAt !== void 0) {
2665
- return {
2666
- ...state,
2667
- optimisticUpdates: updatedOptimisticUpdates
2668
- };
2669
- }
2670
- if (existingThread.updatedAt && existingThread.updatedAt > updatedAt) {
2671
- return {
2672
- ...state,
2673
- optimisticUpdates: updatedOptimisticUpdates
2674
- };
2675
- }
2676
- return {
2677
- ...state,
2678
- threads: {
2679
- ...state.threads,
2680
- [threadId]: {
2681
- ...existingThread,
2682
- resolved: false
2683
- }
2684
- },
2685
- optimisticUpdates: updatedOptimisticUpdates
2686
- };
2687
- });
3213
+ store.patchThread(
3214
+ threadId,
3215
+ optimisticUpdateId,
3216
+ { resolved: false },
3217
+ updatedAt
3218
+ );
2688
3219
  },
2689
3220
  (err) => onMutationFailure(
2690
3221
  err,
@@ -2702,12 +3233,12 @@ function useMarkThreadAsUnresolved() {
2702
3233
  function useThreadSubscription(threadId) {
2703
3234
  const client = useClient();
2704
3235
  const { store } = getExtrasForClient2(client);
2705
- const selector = React4.useCallback(
3236
+ const selector = React5.useCallback(
2706
3237
  (state) => {
2707
- const inboxNotification = selectedInboxNotifications(state).find(
3238
+ const inboxNotification = state.inboxNotifications.find(
2708
3239
  (inboxNotification2) => inboxNotification2.kind === "thread" && inboxNotification2.threadId === threadId
2709
3240
  );
2710
- const thread = state.threads[threadId];
3241
+ const thread = state.threadsById[threadId];
2711
3242
  if (inboxNotification === void 0 || thread === void 0) {
2712
3243
  return {
2713
3244
  status: "not-subscribed"
@@ -2721,9 +3252,9 @@ function useThreadSubscription(threadId) {
2721
3252
  [threadId]
2722
3253
  );
2723
3254
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2724
- store.subscribe,
2725
- store.get,
2726
- store.get,
3255
+ store.subscribeThreads,
3256
+ store.getThreads,
3257
+ store.getThreads,
2727
3258
  selector
2728
3259
  );
2729
3260
  }
@@ -2731,13 +3262,13 @@ function useRoomNotificationSettings() {
2731
3262
  const client = useClient();
2732
3263
  const room = useRoom();
2733
3264
  const { store } = getExtrasForClient2(client);
2734
- React4.useEffect(() => {
3265
+ React5.useEffect(() => {
2735
3266
  const { getInboxNotificationSettings } = getExtrasForClient2(client);
2736
3267
  const queryKey = makeNotificationSettingsQueryKey(room.id);
2737
3268
  void getInboxNotificationSettings(room, queryKey);
2738
3269
  }, [client, room]);
2739
3270
  const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
2740
- const selector = React4.useCallback(
3271
+ const selector = React5.useCallback(
2741
3272
  (state) => {
2742
3273
  const query = state.queries[makeNotificationSettingsQueryKey(room.id)];
2743
3274
  if (query === void 0 || query.isLoading) {
@@ -2754,21 +3285,21 @@ function useRoomNotificationSettings() {
2754
3285
  [room]
2755
3286
  );
2756
3287
  const settings = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2757
- store.subscribe,
2758
- store.get,
2759
- store.get,
3288
+ store.subscribeNotificationSettings,
3289
+ store.getThreads,
3290
+ store.getThreads,
2760
3291
  selector
2761
3292
  );
2762
- return React4.useMemo(() => {
3293
+ return React5.useMemo(() => {
2763
3294
  return [settings, updateRoomNotificationSettings];
2764
3295
  }, [settings, updateRoomNotificationSettings]);
2765
3296
  }
2766
3297
  function useHistoryVersionData(versionId) {
2767
- const [state, setState] = React4.useState({
3298
+ const [state, setState] = React5.useState({
2768
3299
  isLoading: true
2769
3300
  });
2770
3301
  const room = useRoom();
2771
- React4.useEffect(() => {
3302
+ React5.useEffect(() => {
2772
3303
  setState({ isLoading: true });
2773
3304
  const load = async () => {
2774
3305
  try {
@@ -2797,10 +3328,10 @@ function useHistoryVersions() {
2797
3328
  const room = useRoom();
2798
3329
  const queryKey = getVersionsQueryKey(room.id);
2799
3330
  const { store, getRoomVersions } = getExtrasForClient2(client);
2800
- React4.useEffect(() => {
3331
+ React5.useEffect(() => {
2801
3332
  void getRoomVersions(room);
2802
3333
  }, [room]);
2803
- const selector = React4.useCallback(
3334
+ const selector = React5.useCallback(
2804
3335
  (state2) => {
2805
3336
  const query = state2.queries[queryKey];
2806
3337
  if (query === void 0 || query.isLoading) {
@@ -2809,7 +3340,7 @@ function useHistoryVersions() {
2809
3340
  };
2810
3341
  }
2811
3342
  return {
2812
- versions: state2.versions[room.id],
3343
+ versions: state2.versionsByRoomId[room.id],
2813
3344
  isLoading: false,
2814
3345
  error: query.error
2815
3346
  };
@@ -2818,9 +3349,9 @@ function useHistoryVersions() {
2818
3349
  // eslint-disable-line react-hooks/exhaustive-deps
2819
3350
  );
2820
3351
  const state = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2821
- store.subscribe,
2822
- store.get,
2823
- store.get,
3352
+ store.subscribeVersions,
3353
+ store.getVersions,
3354
+ store.getVersions,
2824
3355
  selector
2825
3356
  );
2826
3357
  return state;
@@ -2828,27 +3359,21 @@ function useHistoryVersions() {
2828
3359
  function useUpdateRoomNotificationSettings() {
2829
3360
  const client = useClient();
2830
3361
  const room = useRoom();
2831
- return React4.useCallback(
3362
+ return React5.useCallback(
2832
3363
  (settings) => {
2833
- const optimisticUpdateId = _core.nanoid.call(void 0, );
2834
3364
  const { store, onMutationFailure } = getExtrasForClient2(client);
2835
- store.pushOptimisticUpdate({
2836
- id: optimisticUpdateId,
3365
+ const optimisticUpdateId = store.addOptimisticUpdate({
2837
3366
  type: "update-notification-settings",
2838
3367
  roomId: room.id,
2839
3368
  settings
2840
3369
  });
2841
3370
  room.updateNotificationSettings(settings).then(
2842
3371
  (settings2) => {
2843
- store.set((state) => ({
2844
- ...state,
2845
- notificationSettings: {
2846
- [room.id]: settings2
2847
- },
2848
- optimisticUpdates: state.optimisticUpdates.filter(
2849
- (update) => update.id !== optimisticUpdateId
2850
- )
2851
- }));
3372
+ store.updateRoomInboxNotificationSettings2(
3373
+ room.id,
3374
+ optimisticUpdateId,
3375
+ settings2
3376
+ );
2852
3377
  },
2853
3378
  (err) => onMutationFailure(
2854
3379
  err,
@@ -2922,36 +3447,40 @@ function useThreadsSuspense(options = {
2922
3447
  const { scrollOnLoad = true } = options;
2923
3448
  const client = useClient();
2924
3449
  const room = useRoom();
2925
- const queryKey = React4.useMemo(
3450
+ const queryKey = React5.useMemo(
2926
3451
  () => generateQueryKey(room.id, options.query),
2927
3452
  [room, options]
2928
3453
  );
2929
3454
  const { store, getThreadsAndInboxNotifications } = getExtrasForClient2(client);
2930
- const query = store.get().queries[queryKey];
3455
+ const query = store.getThreads().queries[queryKey];
2931
3456
  if (query === void 0 || query.isLoading) {
2932
3457
  throw getThreadsAndInboxNotifications(room, queryKey, options);
2933
3458
  }
2934
3459
  if (query.error) {
2935
3460
  throw query.error;
2936
3461
  }
2937
- const selector = React4.useCallback(
3462
+ const selector = React5.useCallback(
2938
3463
  (state2) => {
2939
3464
  return {
2940
- threads: selectedThreads(room.id, state2, options),
3465
+ threads: selectThreads(state2, {
3466
+ roomId: room.id,
3467
+ query: options.query,
3468
+ orderBy: "age"
3469
+ }),
2941
3470
  isLoading: false
2942
3471
  };
2943
3472
  },
2944
3473
  [room, queryKey]
2945
3474
  // eslint-disable-line react-hooks/exhaustive-deps
2946
3475
  );
2947
- React4.useEffect(() => {
3476
+ React5.useEffect(() => {
2948
3477
  const { incrementQuerySubscribers } = getExtrasForClient2(client);
2949
3478
  return incrementQuerySubscribers(queryKey);
2950
3479
  }, [client, queryKey]);
2951
3480
  const state = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2952
- store.subscribe,
2953
- store.get,
2954
- store.get,
3481
+ store.subscribeThreads,
3482
+ store.getThreads,
3483
+ store.getThreads,
2955
3484
  selector
2956
3485
  );
2957
3486
  useScrollToCommentOnLoadEffect(scrollOnLoad, state);
@@ -2962,17 +3491,17 @@ function useHistoryVersionsSuspense() {
2962
3491
  const room = useRoom();
2963
3492
  const queryKey = getVersionsQueryKey(room.id);
2964
3493
  const { store, getRoomVersions } = getExtrasForClient2(client);
2965
- const query = store.get().queries[queryKey];
3494
+ const query = store.getVersions().queries[queryKey];
2966
3495
  if (query === void 0 || query.isLoading) {
2967
3496
  throw getRoomVersions(room);
2968
3497
  }
2969
3498
  if (query.error) {
2970
3499
  throw query.error;
2971
3500
  }
2972
- const selector = React4.useCallback(
3501
+ const selector = React5.useCallback(
2973
3502
  (state2) => {
2974
3503
  return {
2975
- versions: state2.versions[room.id],
3504
+ versions: state2.versionsByRoomId[room.id],
2976
3505
  isLoading: false
2977
3506
  };
2978
3507
  },
@@ -2980,9 +3509,9 @@ function useHistoryVersionsSuspense() {
2980
3509
  // eslint-disable-line react-hooks/exhaustive-deps
2981
3510
  );
2982
3511
  const state = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
2983
- store.subscribe,
2984
- store.get,
2985
- store.get,
3512
+ store.subscribeVersions,
3513
+ store.getVersions,
3514
+ store.getVersions,
2986
3515
  selector
2987
3516
  );
2988
3517
  return state;
@@ -2993,14 +3522,14 @@ function useRoomNotificationSettingsSuspense() {
2993
3522
  const room = useRoom();
2994
3523
  const queryKey = makeNotificationSettingsQueryKey(room.id);
2995
3524
  const { store, getInboxNotificationSettings } = getExtrasForClient2(client);
2996
- const query = store.get().queries[queryKey];
3525
+ const query = store.getNotificationSettings().queries[queryKey];
2997
3526
  if (query === void 0 || query.isLoading) {
2998
3527
  throw getInboxNotificationSettings(room, queryKey);
2999
3528
  }
3000
3529
  if (query.error) {
3001
3530
  throw query.error;
3002
3531
  }
3003
- const selector = React4.useCallback(
3532
+ const selector = React5.useCallback(
3004
3533
  (state) => {
3005
3534
  return {
3006
3535
  isLoading: false,
@@ -3010,18 +3539,15 @@ function useRoomNotificationSettingsSuspense() {
3010
3539
  [room]
3011
3540
  );
3012
3541
  const settings = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
3013
- store.subscribe,
3014
- store.get,
3015
- store.get,
3542
+ store.subscribeNotificationSettings,
3543
+ store.getNotificationSettings,
3544
+ store.getNotificationSettings,
3016
3545
  selector
3017
3546
  );
3018
- return React4.useMemo(() => {
3547
+ return React5.useMemo(() => {
3019
3548
  return [settings, updateRoomNotificationSettings];
3020
3549
  }, [settings, updateRoomNotificationSettings]);
3021
3550
  }
3022
- function useRoomOrNull() {
3023
- return React4.useContext(RoomContext);
3024
- }
3025
3551
  function createRoomContext(client) {
3026
3552
  return getOrCreateRoomContextBundle(client);
3027
3553
  }
@@ -3149,5 +3675,6 @@ var _useUpdateMyPresence = useUpdateMyPresence;
3149
3675
 
3150
3676
 
3151
3677
 
3152
- exports.PKG_NAME = PKG_NAME; exports.PKG_VERSION = PKG_VERSION; exports.PKG_FORMAT = PKG_FORMAT; exports.ClientSideSuspense = ClientSideSuspense; exports.selectedThreads = selectedThreads; exports.CreateThreadError = CreateThreadError; exports.RoomContext = RoomContext; exports.useStatus = useStatus; exports.useStorageStatus = useStorageStatus; exports.useBatch = useBatch; exports.useLostConnectionListener = useLostConnectionListener; exports.useErrorListener = useErrorListener; exports.useHistory = useHistory; exports.useUndo = useUndo; exports.useRedo = useRedo; exports.useCanUndo = useCanUndo; exports.useCanRedo = useCanRedo; exports.useOthersConnectionIds = useOthersConnectionIds; exports.useCommentsErrorListener = useCommentsErrorListener; exports.useCreateComment = useCreateComment; exports.useEditComment = useEditComment; exports.useDeleteComment = useDeleteComment; exports.useRemoveReaction = useRemoveReaction; exports.useMarkThreadAsRead = useMarkThreadAsRead; exports.useMarkThreadAsResolved = useMarkThreadAsResolved; exports.useMarkThreadAsUnresolved = useMarkThreadAsUnresolved; exports.useThreadSubscription = useThreadSubscription; exports.useRoomNotificationSettings = useRoomNotificationSettings; exports.useHistoryVersionData = useHistoryVersionData; exports.useUpdateRoomNotificationSettings = useUpdateRoomNotificationSettings; exports.useOthersConnectionIdsSuspense = useOthersConnectionIdsSuspense; exports.useStorageStatusSuspense = useStorageStatusSuspense; exports.createRoomContext = createRoomContext; exports._RoomProvider = _RoomProvider; exports._useBroadcastEvent = _useBroadcastEvent; exports._useOthersListener = _useOthersListener; exports._useRoom = _useRoom; exports._useIsInsideRoom = _useIsInsideRoom; exports._useAddReaction = _useAddReaction; exports._useMutation = _useMutation; exports._useCreateThread = _useCreateThread; exports._useDeleteThread = _useDeleteThread; exports._useEditThreadMetadata = _useEditThreadMetadata; exports._useEventListener = _useEventListener; exports._useMyPresence = _useMyPresence; exports._useOthersMapped = _useOthersMapped; exports._useOthersMappedSuspense = _useOthersMappedSuspense; exports._useThreads = _useThreads; exports._useThreadsSuspense = _useThreadsSuspense; exports._useHistoryVersions = _useHistoryVersions; exports._useHistoryVersionsSuspense = _useHistoryVersionsSuspense; exports._useOther = _useOther; exports._useOthers = _useOthers; exports._useOtherSuspense = _useOtherSuspense; exports._useOthersSuspense = _useOthersSuspense; exports._useStorage = _useStorage; exports._useStorageSuspense = _useStorageSuspense; exports._useSelf = _useSelf; exports._useSelfSuspense = _useSelfSuspense; exports._useStorageRoot = _useStorageRoot; exports._useUpdateMyPresence = _useUpdateMyPresence; exports.ClientContext = ClientContext; exports.useClient = useClient; exports.LiveblocksProvider = LiveblocksProvider; exports.createLiveblocksContext = createLiveblocksContext; exports.useInboxNotifications = useInboxNotifications; exports.useInboxNotificationsSuspense = useInboxNotificationsSuspense; exports.useMarkAllInboxNotificationsAsRead = useMarkAllInboxNotificationsAsRead; exports.useMarkInboxNotificationAsRead = useMarkInboxNotificationAsRead; exports.useDeleteAllInboxNotifications = useDeleteAllInboxNotifications; exports.useDeleteInboxNotification = useDeleteInboxNotification; exports.useUnreadInboxNotificationsCount = useUnreadInboxNotificationsCount; exports.useUnreadInboxNotificationsCountSuspense = useUnreadInboxNotificationsCountSuspense; exports.useRoomInfo = useRoomInfo; exports.useRoomInfoSuspense = useRoomInfoSuspense; exports._useInboxNotificationThread = _useInboxNotificationThread; exports._useUser = _useUser; exports._useUserSuspense = _useUserSuspense; exports._useUserThreads_experimental = _useUserThreads_experimental; exports._useUserThreadsSuspense_experimental = _useUserThreadsSuspense_experimental;
3153
- //# sourceMappingURL=chunk-YGRZXVI6.js.map
3678
+
3679
+ exports.PKG_NAME = PKG_NAME; exports.PKG_VERSION = PKG_VERSION; exports.PKG_FORMAT = PKG_FORMAT; exports.ClientSideSuspense = ClientSideSuspense; exports.RoomContext = RoomContext; exports.ClientContext = ClientContext; exports.selectThreads = selectThreads; exports.getUmbrellaStoreForClient = getUmbrellaStoreForClient; exports.useClient = useClient; exports.LiveblocksProvider = LiveblocksProvider; exports.createLiveblocksContext = createLiveblocksContext; exports.useInboxNotifications = useInboxNotifications; exports.useInboxNotificationsSuspense = useInboxNotificationsSuspense; exports.useMarkAllInboxNotificationsAsRead = useMarkAllInboxNotificationsAsRead; exports.useMarkInboxNotificationAsRead = useMarkInboxNotificationAsRead; exports.useDeleteAllInboxNotifications = useDeleteAllInboxNotifications; exports.useDeleteInboxNotification = useDeleteInboxNotification; exports.useUnreadInboxNotificationsCount = useUnreadInboxNotificationsCount; exports.useUnreadInboxNotificationsCountSuspense = useUnreadInboxNotificationsCountSuspense; exports.useRoomInfo = useRoomInfo; exports.useRoomInfoSuspense = useRoomInfoSuspense; exports._useInboxNotificationThread = _useInboxNotificationThread; exports._useUser = _useUser; exports._useUserSuspense = _useUserSuspense; exports._useUserThreads_experimental = _useUserThreads_experimental; exports._useUserThreadsSuspense_experimental = _useUserThreadsSuspense_experimental; exports.CreateThreadError = CreateThreadError; exports.useStatus = useStatus; exports.useStorageStatus = useStorageStatus; exports.useBatch = useBatch; exports.useLostConnectionListener = useLostConnectionListener; exports.useErrorListener = useErrorListener; exports.useHistory = useHistory; exports.useUndo = useUndo; exports.useRedo = useRedo; exports.useCanUndo = useCanUndo; exports.useCanRedo = useCanRedo; exports.useOthersConnectionIds = useOthersConnectionIds; exports.useCommentsErrorListener = useCommentsErrorListener; exports.useCreateComment = useCreateComment; exports.useEditComment = useEditComment; exports.useDeleteComment = useDeleteComment; exports.useRemoveReaction = useRemoveReaction; exports.useMarkThreadAsRead = useMarkThreadAsRead; exports.useMarkThreadAsResolved = useMarkThreadAsResolved; exports.useMarkThreadAsUnresolved = useMarkThreadAsUnresolved; exports.useThreadSubscription = useThreadSubscription; exports.useRoomNotificationSettings = useRoomNotificationSettings; exports.useHistoryVersionData = useHistoryVersionData; exports.useUpdateRoomNotificationSettings = useUpdateRoomNotificationSettings; exports.useOthersConnectionIdsSuspense = useOthersConnectionIdsSuspense; exports.useStorageStatusSuspense = useStorageStatusSuspense; exports.createRoomContext = createRoomContext; exports._RoomProvider = _RoomProvider; exports._useBroadcastEvent = _useBroadcastEvent; exports._useOthersListener = _useOthersListener; exports._useRoom = _useRoom; exports._useIsInsideRoom = _useIsInsideRoom; exports._useAddReaction = _useAddReaction; exports._useMutation = _useMutation; exports._useCreateThread = _useCreateThread; exports._useDeleteThread = _useDeleteThread; exports._useEditThreadMetadata = _useEditThreadMetadata; exports._useEventListener = _useEventListener; exports._useMyPresence = _useMyPresence; exports._useOthersMapped = _useOthersMapped; exports._useOthersMappedSuspense = _useOthersMappedSuspense; exports._useThreads = _useThreads; exports._useThreadsSuspense = _useThreadsSuspense; exports._useHistoryVersions = _useHistoryVersions; exports._useHistoryVersionsSuspense = _useHistoryVersionsSuspense; exports._useOther = _useOther; exports._useOthers = _useOthers; exports._useOtherSuspense = _useOtherSuspense; exports._useOthersSuspense = _useOthersSuspense; exports._useStorage = _useStorage; exports._useStorageSuspense = _useStorageSuspense; exports._useSelf = _useSelf; exports._useSelfSuspense = _useSelfSuspense; exports._useStorageRoot = _useStorageRoot; exports._useUpdateMyPresence = _useUpdateMyPresence;
3680
+ //# sourceMappingURL=chunk-TNEGW2UU.js.map