@liveblocks/react 1.9.0-example1 → 1.19.0-test1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import { detectDupes } from "@liveblocks/core";
5
5
 
6
6
  // src/version.ts
7
7
  var PKG_NAME = "@liveblocks/react";
8
- var PKG_VERSION = "1.9.0-example1";
8
+ var PKG_VERSION = "1.19.0-test1";
9
9
  var PKG_FORMAT = "esm";
10
10
 
11
11
  // src/ClientSideSuspense.tsx
@@ -26,15 +26,22 @@ import {
26
26
  errorIf,
27
27
  isLiveNode,
28
28
  makeEventSource as makeEventSource2,
29
- stringify
29
+ stringify as stringify2
30
30
  } from "@liveblocks/core";
31
- import * as React2 from "react";
31
+ import * as React3 from "react";
32
32
  import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
33
33
 
34
- // src/comments/CommentsRoom.ts
35
- import { CommentsApiError, console as console2 } from "@liveblocks/core";
34
+ // src/comments/CommentsRoom.tsx
35
+ import { CommentsApiError, makeEventSource, stringify } from "@liveblocks/core";
36
36
  import { nanoid } from "nanoid";
37
- import { useCallback as useCallback3, useEffect as useEffect3 } from "react";
37
+ import React2, {
38
+ createContext,
39
+ useCallback as useCallback3,
40
+ useContext,
41
+ useEffect as useEffect3,
42
+ useMemo,
43
+ useRef as useRef3
44
+ } from "react";
38
45
  import { useSyncExternalStore as useSyncExternalStore3 } from "use-sync-external-store/shim/index.js";
39
46
 
40
47
  // src/comments/errors.ts
@@ -96,7 +103,6 @@ var RemoveReactionError = class extends Error {
96
103
  };
97
104
 
98
105
  // src/comments/lib/revalidation.ts
99
- import { makeEventSource } from "@liveblocks/core";
100
106
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
101
107
 
102
108
  // src/comments/lib/use-is-document-visible.ts
@@ -157,36 +163,39 @@ function useRevalidateCache(manager, fetcher, options = {}) {
157
163
  errorRetryCount = DEFAULT_MAX_ERROR_RETRY_COUNT
158
164
  } = options;
159
165
  const _revalidateCache = useCallback2(
160
- async (shouldDedupe, retryCount = 0) => {
166
+ async ({
167
+ shouldDedupe,
168
+ retryCount = 0
169
+ }) => {
161
170
  let startAt;
162
- const shouldStartRequest = !manager.request || !shouldDedupe;
171
+ const shouldStartRequest = !manager.getRequest() || !shouldDedupe;
163
172
  function deleteActiveRequest() {
164
- const activeRequest = manager.request;
173
+ const activeRequest = manager.getRequest();
165
174
  if (!activeRequest)
166
175
  return;
167
176
  if (activeRequest.timestamp !== startAt)
168
177
  return;
169
- manager.request = void 0;
178
+ manager.setRequest(void 0);
170
179
  }
171
180
  function handleError() {
172
181
  const timeout = ~~((Math.random() + 0.5) * (1 << (retryCount < 8 ? retryCount : 8))) * errorRetryInterval;
173
182
  if (retryCount > errorRetryCount)
174
183
  return;
175
184
  setTimeout(() => {
176
- void _revalidateCache(false, retryCount + 1);
185
+ void _revalidateCache({
186
+ shouldDedupe: false,
187
+ retryCount: retryCount + 1
188
+ });
177
189
  }, timeout);
178
190
  }
191
+ if (shouldStartRequest) {
192
+ manager.setRequest({
193
+ fetcher: fetcher(),
194
+ timestamp: ++timestamp
195
+ });
196
+ }
179
197
  try {
180
- if (shouldStartRequest) {
181
- const currentCache = manager.cache;
182
- if (!currentCache)
183
- manager.cache = { isLoading: true };
184
- manager.request = {
185
- fetcher: fetcher(),
186
- timestamp: ++timestamp
187
- };
188
- }
189
- const activeRequest = manager.request;
198
+ let activeRequest = manager.getRequest();
190
199
  if (!activeRequest)
191
200
  return;
192
201
  startAt = activeRequest.timestamp;
@@ -194,27 +203,21 @@ function useRevalidateCache(manager, fetcher, options = {}) {
194
203
  if (shouldStartRequest) {
195
204
  setTimeout(deleteActiveRequest, dedupingInterval);
196
205
  }
197
- if (!manager.request || manager.request.timestamp !== startAt)
206
+ activeRequest = manager.getRequest();
207
+ if (!activeRequest || activeRequest.timestamp !== startAt)
198
208
  return;
199
- const activeMutation = manager.mutation;
209
+ const activeMutation = manager.getMutation();
200
210
  if (activeMutation && (activeMutation.startTime > startAt || activeMutation.endTime > startAt || activeMutation.endTime === 0)) {
201
211
  return;
202
212
  }
203
- manager.cache = {
204
- isLoading: false,
205
- data: newData
206
- };
213
+ manager.setCache(newData);
207
214
  } catch (err) {
208
215
  deleteActiveRequest();
209
216
  const isVisible = document.visibilityState === "visible";
210
217
  const isOnline = isOnlineRef.current;
211
218
  if (shouldStartRequest && isVisible && isOnline)
212
219
  handleError();
213
- manager.cache = {
214
- data: manager.cache?.data,
215
- isLoading: false,
216
- error: err
217
- };
220
+ manager.setError(err);
218
221
  }
219
222
  return;
220
223
  },
@@ -235,8 +238,8 @@ function useRevalidateCache(manager, fetcher, options = {}) {
235
238
  };
236
239
  }, []);
237
240
  const revalidateCache = useCallback2(
238
- (shoulDedupe) => {
239
- return _revalidateCache(shoulDedupe, 0);
241
+ ({ shouldDedupe }) => {
242
+ return _revalidateCache({ shouldDedupe, retryCount: 0 });
240
243
  },
241
244
  [_revalidateCache]
242
245
  );
@@ -246,36 +249,33 @@ function useMutate(manager, revalidateCache) {
246
249
  const mutate = useCallback2(
247
250
  async (data, options) => {
248
251
  const beforeMutationTimestamp = ++timestamp;
249
- manager.mutation = {
252
+ manager.setMutation({
250
253
  startTime: beforeMutationTimestamp,
251
254
  endTime: 0
252
- };
253
- const currentCache = manager.cache;
254
- manager.cache = {
255
- isLoading: false,
256
- data: options.optimisticData
257
- };
255
+ });
256
+ const currentCache = manager.getCache();
257
+ manager.setCache(options.optimisticData);
258
258
  let error;
259
259
  try {
260
260
  await data;
261
261
  } catch (err) {
262
262
  error = err;
263
263
  }
264
- const activeMutation = manager.mutation;
264
+ const activeMutation = manager.getMutation();
265
265
  if (activeMutation && beforeMutationTimestamp !== activeMutation.startTime) {
266
266
  if (error)
267
267
  throw error;
268
268
  return;
269
269
  }
270
270
  if (error) {
271
- manager.cache = currentCache;
271
+ manager.setCache(currentCache);
272
272
  }
273
- manager.mutation = {
273
+ manager.setMutation({
274
274
  startTime: beforeMutationTimestamp,
275
275
  endTime: ++timestamp
276
- };
277
- manager.request = void 0;
278
- void revalidateCache(false);
276
+ });
277
+ manager.setRequest(void 0);
278
+ void revalidateCache({ shouldDedupe: false });
279
279
  if (error)
280
280
  throw error;
281
281
  },
@@ -297,8 +297,10 @@ function useAutomaticRevalidation(manager, revalidateCache, options = {}) {
297
297
  if (refreshInterval === 0)
298
298
  return;
299
299
  revalidationTimerId = window.setTimeout(() => {
300
- if (isOnline && isDocumentVisible && !manager.cache?.error) {
301
- void revalidateCache(true).then(scheduleRevalidation);
300
+ if (isOnline && isDocumentVisible && !manager.getError()) {
301
+ void revalidateCache({ shouldDedupe: true }).then(
302
+ scheduleRevalidation
303
+ );
302
304
  return;
303
305
  }
304
306
  scheduleRevalidation();
@@ -312,7 +314,7 @@ function useAutomaticRevalidation(manager, revalidateCache, options = {}) {
312
314
  useEffect2(() => {
313
315
  function handleIsOnline() {
314
316
  if (revalidateOnReconnect && isDocumentVisible) {
315
- void revalidateCache(true);
317
+ void revalidateCache({ shouldDedupe: true });
316
318
  }
317
319
  }
318
320
  window.addEventListener("online", handleIsOnline);
@@ -324,7 +326,7 @@ function useAutomaticRevalidation(manager, revalidateCache, options = {}) {
324
326
  function handleVisibilityChange() {
325
327
  const isVisible = document.visibilityState === "visible";
326
328
  if (revalidateOnFocus && isVisible && isOnline) {
327
- void revalidateCache(true);
329
+ void revalidateCache({ shouldDedupe: true });
328
330
  }
329
331
  }
330
332
  document.addEventListener("visibilitychange", handleVisibilityChange);
@@ -333,55 +335,171 @@ function useAutomaticRevalidation(manager, revalidateCache, options = {}) {
333
335
  };
334
336
  }, [revalidateCache, revalidateOnFocus, isOnline]);
335
337
  }
336
- function createCacheManager() {
337
- let cache;
338
- let request;
339
- let mutation;
340
- const eventSource = makeEventSource();
341
- return {
342
- get cache() {
343
- return cache;
344
- },
345
- set cache(value) {
346
- cache = value;
347
- eventSource.notify(cache);
348
- },
349
- get request() {
350
- return request;
351
- },
352
- set request(value) {
353
- request = value;
354
- },
355
- get mutation() {
356
- return mutation;
357
- },
358
- set mutation(value) {
359
- mutation = value;
360
- },
361
- subscribe(callback) {
362
- return eventSource.subscribe(callback);
363
- }
364
- };
365
- }
366
338
 
367
- // src/comments/CommentsRoom.ts
339
+ // src/comments/CommentsRoom.tsx
368
340
  var POLLING_INTERVAL_REALTIME = 3e4;
369
341
  var POLLING_INTERVAL = 5e3;
370
342
  var THREAD_ID_PREFIX = "th";
371
343
  var COMMENT_ID_PREFIX = "cm";
372
- function createOptimisticId(prefix) {
373
- return `${prefix}_${nanoid()}`;
374
- }
375
- function getPollingInterval(isBrowserOnline, isDocumentVisible, isRoomConnected) {
376
- if (!isBrowserOnline || !isDocumentVisible)
377
- return;
378
- if (isRoomConnected)
379
- return POLLING_INTERVAL_REALTIME;
380
- return POLLING_INTERVAL;
381
- }
382
- function createCommentsRoom(room, errorEventSource) {
383
- const manager = createCacheManager();
384
- function _useThreads(revalidateCache) {
344
+ function createCommentsRoom(errorEventSource) {
345
+ const manager = createThreadsCacheManager();
346
+ const filterOptions = /* @__PURE__ */ new Map();
347
+ const cacheStates = /* @__PURE__ */ new Map();
348
+ const revalidationManagers = /* @__PURE__ */ new Map();
349
+ function createThreadsRevalidationManager(key) {
350
+ let request;
351
+ let error;
352
+ return {
353
+ getCache() {
354
+ return void 0;
355
+ },
356
+ setCache(value) {
357
+ const cache = new Map(
358
+ (manager.getCache() ?? []).map((thread) => [thread.id, thread])
359
+ );
360
+ for (const thread of value) {
361
+ cache.set(thread.id, thread);
362
+ }
363
+ setCache(key, {
364
+ isLoading: false,
365
+ data: value
366
+ });
367
+ manager.setCache(Array.from(cache.values()));
368
+ },
369
+ // Request
370
+ getRequest() {
371
+ return request;
372
+ },
373
+ setRequest(value) {
374
+ request = value;
375
+ },
376
+ // Error
377
+ getError() {
378
+ return error;
379
+ },
380
+ setError(err) {
381
+ error = err;
382
+ manager.setError(err);
383
+ },
384
+ // Mutation
385
+ getMutation() {
386
+ return void 0;
387
+ },
388
+ setMutation() {
389
+ }
390
+ };
391
+ }
392
+ const eventSource = makeEventSource();
393
+ const subscribe2 = eventSource.subscribe;
394
+ const getCache = (key) => cacheStates.get(key);
395
+ const setCache = (key, value) => {
396
+ cacheStates.set(key, value);
397
+ };
398
+ const FetcherContext = createContext(null);
399
+ const CommentsEventSubscriptionContext = createContext(() => {
400
+ });
401
+ function getThreads() {
402
+ const threads = manager.getCache();
403
+ if (!threads) {
404
+ throw new Error(
405
+ "Cannot update threads or comments before they are loaded."
406
+ );
407
+ }
408
+ return threads;
409
+ }
410
+ function CommentsRoomProvider({
411
+ room,
412
+ children
413
+ }) {
414
+ const commentsEventSubscribersCountRef = useRef3(0);
415
+ const commentsEventDisposerRef = useRef3();
416
+ const fetcher = useCallback3(async () => {
417
+ const responses = await Promise.all(
418
+ Array.from(filterOptions.values()).map((info) => {
419
+ return room.getThreads(info.options);
420
+ })
421
+ );
422
+ const threads = Array.from(
423
+ new Map(responses.flat().map((thread) => [thread.id, thread])).values()
424
+ );
425
+ return threads;
426
+ }, [room]);
427
+ const revalidateCache = useRevalidateCache(manager, fetcher);
428
+ const subscribeToCommentEvents = useCallback3(() => {
429
+ const commentsEventSubscribersCount = commentsEventSubscribersCountRef.current;
430
+ if (commentsEventSubscribersCount === 0) {
431
+ const unsubscribe = room.events.comments.subscribe(() => {
432
+ void revalidateCache({ shouldDedupe: true });
433
+ });
434
+ commentsEventDisposerRef.current = unsubscribe;
435
+ }
436
+ commentsEventSubscribersCountRef.current = commentsEventSubscribersCount + 1;
437
+ return () => {
438
+ commentsEventSubscribersCountRef.current = commentsEventSubscribersCountRef.current - 1;
439
+ if (commentsEventSubscribersCountRef.current > 0)
440
+ return;
441
+ commentsEventDisposerRef.current?.();
442
+ commentsEventDisposerRef.current = void 0;
443
+ };
444
+ }, [revalidateCache, room]);
445
+ useEffect3(() => {
446
+ const unsubscribe = manager.subscribe("cache", (threads) => {
447
+ for (const [key, info] of filterOptions.entries()) {
448
+ const filtered = threads.filter((thread) => {
449
+ const query = info.options.query;
450
+ if (!query)
451
+ return true;
452
+ for (const key2 in query.metadata) {
453
+ if (thread.metadata[key2] !== query.metadata[key2]) {
454
+ return false;
455
+ }
456
+ }
457
+ return true;
458
+ });
459
+ setCache(key, {
460
+ isLoading: false,
461
+ data: filtered
462
+ });
463
+ }
464
+ for (const [key] of cacheStates.entries()) {
465
+ if (filterOptions.has(key))
466
+ continue;
467
+ cacheStates.delete(key);
468
+ }
469
+ eventSource.notify(threads);
470
+ });
471
+ return () => {
472
+ unsubscribe();
473
+ };
474
+ }, []);
475
+ useEffect3(() => {
476
+ const unsubscribe = manager.subscribe("error", (error) => {
477
+ for (const state of cacheStates.values()) {
478
+ state.error = error;
479
+ }
480
+ });
481
+ return () => {
482
+ unsubscribe();
483
+ };
484
+ }, []);
485
+ return /* @__PURE__ */ React2.createElement(FetcherContext.Provider, { value: fetcher }, /* @__PURE__ */ React2.createElement(
486
+ CommentsEventSubscriptionContext.Provider,
487
+ {
488
+ value: subscribeToCommentEvents
489
+ },
490
+ children
491
+ ));
492
+ }
493
+ function useThreadsFetcher() {
494
+ const fetcher = useContext(FetcherContext);
495
+ if (fetcher === null) {
496
+ throw new Error("CommentsRoomProvider is missing from the React tree.");
497
+ }
498
+ return fetcher;
499
+ }
500
+ function _useThreads(room, key) {
501
+ const fetcher = useThreadsFetcher();
502
+ const revalidateCache = useRevalidateCache(manager, fetcher);
385
503
  const status = useSyncExternalStore3(
386
504
  room.events.status.subscribe,
387
505
  room.getStatus,
@@ -389,6 +507,9 @@ function createCommentsRoom(room, errorEventSource) {
389
507
  );
390
508
  const isOnline = useIsOnline();
391
509
  const isDocumentVisible = useIsDocumentVisible();
510
+ const subscribeToCommentEvents = useContext(
511
+ CommentsEventSubscriptionContext
512
+ );
392
513
  const interval = getPollingInterval(
393
514
  isOnline,
394
515
  isDocumentVisible,
@@ -399,50 +520,126 @@ function createCommentsRoom(room, errorEventSource) {
399
520
  revalidateOnReconnect: true,
400
521
  refreshInterval: interval
401
522
  });
402
- useEffect3(() => {
403
- const unsubscribe = room.events.comments.subscribe(() => {
404
- void revalidateCache(true);
405
- });
406
- return () => {
407
- unsubscribe();
408
- };
409
- }, [revalidateCache]);
523
+ useEffect3(subscribeToCommentEvents, [subscribeToCommentEvents]);
410
524
  const cache = useSyncExternalStore3(
411
- manager.subscribe,
412
- () => manager.cache,
413
- () => manager.cache
525
+ subscribe2,
526
+ () => getCache(key),
527
+ () => getCache(key)
414
528
  );
415
529
  if (!cache || cache.isLoading) {
416
530
  return { isLoading: true };
417
531
  }
418
532
  return {
419
533
  isLoading: cache.isLoading,
420
- threads: cache.data ?? [],
534
+ threads: cache.data || [],
421
535
  error: cache.error
422
536
  };
423
537
  }
424
- function useThreads() {
425
- const revalidate = useRevalidateCache(manager, room.getThreads);
538
+ function useThreads(room, options = { query: { metadata: {} } }) {
539
+ const key = useMemo(() => stringify(options), [options]);
540
+ let revalidationManager = revalidationManagers.get(key);
541
+ if (!revalidationManager) {
542
+ revalidationManager = createThreadsRevalidationManager(key);
543
+ revalidationManagers.set(key, revalidationManager);
544
+ }
545
+ const fetcher = useCallback3(
546
+ () => {
547
+ return room.getThreads(options);
548
+ },
549
+ // eslint-disable-next-line react-hooks/exhaustive-deps
550
+ [key]
551
+ );
552
+ const revalidateCache = useRevalidateCache(revalidationManager, fetcher);
553
+ useEffect3(
554
+ () => {
555
+ const info = filterOptions.get(key);
556
+ if (info) {
557
+ info.count += 1;
558
+ } else {
559
+ filterOptions.set(key, {
560
+ options,
561
+ count: 1
562
+ });
563
+ cacheStates.set(key, { isLoading: true });
564
+ }
565
+ return () => {
566
+ const info2 = filterOptions.get(key);
567
+ if (!info2)
568
+ return;
569
+ info2.count -= 1;
570
+ if (info2.count > 0)
571
+ return;
572
+ filterOptions.delete(key);
573
+ };
574
+ },
575
+ // eslint-disable-next-line react-hooks/exhaustive-deps
576
+ [key]
577
+ );
426
578
  useEffect3(() => {
427
- void revalidate(true);
428
- }, [revalidate]);
429
- return _useThreads(revalidate);
430
- }
431
- function useThreadsSuspense() {
432
- const revalidate = useRevalidateCache(manager, room.getThreads);
433
- const cache = _useThreads(revalidate);
579
+ void revalidateCache({ shouldDedupe: true });
580
+ }, [revalidateCache]);
581
+ return _useThreads(room, key);
582
+ }
583
+ function useThreadsSuspense(room, options = {}) {
584
+ const key = useMemo(() => stringify(options), [options]);
585
+ let revalidationManager = revalidationManagers.get(key);
586
+ if (!revalidationManager) {
587
+ revalidationManager = createThreadsRevalidationManager(key);
588
+ revalidationManagers.set(key, revalidationManager);
589
+ }
590
+ const fetcher = useCallback3(
591
+ () => {
592
+ return room.getThreads(options);
593
+ },
594
+ // eslint-disable-next-line react-hooks/exhaustive-deps
595
+ [key]
596
+ );
597
+ const info = filterOptions.get(key);
598
+ if (!info) {
599
+ filterOptions.set(key, {
600
+ options,
601
+ count: 0
602
+ });
603
+ cacheStates.set(key, { isLoading: true });
604
+ }
605
+ const revalidateCache = useRevalidateCache(revalidationManager, fetcher);
606
+ useEffect3(
607
+ () => {
608
+ const info2 = filterOptions.get(key);
609
+ if (info2) {
610
+ info2.count += 1;
611
+ } else {
612
+ filterOptions.set(key, {
613
+ options,
614
+ count: 1
615
+ });
616
+ }
617
+ return () => {
618
+ const info3 = filterOptions.get(key);
619
+ if (!info3)
620
+ return;
621
+ info3.count -= 1;
622
+ if (info3.count > 0)
623
+ return;
624
+ filterOptions.delete(key);
625
+ };
626
+ },
627
+ // eslint-disable-next-line react-hooks/exhaustive-deps
628
+ [key]
629
+ );
630
+ const cache = _useThreads(room, key);
434
631
  if (cache.error) {
435
632
  throw cache.error;
436
633
  }
437
634
  if (cache.isLoading || !cache.threads) {
438
- throw revalidate(true);
635
+ throw revalidateCache({ shouldDedupe: true });
439
636
  }
440
637
  return {
441
638
  threads: cache.threads,
442
639
  isLoading: false
443
640
  };
444
641
  }
445
- function useEditThreadMetadata() {
642
+ function useEditThreadMetadata(room) {
446
643
  const revalidate = useRevalidateCache(manager, room.getThreads);
447
644
  const mutate = useMutate(manager, revalidate);
448
645
  const editThreadMetadata = useCallback3(
@@ -475,12 +672,13 @@ function createCommentsRoom(room, errorEventSource) {
475
672
  );
476
673
  });
477
674
  },
478
- [mutate]
675
+ [room, mutate]
479
676
  );
480
677
  return editThreadMetadata;
481
678
  }
482
- function useCreateThread() {
483
- const revalidate = useRevalidateCache(manager, room.getThreads);
679
+ function useCreateThread(room) {
680
+ const fetcher = useThreadsFetcher();
681
+ const revalidate = useRevalidateCache(manager, fetcher);
484
682
  const mutate = useMutate(manager, revalidate);
485
683
  const createThread = useCallback3(
486
684
  (options) => {
@@ -496,7 +694,7 @@ function createCommentsRoom(room, errorEventSource) {
496
694
  roomId: room.id,
497
695
  createdAt: now,
498
696
  type: "comment",
499
- userId: getCurrentUserId(),
697
+ userId: getCurrentUserId(room),
500
698
  body,
501
699
  reactions: []
502
700
  };
@@ -527,12 +725,13 @@ function createCommentsRoom(room, errorEventSource) {
527
725
  });
528
726
  return newThread;
529
727
  },
530
- [mutate]
728
+ [room, mutate]
531
729
  );
532
730
  return createThread;
533
731
  }
534
- function useCreateComment() {
535
- const revalidate = useRevalidateCache(manager, room.getThreads);
732
+ function useCreateComment(room) {
733
+ const fetcher = useThreadsFetcher();
734
+ const revalidate = useRevalidateCache(manager, fetcher);
536
735
  const mutate = useMutate(manager, revalidate);
537
736
  const createComment = useCallback3(
538
737
  ({ threadId, body }) => {
@@ -545,7 +744,7 @@ function createCommentsRoom(room, errorEventSource) {
545
744
  roomId: room.id,
546
745
  type: "comment",
547
746
  createdAt: now,
548
- userId: getCurrentUserId(),
747
+ userId: getCurrentUserId(room),
549
748
  body,
550
749
  reactions: []
551
750
  };
@@ -573,11 +772,11 @@ function createCommentsRoom(room, errorEventSource) {
573
772
  });
574
773
  return comment;
575
774
  },
576
- [mutate]
775
+ [room, mutate]
577
776
  );
578
777
  return createComment;
579
778
  }
580
- function useEditComment() {
779
+ function useEditComment(room) {
581
780
  const revalidate = useRevalidateCache(manager, room.getThreads);
582
781
  const mutate = useMutate(manager, revalidate);
583
782
  const editComment = useCallback3(
@@ -613,11 +812,11 @@ function createCommentsRoom(room, errorEventSource) {
613
812
  );
614
813
  });
615
814
  },
616
- [mutate]
815
+ [room, mutate]
617
816
  );
618
817
  return editComment;
619
818
  }
620
- function useDeleteComment() {
819
+ function useDeleteComment(room) {
621
820
  const revalidate = useRevalidateCache(manager, room.getThreads);
622
821
  const mutate = useMutate(manager, revalidate);
623
822
  const deleteComment = useCallback3(
@@ -662,18 +861,18 @@ function createCommentsRoom(room, errorEventSource) {
662
861
  );
663
862
  });
664
863
  },
665
- [mutate]
864
+ [room, mutate]
666
865
  );
667
866
  return deleteComment;
668
867
  }
669
- function useAddReaction() {
868
+ function useAddReaction(room) {
670
869
  const revalidate = useRevalidateCache(manager, room.getThreads);
671
870
  const mutate = useMutate(manager, revalidate);
672
871
  const createComment = useCallback3(
673
872
  ({ threadId, commentId, emoji }) => {
674
873
  const threads = getThreads();
675
874
  const now = /* @__PURE__ */ new Date();
676
- const userId = getCurrentUserId();
875
+ const userId = getCurrentUserId(room);
677
876
  const optimisticData = threads.map(
678
877
  (thread) => thread.id === threadId ? {
679
878
  ...thread,
@@ -725,17 +924,17 @@ function createCommentsRoom(room, errorEventSource) {
725
924
  );
726
925
  });
727
926
  },
728
- [mutate]
927
+ [room, mutate]
729
928
  );
730
929
  return createComment;
731
930
  }
732
- function useRemoveReaction() {
931
+ function useRemoveReaction(room) {
733
932
  const revalidate = useRevalidateCache(manager, room.getThreads);
734
933
  const mutate = useMutate(manager, revalidate);
735
934
  const createComment = useCallback3(
736
935
  ({ threadId, commentId, emoji }) => {
737
936
  const threads = getThreads();
738
- const userId = getCurrentUserId();
937
+ const userId = getCurrentUserId(room);
739
938
  const optimisticData = threads.map(
740
939
  (thread) => thread.id === threadId ? {
741
940
  ...thread,
@@ -786,44 +985,16 @@ function createCommentsRoom(room, errorEventSource) {
786
985
  );
787
986
  });
788
987
  },
789
- [mutate]
988
+ [room, mutate]
790
989
  );
791
990
  return createComment;
792
991
  }
793
- function getThreads() {
794
- const threads = manager.cache;
795
- if (!threads || threads.isLoading || threads.error || threads.data === void 0) {
796
- throw new Error(
797
- "Cannot update threads or comments before they are loaded."
798
- );
799
- }
800
- return threads.data;
801
- }
802
- function getCurrentUserId() {
803
- const self = room.getSelf();
804
- if (self === null || self.id === void 0) {
805
- return "anonymous";
806
- } else {
807
- return self.id;
808
- }
809
- }
810
- function handleCommentsApiError(err) {
811
- const message = `Request failed with status ${err.status}: ${err.message}`;
812
- if (err.details?.error === "FORBIDDEN") {
813
- const detailedMessage = [
814
- message,
815
- err.details.suggestion,
816
- err.details.docs
817
- ].filter(Boolean).join("\n");
818
- console2.error(detailedMessage);
819
- }
820
- return new Error(message);
821
- }
822
992
  return {
993
+ CommentsRoomProvider,
823
994
  useThreads,
824
995
  useThreadsSuspense,
825
- useCreateThread,
826
996
  useEditThreadMetadata,
997
+ useCreateThread,
827
998
  useCreateComment,
828
999
  useEditComment,
829
1000
  useDeleteComment,
@@ -831,12 +1002,92 @@ function createCommentsRoom(room, errorEventSource) {
831
1002
  useRemoveReaction
832
1003
  };
833
1004
  }
1005
+ function createOptimisticId(prefix) {
1006
+ return `${prefix}_${nanoid()}`;
1007
+ }
1008
+ function getCurrentUserId(room) {
1009
+ const self = room.getSelf();
1010
+ if (self === null || self.id === void 0) {
1011
+ return "anonymous";
1012
+ } else {
1013
+ return self.id;
1014
+ }
1015
+ }
1016
+ function handleCommentsApiError(err) {
1017
+ const message = `Request failed with status ${err.status}: ${err.message}`;
1018
+ if (err.details?.error === "FORBIDDEN") {
1019
+ const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
1020
+ console.error(detailedMessage);
1021
+ }
1022
+ return new Error(message);
1023
+ }
1024
+ function getPollingInterval(isBrowserOnline, isDocumentVisible, isRoomConnected) {
1025
+ if (!isBrowserOnline || !isDocumentVisible)
1026
+ return;
1027
+ if (isRoomConnected)
1028
+ return POLLING_INTERVAL_REALTIME;
1029
+ return POLLING_INTERVAL;
1030
+ }
1031
+ function createThreadsCacheManager() {
1032
+ let cache;
1033
+ let request;
1034
+ let error;
1035
+ let mutation;
1036
+ const cacheEventSource = makeEventSource();
1037
+ const errorEventSource = makeEventSource();
1038
+ return {
1039
+ // Cache
1040
+ getCache() {
1041
+ return cache;
1042
+ },
1043
+ setCache(value) {
1044
+ const sorted = value.sort(
1045
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1046
+ );
1047
+ cache = sorted;
1048
+ cacheEventSource.notify(cache);
1049
+ },
1050
+ // Request
1051
+ getRequest() {
1052
+ return request;
1053
+ },
1054
+ setRequest(value) {
1055
+ request = value;
1056
+ },
1057
+ // Error
1058
+ getError() {
1059
+ return error;
1060
+ },
1061
+ setError(err) {
1062
+ error = err;
1063
+ errorEventSource.notify(err);
1064
+ },
1065
+ // Mutation
1066
+ getMutation() {
1067
+ return mutation;
1068
+ },
1069
+ setMutation(info) {
1070
+ mutation = info;
1071
+ },
1072
+ // Subscription
1073
+ subscribe(type, callback) {
1074
+ switch (type) {
1075
+ case "cache":
1076
+ return cacheEventSource.subscribe(
1077
+ callback
1078
+ );
1079
+ case "error":
1080
+ return errorEventSource.subscribe(callback);
1081
+ }
1082
+ }
1083
+ };
1084
+ }
834
1085
 
835
1086
  // src/comments/lib/use-debounce.ts
836
- import { useEffect as useEffect4, useRef as useRef3, useState as useState2 } from "react";
1087
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState2 } from "react";
837
1088
  var DEFAULT_DELAY = 500;
838
1089
  function useDebounce(value, delay = DEFAULT_DELAY) {
839
- const timeout = useRef3();
1090
+ const timeout = useRef4();
840
1091
  const [debouncedValue, setDebouncedValue] = useState2(value);
841
1092
  useEffect4(() => {
842
1093
  if (delay === false) {
@@ -857,7 +1108,7 @@ function useDebounce(value, delay = DEFAULT_DELAY) {
857
1108
  }
858
1109
 
859
1110
  // src/lib/use-async-cache.ts
860
- import { useCallback as useCallback4, useEffect as useEffect5, useMemo, useRef as useRef4 } from "react";
1111
+ import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo2, useRef as useRef5 } from "react";
861
1112
  import { useSyncExternalStore as useSyncExternalStore4 } from "use-sync-external-store/shim/index.js";
862
1113
 
863
1114
  // src/lib/use-initial.ts
@@ -876,7 +1127,7 @@ var noop = () => {
876
1127
  };
877
1128
  function useAsyncCache(cache, key, options) {
878
1129
  const frozenOptions = useInitial(options);
879
- const cacheItem = useMemo(() => {
1130
+ const cacheItem = useMemo2(() => {
880
1131
  if (key === null || !cache) {
881
1132
  return null;
882
1133
  }
@@ -894,7 +1145,7 @@ function useAsyncCache(cache, key, options) {
894
1145
  );
895
1146
  const revalidate = useCallback4(() => cacheItem?.revalidate(), [cacheItem]);
896
1147
  const state = useSyncExternalStore4(subscribe2, getState, getState);
897
- const previousData = useRef4();
1148
+ const previousData = useRef5();
898
1149
  let data = state.data;
899
1150
  useEffect5(() => {
900
1151
  previousData.current = { key, data: state.data };
@@ -935,9 +1186,9 @@ function useAsyncCache(cache, key, options) {
935
1186
  }
936
1187
 
937
1188
  // src/lib/use-latest.ts
938
- import { useEffect as useEffect6, useRef as useRef5 } from "react";
1189
+ import { useEffect as useEffect6, useRef as useRef6 } from "react";
939
1190
  function useLatest(value) {
940
- const ref = useRef5(value);
1191
+ const ref = useRef6(value);
941
1192
  useEffect6(() => {
942
1193
  ref.current = value;
943
1194
  }, [value]);
@@ -1019,21 +1270,23 @@ function warnIfNoResolveUsers(usersCache) {
1019
1270
  hasWarnedIfNoResolveUsers = true;
1020
1271
  }
1021
1272
  }
1022
- var ContextBundle = React2.createContext(null);
1273
+ var ContextBundle = React3.createContext(null);
1023
1274
  function useRoomContextBundle() {
1024
- const bundle = React2.useContext(ContextBundle);
1275
+ const bundle = React3.useContext(ContextBundle);
1025
1276
  if (bundle === null) {
1026
1277
  throw new Error("RoomProvider is missing from the React tree.");
1027
1278
  }
1028
1279
  return bundle;
1029
1280
  }
1030
1281
  function createRoomContext(client, options) {
1031
- const RoomContext = React2.createContext(null);
1282
+ const RoomContext = React3.createContext(null);
1283
+ const commentsErrorEventSource = makeEventSource2();
1284
+ const { CommentsRoomProvider, ...commentsRoom } = createCommentsRoom(commentsErrorEventSource);
1032
1285
  function RoomProviderOuter(props) {
1033
- const [cache] = React2.useState(
1286
+ const [cache] = React3.useState(
1034
1287
  () => /* @__PURE__ */ new Map()
1035
1288
  );
1036
- const stableEnterRoom = React2.useCallback(
1289
+ const stableEnterRoom = React3.useCallback(
1037
1290
  (roomId, options2) => {
1038
1291
  const cached = cache.get(roomId);
1039
1292
  if (cached)
@@ -1052,7 +1305,7 @@ function createRoomContext(client, options) {
1052
1305
  },
1053
1306
  [cache]
1054
1307
  );
1055
- return /* @__PURE__ */ React2.createElement(RoomProviderInner, { ...props, stableEnterRoom });
1308
+ return /* @__PURE__ */ React3.createElement(RoomProviderInner, { ...props, stableEnterRoom });
1056
1309
  }
1057
1310
  function RoomProviderInner(props) {
1058
1311
  const { id: roomId, stableEnterRoom } = props;
@@ -1065,7 +1318,7 @@ function createRoomContext(client, options) {
1065
1318
  if (typeof roomId !== "string") {
1066
1319
  throw new Error("RoomProvider id property should be a string.");
1067
1320
  }
1068
- const majorReactVersion = parseInt(React2.version) || 1;
1321
+ const majorReactVersion = parseInt(React3.version) || 1;
1069
1322
  const oldReactVersion = majorReactVersion < 18;
1070
1323
  errorIf(
1071
1324
  oldReactVersion && props.unstable_batchedUpdates === void 0,
@@ -1082,14 +1335,14 @@ function createRoomContext(client, options) {
1082
1335
  unstable_batchedUpdates: props.unstable_batchedUpdates,
1083
1336
  autoConnect: props.autoConnect ?? props.shouldInitiallyConnect ?? typeof window !== "undefined"
1084
1337
  });
1085
- const [{ room }, setRoomLeavePair] = React2.useState(
1338
+ const [{ room }, setRoomLeavePair] = React3.useState(
1086
1339
  () => stableEnterRoom(roomId, {
1087
1340
  ...frozenProps,
1088
1341
  autoConnect: false
1089
1342
  // Deliberately using false here on the first render, see below
1090
1343
  })
1091
1344
  );
1092
- React2.useEffect(() => {
1345
+ React3.useEffect(() => {
1093
1346
  const pair = stableEnterRoom(roomId, frozenProps);
1094
1347
  setRoomLeavePair(pair);
1095
1348
  const { room: room2, leave } = pair;
@@ -1097,26 +1350,22 @@ function createRoomContext(client, options) {
1097
1350
  room2.connect();
1098
1351
  }
1099
1352
  return () => {
1100
- const commentsRoom = commentsRooms.get(room2);
1101
- if (commentsRoom) {
1102
- commentsRooms.delete(room2);
1103
- }
1104
1353
  leave();
1105
1354
  };
1106
1355
  }, [roomId, frozenProps, stableEnterRoom]);
1107
- return /* @__PURE__ */ React2.createElement(RoomContext.Provider, { value: room }, /* @__PURE__ */ React2.createElement(
1356
+ return /* @__PURE__ */ React3.createElement(RoomContext.Provider, { value: room }, /* @__PURE__ */ React3.createElement(CommentsRoomProvider, { room }, /* @__PURE__ */ React3.createElement(
1108
1357
  ContextBundle.Provider,
1109
1358
  {
1110
1359
  value: internalBundle
1111
1360
  },
1112
1361
  props.children
1113
- ));
1362
+ )));
1114
1363
  }
1115
1364
  function connectionIdSelector(others) {
1116
1365
  return others.map((user) => user.connectionId);
1117
1366
  }
1118
1367
  function useRoom() {
1119
- const room = React2.useContext(RoomContext);
1368
+ const room = React3.useContext(RoomContext);
1120
1369
  if (room === null) {
1121
1370
  throw new Error("RoomProvider is missing from the React tree.");
1122
1371
  }
@@ -1157,13 +1406,13 @@ function createRoomContext(client, options) {
1157
1406
  return useOthers(connectionIdSelector, shallow);
1158
1407
  }
1159
1408
  function useOthersMapped(itemSelector, itemIsEqual) {
1160
- const wrappedSelector = React2.useCallback(
1409
+ const wrappedSelector = React3.useCallback(
1161
1410
  (others) => others.map(
1162
1411
  (other) => [other.connectionId, itemSelector(other)]
1163
1412
  ),
1164
1413
  [itemSelector]
1165
1414
  );
1166
- const wrappedIsEqual = React2.useCallback(
1415
+ const wrappedIsEqual = React3.useCallback(
1167
1416
  (a, b) => {
1168
1417
  const eq = itemIsEqual ?? Object.is;
1169
1418
  return a.length === b.length && a.every((atuple, index) => {
@@ -1177,7 +1426,7 @@ function createRoomContext(client, options) {
1177
1426
  }
1178
1427
  const NOT_FOUND = Symbol();
1179
1428
  function useOther(connectionId, selector, isEqual) {
1180
- const wrappedSelector = React2.useCallback(
1429
+ const wrappedSelector = React3.useCallback(
1181
1430
  (others) => {
1182
1431
  const other2 = others.find(
1183
1432
  (other3) => other3.connectionId === connectionId
@@ -1186,7 +1435,7 @@ function createRoomContext(client, options) {
1186
1435
  },
1187
1436
  [connectionId, selector]
1188
1437
  );
1189
- const wrappedIsEqual = React2.useCallback(
1438
+ const wrappedIsEqual = React3.useCallback(
1190
1439
  (prev, curr) => {
1191
1440
  if (prev === NOT_FOUND || curr === NOT_FOUND) {
1192
1441
  return prev === curr;
@@ -1206,7 +1455,7 @@ function createRoomContext(client, options) {
1206
1455
  }
1207
1456
  function useBroadcastEvent() {
1208
1457
  const room = useRoom();
1209
- return React2.useCallback(
1458
+ return React3.useCallback(
1210
1459
  (event, options2 = { shouldQueueEventIfNotReady: false }) => {
1211
1460
  room.broadcastEvent(event, options2);
1212
1461
  },
@@ -1216,7 +1465,7 @@ function createRoomContext(client, options) {
1216
1465
  function useOthersListener(callback) {
1217
1466
  const room = useRoom();
1218
1467
  const savedCallback = useLatest(callback);
1219
- React2.useEffect(
1468
+ React3.useEffect(
1220
1469
  () => room.events.others.subscribe((event) => savedCallback.current(event)),
1221
1470
  [room, savedCallback]
1222
1471
  );
@@ -1224,7 +1473,7 @@ function createRoomContext(client, options) {
1224
1473
  function useLostConnectionListener(callback) {
1225
1474
  const room = useRoom();
1226
1475
  const savedCallback = useLatest(callback);
1227
- React2.useEffect(
1476
+ React3.useEffect(
1228
1477
  () => room.events.lostConnection.subscribe(
1229
1478
  (event) => savedCallback.current(event)
1230
1479
  ),
@@ -1234,7 +1483,7 @@ function createRoomContext(client, options) {
1234
1483
  function useErrorListener(callback) {
1235
1484
  const room = useRoom();
1236
1485
  const savedCallback = useLatest(callback);
1237
- React2.useEffect(
1486
+ React3.useEffect(
1238
1487
  () => room.events.error.subscribe((e) => savedCallback.current(e)),
1239
1488
  [room, savedCallback]
1240
1489
  );
@@ -1242,7 +1491,7 @@ function createRoomContext(client, options) {
1242
1491
  function useEventListener(callback) {
1243
1492
  const room = useRoom();
1244
1493
  const savedCallback = useLatest(callback);
1245
- React2.useEffect(() => {
1494
+ React3.useEffect(() => {
1246
1495
  const listener = (eventData) => {
1247
1496
  savedCallback.current(eventData);
1248
1497
  };
@@ -1254,7 +1503,7 @@ function createRoomContext(client, options) {
1254
1503
  const subscribe2 = room.events.self.subscribe;
1255
1504
  const getSnapshot2 = room.getSelf;
1256
1505
  const selector = maybeSelector ?? identity;
1257
- const wrappedSelector = React2.useCallback(
1506
+ const wrappedSelector = React3.useCallback(
1258
1507
  (me) => me !== null ? selector(me) : null,
1259
1508
  [selector]
1260
1509
  );
@@ -1305,7 +1554,7 @@ function createRoomContext(client, options) {
1305
1554
  const room = useRoom();
1306
1555
  const rootOrNull = useMutableStorageRoot();
1307
1556
  const rerender = useRerender();
1308
- React2.useEffect(() => {
1557
+ React3.useEffect(() => {
1309
1558
  if (rootOrNull === null) {
1310
1559
  return;
1311
1560
  }
@@ -1341,15 +1590,15 @@ function createRoomContext(client, options) {
1341
1590
  function useStorage(selector, isEqual) {
1342
1591
  const room = useRoom();
1343
1592
  const rootOrNull = useMutableStorageRoot();
1344
- const wrappedSelector = React2.useCallback(
1593
+ const wrappedSelector = React3.useCallback(
1345
1594
  (rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
1346
1595
  [selector]
1347
1596
  );
1348
- const subscribe2 = React2.useCallback(
1597
+ const subscribe2 = React3.useCallback(
1349
1598
  (onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop2,
1350
1599
  [room, rootOrNull]
1351
1600
  );
1352
- const getSnapshot2 = React2.useCallback(() => {
1601
+ const getSnapshot2 = React3.useCallback(() => {
1353
1602
  if (rootOrNull === null) {
1354
1603
  return null;
1355
1604
  } else {
@@ -1397,7 +1646,7 @@ function createRoomContext(client, options) {
1397
1646
  }
1398
1647
  function useMutation(callback, deps) {
1399
1648
  const room = useRoom();
1400
- return React2.useMemo(
1649
+ return React3.useMemo(
1401
1650
  () => {
1402
1651
  return (...args) => (
1403
1652
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
@@ -1453,51 +1702,41 @@ function createRoomContext(client, options) {
1453
1702
  useSuspendUntilStorageLoaded();
1454
1703
  return useLegacyKey(key);
1455
1704
  }
1456
- const commentsErrorEventSource = makeEventSource2();
1457
- const commentsRooms = /* @__PURE__ */ new Map();
1458
- function getCommentsRoom(room) {
1459
- let commentsRoom = commentsRooms.get(room);
1460
- if (commentsRoom === void 0) {
1461
- commentsRoom = createCommentsRoom(room, commentsErrorEventSource);
1462
- commentsRooms.set(room, commentsRoom);
1463
- }
1464
- return commentsRoom;
1465
- }
1466
- function useThreads() {
1705
+ function useThreads(options2) {
1467
1706
  const room = useRoom();
1468
- return getCommentsRoom(room).useThreads();
1707
+ return commentsRoom.useThreads(room, options2);
1469
1708
  }
1470
- function useThreadsSuspense() {
1709
+ function useThreadsSuspense(options2) {
1471
1710
  const room = useRoom();
1472
- return getCommentsRoom(room).useThreadsSuspense();
1711
+ return commentsRoom.useThreadsSuspense(room, options2);
1473
1712
  }
1474
1713
  function useCreateThread() {
1475
1714
  const room = useRoom();
1476
- return getCommentsRoom(room).useCreateThread();
1715
+ return commentsRoom.useCreateThread(room);
1477
1716
  }
1478
1717
  function useEditThreadMetadata() {
1479
1718
  const room = useRoom();
1480
- return getCommentsRoom(room).useEditThreadMetadata();
1719
+ return commentsRoom.useEditThreadMetadata(room);
1481
1720
  }
1482
1721
  function useAddReaction() {
1483
1722
  const room = useRoom();
1484
- return getCommentsRoom(room).useAddReaction();
1723
+ return commentsRoom.useAddReaction(room);
1485
1724
  }
1486
1725
  function useRemoveReaction() {
1487
1726
  const room = useRoom();
1488
- return getCommentsRoom(room).useRemoveReaction();
1727
+ return commentsRoom.useRemoveReaction(room);
1489
1728
  }
1490
1729
  function useCreateComment() {
1491
1730
  const room = useRoom();
1492
- return getCommentsRoom(room).useCreateComment();
1731
+ return commentsRoom.useCreateComment(room);
1493
1732
  }
1494
1733
  function useEditComment() {
1495
1734
  const room = useRoom();
1496
- return getCommentsRoom(room).useEditComment();
1735
+ return commentsRoom.useEditComment(room);
1497
1736
  }
1498
1737
  function useDeleteComment() {
1499
1738
  const room = useRoom();
1500
- return getCommentsRoom(room).useDeleteComment();
1739
+ return commentsRoom.useDeleteComment(room);
1501
1740
  }
1502
1741
  const { resolveUsers, resolveMentionSuggestions } = options ?? {};
1503
1742
  const usersCache = resolveUsers ? createAsyncCache(async (stringifiedOptions) => {
@@ -1508,12 +1747,12 @@ function createRoomContext(client, options) {
1508
1747
  }) : void 0;
1509
1748
  function useUser(userId) {
1510
1749
  const room = useRoom();
1511
- const resolverKey = React2.useMemo(
1512
- () => stringify({ userIds: [userId], roomId: room.id }),
1750
+ const resolverKey = React3.useMemo(
1751
+ () => stringify2({ userIds: [userId], roomId: room.id }),
1513
1752
  [userId, room.id]
1514
1753
  );
1515
1754
  const state = useAsyncCache(usersCache, resolverKey);
1516
- React2.useEffect(() => warnIfNoResolveUsers(usersCache), []);
1755
+ React3.useEffect(() => warnIfNoResolveUsers(usersCache), []);
1517
1756
  if (state.isLoading) {
1518
1757
  return {
1519
1758
  isLoading: true
@@ -1528,14 +1767,14 @@ function createRoomContext(client, options) {
1528
1767
  }
1529
1768
  function useUserSuspense(userId) {
1530
1769
  const room = useRoom();
1531
- const resolverKey = React2.useMemo(
1532
- () => stringify({ userIds: [userId], roomId: room.id }),
1770
+ const resolverKey = React3.useMemo(
1771
+ () => stringify2({ userIds: [userId], roomId: room.id }),
1533
1772
  [userId, room.id]
1534
1773
  );
1535
1774
  const state = useAsyncCache(usersCache, resolverKey, {
1536
1775
  suspense: true
1537
1776
  });
1538
- React2.useEffect(() => warnIfNoResolveUsers(usersCache), []);
1777
+ React3.useEffect(() => warnIfNoResolveUsers(usersCache), []);
1539
1778
  return {
1540
1779
  user: state.data,
1541
1780
  isLoading: false
@@ -1551,8 +1790,8 @@ function createRoomContext(client, options) {
1551
1790
  function useMentionSuggestions(search) {
1552
1791
  const room = useRoom();
1553
1792
  const debouncedSearch = useDebounce(search, 500);
1554
- const resolverKey = React2.useMemo(
1555
- () => debouncedSearch !== void 0 ? stringify({ text: debouncedSearch, roomId: room.id }) : null,
1793
+ const resolverKey = React3.useMemo(
1794
+ () => debouncedSearch !== void 0 ? stringify2({ text: debouncedSearch, roomId: room.id }) : null,
1556
1795
  [debouncedSearch, room.id]
1557
1796
  );
1558
1797
  const { data } = useAsyncCache(mentionSuggestionsCache, resolverKey, {