@liveblocks/react 1.9.2 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ var _core = require('@liveblocks/core');
5
5
 
6
6
  // src/version.ts
7
7
  var PKG_NAME = "@liveblocks/react";
8
- var PKG_VERSION = "1.9.2";
8
+ var PKG_VERSION = "1.9.3";
9
9
  var PKG_FORMAT = "cjs";
10
10
 
11
11
  // src/ClientSideSuspense.tsx
@@ -42,7 +42,6 @@ var _nanoid = require('nanoid');
42
42
 
43
43
 
44
44
 
45
- var _indexjs = require('use-sync-external-store/shim/index.js');
46
45
 
47
46
  // src/comments/errors.ts
48
47
  var CreateThreadError = class extends Error {
@@ -104,53 +103,6 @@ var RemoveReactionError = class extends Error {
104
103
 
105
104
  // src/comments/lib/revalidation.ts
106
105
 
107
-
108
- // src/comments/lib/use-is-document-visible.ts
109
-
110
- function useIsDocumentVisible() {
111
- const isVisible = _indexjs.useSyncExternalStore.call(void 0, subscribe, getSnapshot, getSnapshot);
112
- return isVisible;
113
- }
114
- function subscribe(onStoreChange) {
115
- document.addEventListener("visibilitychange", onStoreChange);
116
- return () => {
117
- document.removeEventListener("visibilitychange", onStoreChange);
118
- };
119
- }
120
- function getSnapshot() {
121
- const isDocumentDefined = typeof document !== "undefined";
122
- return isDocumentDefined ? document.visibilityState === "visible" : true;
123
- }
124
-
125
- // src/comments/lib/use-is-online.ts
126
-
127
-
128
- function useIsOnline() {
129
- const isOnlineRef = _react.useRef.call(void 0, true);
130
- const subscribe2 = _react.useCallback.call(void 0, (onStoreChange) => {
131
- function handleIsOnline() {
132
- isOnlineRef.current = true;
133
- onStoreChange();
134
- }
135
- function handleIsOffline() {
136
- isOnlineRef.current = false;
137
- onStoreChange();
138
- }
139
- window.addEventListener("online", handleIsOnline);
140
- window.addEventListener("offline", handleIsOffline);
141
- return () => {
142
- window.removeEventListener("online", handleIsOnline);
143
- window.removeEventListener("offline", handleIsOffline);
144
- };
145
- }, []);
146
- const getSnapshot2 = _react.useCallback.call(void 0, () => {
147
- return isOnlineRef.current;
148
- }, []);
149
- const isOnline = _indexjs.useSyncExternalStore.call(void 0, subscribe2, getSnapshot2, getSnapshot2);
150
- return isOnline;
151
- }
152
-
153
- // src/comments/lib/revalidation.ts
154
106
  var DEFAULT_ERROR_RETRY_INTERVAL = 5e3;
155
107
  var DEFAULT_MAX_ERROR_RETRY_COUNT = 5;
156
108
  var DEFAULT_DEDUPING_INTERVAL = 2e3;
@@ -283,122 +235,15 @@ function useMutate(manager, revalidateCache) {
283
235
  );
284
236
  return mutate;
285
237
  }
286
- function useAutomaticRevalidation(manager, revalidateCache, options = {}) {
287
- const isOnline = useIsOnline();
288
- const isDocumentVisible = useIsDocumentVisible();
289
- const {
290
- revalidateOnFocus = true,
291
- revalidateOnReconnect = true,
292
- refreshInterval = 0
293
- } = options;
294
- _react.useEffect.call(void 0, () => {
295
- let revalidationTimerId;
296
- function scheduleRevalidation() {
297
- if (refreshInterval === 0)
298
- return;
299
- revalidationTimerId = window.setTimeout(() => {
300
- if (isOnline && isDocumentVisible && !manager.getError()) {
301
- void revalidateCache({ shouldDedupe: true }).then(
302
- scheduleRevalidation
303
- );
304
- return;
305
- }
306
- scheduleRevalidation();
307
- }, refreshInterval);
308
- }
309
- scheduleRevalidation();
310
- return () => {
311
- window.clearTimeout(revalidationTimerId);
312
- };
313
- }, [revalidateCache, refreshInterval, isOnline, isDocumentVisible, manager]);
314
- _react.useEffect.call(void 0, () => {
315
- function handleIsOnline() {
316
- if (revalidateOnReconnect && isDocumentVisible) {
317
- void revalidateCache({ shouldDedupe: true });
318
- }
319
- }
320
- window.addEventListener("online", handleIsOnline);
321
- return () => {
322
- window.removeEventListener("online", handleIsOnline);
323
- };
324
- }, [revalidateCache, revalidateOnReconnect, isDocumentVisible]);
325
- _react.useEffect.call(void 0, () => {
326
- function handleVisibilityChange() {
327
- const isVisible = document.visibilityState === "visible";
328
- if (revalidateOnFocus && isVisible && isOnline) {
329
- void revalidateCache({ shouldDedupe: true });
330
- }
331
- }
332
- document.addEventListener("visibilitychange", handleVisibilityChange);
333
- return () => {
334
- document.removeEventListener("visibilitychange", handleVisibilityChange);
335
- };
336
- }, [revalidateCache, revalidateOnFocus, isOnline]);
337
- }
338
238
 
339
239
  // src/comments/CommentsRoom.tsx
340
- var POLLING_INTERVAL_REALTIME = 3e4;
341
- var POLLING_INTERVAL = 5e3;
342
240
  var THREAD_ID_PREFIX = "th";
343
241
  var COMMENT_ID_PREFIX = "cm";
344
242
  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
- (_nullishCoalesce(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 = _core.makeEventSource.call(void 0, );
393
- const subscribe2 = eventSource.subscribe;
394
- const getCache = (key) => cacheStates.get(key);
395
- const setCache = (key, value) => {
396
- cacheStates.set(key, value);
397
- };
243
+ const store = createClientCacheStore();
398
244
  const FetcherContext = _react.createContext.call(void 0, null);
399
- const CommentsEventSubscriptionContext = _react.createContext.call(void 0, () => {
400
- });
401
- function getThreads() {
245
+ const RoomManagerContext = _react.createContext.call(void 0, null);
246
+ function getThreads(manager) {
402
247
  const threads = manager.getCache();
403
248
  if (!threads) {
404
249
  throw new Error(
@@ -411,84 +256,54 @@ function createCommentsRoom(errorEventSource) {
411
256
  room,
412
257
  children
413
258
  }) {
414
- const commentsEventSubscribersCountRef = _react.useRef.call(void 0, 0);
415
- const commentsEventDisposerRef = _react.useRef.call(void 0, );
416
- const fetcher = _react.useCallback.call(void 0, async () => {
259
+ const manager = _react.useMemo.call(void 0, () => {
260
+ return createRoomRevalidationManager(room.id, {
261
+ getCache: store.getThreads,
262
+ setCache: store.setThreads
263
+ });
264
+ }, [room.id]);
265
+ const fetcher = React.default.useCallback(async () => {
266
+ const options = manager.getRevalidationManagers().filter(([key]) => manager.getReferenceCount(key) > 0).map(([_, manager2]) => manager2.getOptions());
417
267
  const responses = await Promise.all(
418
- Array.from(filterOptions.values()).map((info) => {
419
- return room.getThreads(info.options);
268
+ options.map(async (option) => {
269
+ return await room.getThreads(option);
420
270
  })
421
271
  );
422
272
  const threads = Array.from(
423
273
  new Map(responses.flat().map((thread) => [thread.id, thread])).values()
424
274
  );
425
275
  return threads;
426
- }, [room]);
276
+ }, [room, manager]);
427
277
  const revalidateCache = useRevalidateCache(manager, fetcher);
428
- const subscribeToCommentEvents = _react.useCallback.call(void 0, () => {
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
- _optionalChain([commentsEventDisposerRef, 'access', _ => _.current, 'optionalCall', _2 => _2()]);
442
- commentsEventDisposerRef.current = void 0;
443
- };
444
- }, [revalidateCache, room]);
445
- _react.useEffect.call(void 0, () => {
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
278
  _react.useEffect.call(void 0, () => {
476
- const unsubscribe = manager.subscribe("error", (error) => {
477
- for (const state of cacheStates.values()) {
478
- state.error = error;
479
- }
279
+ const unsubscribe = room.events.comments.subscribe(() => {
280
+ void revalidateCache({ shouldDedupe: false });
480
281
  });
481
282
  return () => {
482
283
  unsubscribe();
483
284
  };
484
- }, []);
485
- return /* @__PURE__ */ React.default.createElement(FetcherContext.Provider, { value: fetcher }, /* @__PURE__ */ React.default.createElement(
486
- CommentsEventSubscriptionContext.Provider,
487
- {
488
- value: subscribeToCommentEvents
489
- },
490
- children
491
- ));
285
+ }, [room, revalidateCache]);
286
+ return /* @__PURE__ */ React.default.createElement(FetcherContext.Provider, { value: fetcher }, /* @__PURE__ */ React.default.createElement(RoomManagerContext.Provider, { value: manager }, children));
287
+ }
288
+ function useRoomManager() {
289
+ const manager = _react.useContext.call(void 0, RoomManagerContext);
290
+ if (manager === null) {
291
+ throw new Error("CommentsRoomProvider is missing from the React tree.");
292
+ }
293
+ return manager;
294
+ }
295
+ function getUseThreadsRevalidationManager(options, roomManager) {
296
+ const key = _core.stringify.call(void 0, options);
297
+ const revalidationManager = roomManager.getRevalidationManager(key);
298
+ if (!revalidationManager) {
299
+ const useThreadsRevalidationManager = createUseThreadsRevalidationManager(
300
+ options,
301
+ roomManager
302
+ );
303
+ roomManager.setRevalidationmanager(key, useThreadsRevalidationManager);
304
+ return useThreadsRevalidationManager;
305
+ }
306
+ return revalidationManager;
492
307
  }
493
308
  function useThreadsFetcher() {
494
309
  const fetcher = _react.useContext.call(void 0, FetcherContext);
@@ -497,156 +312,147 @@ function createCommentsRoom(errorEventSource) {
497
312
  }
498
313
  return fetcher;
499
314
  }
500
- function _useThreads(room, key) {
501
- const fetcher = useThreadsFetcher();
502
- const revalidateCache = useRevalidateCache(manager, fetcher);
503
- const status = _indexjs.useSyncExternalStore.call(void 0,
504
- room.events.status.subscribe,
505
- room.getStatus,
506
- room.getStatus
507
- );
508
- const isOnline = useIsOnline();
509
- const isDocumentVisible = useIsDocumentVisible();
510
- const subscribeToCommentEvents = _react.useContext.call(void 0,
511
- CommentsEventSubscriptionContext
512
- );
513
- const interval = getPollingInterval(
514
- isOnline,
515
- isDocumentVisible,
516
- status === "connected"
517
- );
518
- useAutomaticRevalidation(manager, revalidateCache, {
519
- revalidateOnFocus: true,
520
- revalidateOnReconnect: true,
521
- refreshInterval: interval
522
- });
523
- _react.useEffect.call(void 0, subscribeToCommentEvents, [subscribeToCommentEvents]);
524
- const cache = _indexjs.useSyncExternalStore.call(void 0,
525
- subscribe2,
526
- () => getCache(key),
527
- () => getCache(key)
528
- );
529
- if (!cache || cache.isLoading) {
530
- return { isLoading: true };
531
- }
532
- return {
533
- isLoading: cache.isLoading,
534
- threads: cache.data || [],
535
- error: cache.error
536
- };
537
- }
538
315
  function useThreads(room, options = { query: { metadata: {} } }) {
539
316
  const key = _react.useMemo.call(void 0, () => _core.stringify.call(void 0, options), [options]);
540
- let revalidationManager = revalidationManagers.get(key);
541
- if (!revalidationManager) {
542
- revalidationManager = createThreadsRevalidationManager(key);
543
- revalidationManagers.set(key, revalidationManager);
544
- }
545
- const fetcher = _react.useCallback.call(void 0,
317
+ const manager = useRoomManager();
318
+ const useThreadsRevalidationManager = getUseThreadsRevalidationManager(
319
+ options,
320
+ manager
321
+ );
322
+ const fetcher = React.default.useCallback(
546
323
  () => {
547
324
  return room.getThreads(options);
548
325
  },
549
- // eslint-disable-next-line react-hooks/exhaustive-deps
550
- [key]
326
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- The missing dependency is `options` but `key` and `normalized` are analogous, so we only include `key` as dependency. This helps minimize the number of re-renders as `options` can change on each render
327
+ [key, room]
551
328
  );
552
- const revalidateCache = useRevalidateCache(revalidationManager, fetcher);
553
- _react.useEffect.call(void 0,
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]
329
+ const revalidateCache = useRevalidateCache(
330
+ useThreadsRevalidationManager,
331
+ fetcher
577
332
  );
578
333
  _react.useEffect.call(void 0, () => {
579
334
  void revalidateCache({ shouldDedupe: true });
580
335
  }, [revalidateCache]);
581
- return _useThreads(room, key);
336
+ _react.useEffect.call(void 0, () => {
337
+ manager.incrementReferenceCount(key);
338
+ return () => {
339
+ manager.decrementReferenceCount(key);
340
+ };
341
+ });
342
+ return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
343
+ store.subscribe,
344
+ () => store.getThreads(),
345
+ () => store.getThreads(),
346
+ (state) => {
347
+ const isLoading = useThreadsRevalidationManager.getIsLoading();
348
+ if (isLoading) {
349
+ return {
350
+ isLoading: true
351
+ };
352
+ }
353
+ const options2 = useThreadsRevalidationManager.getOptions();
354
+ const error = useThreadsRevalidationManager.getError();
355
+ const filtered = state.filter((thread) => {
356
+ if (thread.roomId !== room.id)
357
+ return false;
358
+ const query = _nullishCoalesce(options2.query, () => ( {}));
359
+ for (const key2 in query.metadata) {
360
+ if (thread.metadata[key2] !== query.metadata[key2]) {
361
+ return false;
362
+ }
363
+ }
364
+ return true;
365
+ });
366
+ return {
367
+ isLoading: false,
368
+ threads: filtered,
369
+ error
370
+ };
371
+ }
372
+ );
582
373
  }
583
- function useThreadsSuspense(room, options = {}) {
374
+ function useThreadsSuspense(room, options = { query: { metadata: {} } }) {
584
375
  const key = _react.useMemo.call(void 0, () => _core.stringify.call(void 0, options), [options]);
585
- let revalidationManager = revalidationManagers.get(key);
586
- if (!revalidationManager) {
587
- revalidationManager = createThreadsRevalidationManager(key);
588
- revalidationManagers.set(key, revalidationManager);
589
- }
590
- const fetcher = _react.useCallback.call(void 0,
376
+ const manager = useRoomManager();
377
+ const useThreadsRevalidationManager = getUseThreadsRevalidationManager(
378
+ options,
379
+ manager
380
+ );
381
+ const fetcher = React.default.useCallback(
591
382
  () => {
592
383
  return room.getThreads(options);
593
384
  },
594
- // eslint-disable-next-line react-hooks/exhaustive-deps
595
- [key]
385
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- The missing dependency is `options` but `key` and `normalized` are analogous, so we only include `key` as dependency. This helps minimize the number of re-renders as `options` can change on each render
386
+ [key, room]
596
387
  );
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
- _react.useEffect.call(void 0,
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
- });
388
+ const revalidateCache = useRevalidateCache(
389
+ useThreadsRevalidationManager,
390
+ fetcher
391
+ );
392
+ _react.useEffect.call(void 0, () => {
393
+ void revalidateCache({ shouldDedupe: true });
394
+ }, [revalidateCache]);
395
+ _react.useEffect.call(void 0, () => {
396
+ manager.incrementReferenceCount(key);
397
+ return () => {
398
+ manager.decrementReferenceCount(key);
399
+ };
400
+ });
401
+ const cache = _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
402
+ store.subscribe,
403
+ () => store.getThreads(),
404
+ () => store.getThreads(),
405
+ (state) => {
406
+ const isLoading = useThreadsRevalidationManager.getIsLoading();
407
+ if (isLoading) {
408
+ return {
409
+ isLoading: true
410
+ };
616
411
  }
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);
412
+ const options2 = useThreadsRevalidationManager.getOptions();
413
+ const error = useThreadsRevalidationManager.getError();
414
+ const filtered = state.filter((thread) => {
415
+ if (thread.roomId !== room.id)
416
+ return false;
417
+ const query = _nullishCoalesce(options2.query, () => ( {}));
418
+ for (const key2 in query.metadata) {
419
+ if (thread.metadata[key2] !== query.metadata[key2]) {
420
+ return false;
421
+ }
422
+ }
423
+ return true;
424
+ });
425
+ return {
426
+ isLoading: false,
427
+ threads: filtered,
428
+ error
625
429
  };
626
- },
627
- // eslint-disable-next-line react-hooks/exhaustive-deps
628
- [key]
430
+ }
629
431
  );
630
- const cache = _useThreads(room, key);
631
432
  if (cache.error) {
632
433
  throw cache.error;
633
434
  }
634
435
  if (cache.isLoading || !cache.threads) {
635
- throw revalidateCache({ shouldDedupe: true });
436
+ throw revalidateCache({
437
+ shouldDedupe: true
438
+ });
636
439
  }
637
440
  return {
441
+ isLoading: false,
638
442
  threads: cache.threads,
639
- isLoading: false
443
+ error: cache.error
640
444
  };
641
445
  }
642
446
  function useEditThreadMetadata(room) {
643
- const revalidate = useRevalidateCache(manager, room.getThreads);
447
+ const manager = useRoomManager();
448
+ const fetcher = useThreadsFetcher();
449
+ const revalidate = useRevalidateCache(manager, fetcher);
644
450
  const mutate = useMutate(manager, revalidate);
645
451
  const editThreadMetadata = _react.useCallback.call(void 0,
646
452
  (options) => {
647
453
  const threadId = options.threadId;
648
454
  const metadata = "metadata" in options ? options.metadata : {};
649
- const threads = getThreads();
455
+ const threads = getThreads(manager);
650
456
  const optimisticData = threads.map(
651
457
  (thread) => thread.id === threadId ? {
652
458
  ...thread,
@@ -672,11 +478,12 @@ function createCommentsRoom(errorEventSource) {
672
478
  );
673
479
  });
674
480
  },
675
- [room, mutate]
481
+ [room, mutate, manager]
676
482
  );
677
483
  return editThreadMetadata;
678
484
  }
679
485
  function useCreateThread(room) {
486
+ const manager = useRoomManager();
680
487
  const fetcher = useThreadsFetcher();
681
488
  const revalidate = useRevalidateCache(manager, fetcher);
682
489
  const mutate = useMutate(manager, revalidate);
@@ -684,7 +491,7 @@ function createCommentsRoom(errorEventSource) {
684
491
  (options) => {
685
492
  const body = options.body;
686
493
  const metadata = "metadata" in options ? options.metadata : {};
687
- const threads = getThreads();
494
+ const threads = getThreads(manager);
688
495
  const threadId = createOptimisticId(THREAD_ID_PREFIX);
689
496
  const commentId = createOptimisticId(COMMENT_ID_PREFIX);
690
497
  const now = /* @__PURE__ */ new Date();
@@ -725,17 +532,18 @@ function createCommentsRoom(errorEventSource) {
725
532
  });
726
533
  return newThread;
727
534
  },
728
- [room, mutate]
535
+ [room, mutate, manager]
729
536
  );
730
537
  return createThread;
731
538
  }
732
539
  function useCreateComment(room) {
540
+ const manager = useRoomManager();
733
541
  const fetcher = useThreadsFetcher();
734
542
  const revalidate = useRevalidateCache(manager, fetcher);
735
543
  const mutate = useMutate(manager, revalidate);
736
544
  const createComment = _react.useCallback.call(void 0,
737
545
  ({ threadId, body }) => {
738
- const threads = getThreads();
546
+ const threads = getThreads(manager);
739
547
  const commentId = createOptimisticId(COMMENT_ID_PREFIX);
740
548
  const now = /* @__PURE__ */ new Date();
741
549
  const comment = {
@@ -772,16 +580,18 @@ function createCommentsRoom(errorEventSource) {
772
580
  });
773
581
  return comment;
774
582
  },
775
- [room, mutate]
583
+ [room, mutate, manager]
776
584
  );
777
585
  return createComment;
778
586
  }
779
587
  function useEditComment(room) {
780
- const revalidate = useRevalidateCache(manager, room.getThreads);
588
+ const manager = useRoomManager();
589
+ const fetcher = useThreadsFetcher();
590
+ const revalidate = useRevalidateCache(manager, fetcher);
781
591
  const mutate = useMutate(manager, revalidate);
782
592
  const editComment = _react.useCallback.call(void 0,
783
593
  ({ threadId, commentId, body }) => {
784
- const threads = getThreads();
594
+ const threads = getThreads(manager);
785
595
  const now = /* @__PURE__ */ new Date();
786
596
  const optimisticData = threads.map(
787
597
  (thread) => thread.id === threadId ? {
@@ -812,16 +622,18 @@ function createCommentsRoom(errorEventSource) {
812
622
  );
813
623
  });
814
624
  },
815
- [room, mutate]
625
+ [room, mutate, manager]
816
626
  );
817
627
  return editComment;
818
628
  }
819
629
  function useDeleteComment(room) {
820
- const revalidate = useRevalidateCache(manager, room.getThreads);
630
+ const manager = useRoomManager();
631
+ const fetcher = useThreadsFetcher();
632
+ const revalidate = useRevalidateCache(manager, fetcher);
821
633
  const mutate = useMutate(manager, revalidate);
822
634
  const deleteComment = _react.useCallback.call(void 0,
823
635
  ({ threadId, commentId }) => {
824
- const threads = getThreads();
636
+ const threads = getThreads(manager);
825
637
  const now = /* @__PURE__ */ new Date();
826
638
  const newThreads = [];
827
639
  for (const thread of threads) {
@@ -861,16 +673,18 @@ function createCommentsRoom(errorEventSource) {
861
673
  );
862
674
  });
863
675
  },
864
- [room, mutate]
676
+ [room, mutate, manager]
865
677
  );
866
678
  return deleteComment;
867
679
  }
868
680
  function useAddReaction(room) {
869
- const revalidate = useRevalidateCache(manager, room.getThreads);
681
+ const manager = useRoomManager();
682
+ const fetcher = useThreadsFetcher();
683
+ const revalidate = useRevalidateCache(manager, fetcher);
870
684
  const mutate = useMutate(manager, revalidate);
871
685
  const createComment = _react.useCallback.call(void 0,
872
686
  ({ threadId, commentId, emoji }) => {
873
- const threads = getThreads();
687
+ const threads = getThreads(manager);
874
688
  const now = /* @__PURE__ */ new Date();
875
689
  const userId = getCurrentUserId(room);
876
690
  const optimisticData = threads.map(
@@ -924,16 +738,18 @@ function createCommentsRoom(errorEventSource) {
924
738
  );
925
739
  });
926
740
  },
927
- [room, mutate]
741
+ [room, mutate, manager]
928
742
  );
929
743
  return createComment;
930
744
  }
931
745
  function useRemoveReaction(room) {
932
- const revalidate = useRevalidateCache(manager, room.getThreads);
746
+ const manager = useRoomManager();
747
+ const fetcher = useThreadsFetcher();
748
+ const revalidate = useRevalidateCache(manager, fetcher);
933
749
  const mutate = useMutate(manager, revalidate);
934
750
  const createComment = _react.useCallback.call(void 0,
935
751
  ({ threadId, commentId, emoji }) => {
936
- const threads = getThreads();
752
+ const threads = getThreads(manager);
937
753
  const userId = getCurrentUserId(room);
938
754
  const optimisticData = threads.map(
939
755
  (thread) => thread.id === threadId ? {
@@ -985,7 +801,7 @@ function createCommentsRoom(errorEventSource) {
985
801
  );
986
802
  });
987
803
  },
988
- [room, mutate]
804
+ [room, mutate, manager]
989
805
  );
990
806
  return createComment;
991
807
  }
@@ -1015,37 +831,41 @@ function getCurrentUserId(room) {
1015
831
  }
1016
832
  function handleCommentsApiError(err) {
1017
833
  const message = `Request failed with status ${err.status}: ${err.message}`;
1018
- if (_optionalChain([err, 'access', _3 => _3.details, 'optionalAccess', _4 => _4.error]) === "FORBIDDEN") {
834
+ if (_optionalChain([err, 'access', _2 => _2.details, 'optionalAccess', _3 => _3.error]) === "FORBIDDEN") {
1019
835
  const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
1020
836
  console.error(detailedMessage);
1021
837
  }
1022
838
  return new Error(message);
1023
839
  }
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;
840
+ function createRoomRevalidationManager(roomId, {
841
+ getCache,
842
+ setCache
843
+ }) {
1033
844
  let request;
1034
845
  let error;
1035
846
  let mutation;
1036
- const cacheEventSource = _core.makeEventSource.call(void 0, );
1037
- const errorEventSource = _core.makeEventSource.call(void 0, );
847
+ const revalidationManagerByOptions = /* @__PURE__ */ new Map();
848
+ const referenceCountByOptions = /* @__PURE__ */ new Map();
1038
849
  return {
1039
850
  // Cache
1040
851
  getCache() {
1041
- return cache;
852
+ const threads = getCache();
853
+ const filtered = threads.filter((thread) => thread.roomId === roomId);
854
+ return filtered;
1042
855
  },
1043
856
  setCache(value) {
857
+ for (const key of revalidationManagerByOptions.keys()) {
858
+ if (referenceCountByOptions.get(key) === 0) {
859
+ revalidationManagerByOptions.delete(key);
860
+ referenceCountByOptions.delete(key);
861
+ }
862
+ }
1044
863
  const sorted = value.sort(
1045
864
  (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1046
865
  );
1047
- cache = sorted;
1048
- cacheEventSource.notify(cache);
866
+ const threads = getCache();
867
+ const newThreads = threads.filter((thread) => thread.roomId !== roomId).concat(sorted);
868
+ setCache(newThreads);
1049
869
  },
1050
870
  // Request
1051
871
  getRequest() {
@@ -1060,7 +880,6 @@ function createThreadsCacheManager() {
1060
880
  },
1061
881
  setError(err) {
1062
882
  error = err;
1063
- errorEventSource.notify(err);
1064
883
  },
1065
884
  // Mutation
1066
885
  getMutation() {
@@ -1069,16 +888,94 @@ function createThreadsCacheManager() {
1069
888
  setMutation(info) {
1070
889
  mutation = info;
1071
890
  },
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);
891
+ getRevalidationManagers() {
892
+ return Array.from(revalidationManagerByOptions.entries());
893
+ },
894
+ getRevalidationManager(key) {
895
+ return revalidationManagerByOptions.get(key);
896
+ },
897
+ setRevalidationmanager(key, manager) {
898
+ revalidationManagerByOptions.set(key, manager);
899
+ },
900
+ incrementReferenceCount(key) {
901
+ const count = _nullishCoalesce(referenceCountByOptions.get(key), () => ( 0));
902
+ referenceCountByOptions.set(key, count + 1);
903
+ },
904
+ decrementReferenceCount(key) {
905
+ const count = _nullishCoalesce(referenceCountByOptions.get(key), () => ( 0));
906
+ referenceCountByOptions.set(key, count - 1);
907
+ },
908
+ getReferenceCount(key) {
909
+ return _nullishCoalesce(referenceCountByOptions.get(key), () => ( 0));
910
+ }
911
+ };
912
+ }
913
+ function createClientCacheStore() {
914
+ let threads = [];
915
+ const threadsEventSource = _core.makeEventSource.call(void 0, );
916
+ return {
917
+ getThreads() {
918
+ return threads;
919
+ },
920
+ setThreads(value) {
921
+ threads = value;
922
+ threadsEventSource.notify(threads);
923
+ },
924
+ subscribe(callback) {
925
+ return threadsEventSource.subscribe(callback);
926
+ }
927
+ };
928
+ }
929
+ function createUseThreadsRevalidationManager(options, manager) {
930
+ let isLoading = true;
931
+ let request;
932
+ let error;
933
+ const errorEventSource = _core.makeEventSource.call(void 0, );
934
+ return {
935
+ // Cache
936
+ getCache() {
937
+ return void 0;
938
+ },
939
+ setCache(value) {
940
+ const cache = new Map(
941
+ (_nullishCoalesce(manager.getCache(), () => ( []))).map((thread) => [thread.id, thread])
942
+ );
943
+ for (const thread of value) {
944
+ cache.set(thread.id, thread);
1081
945
  }
946
+ manager.setCache(Array.from(cache.values()));
947
+ isLoading = false;
948
+ },
949
+ // Request
950
+ getRequest() {
951
+ return request;
952
+ },
953
+ setRequest(value) {
954
+ request = value;
955
+ },
956
+ // Error
957
+ getError() {
958
+ return error;
959
+ },
960
+ setError(err) {
961
+ error = err;
962
+ errorEventSource.notify(err);
963
+ },
964
+ // Mutation
965
+ getMutation() {
966
+ return void 0;
967
+ },
968
+ setMutation(_) {
969
+ return;
970
+ },
971
+ getOptions() {
972
+ return options;
973
+ },
974
+ getIsLoading() {
975
+ return isLoading;
976
+ },
977
+ setIsLoading(value) {
978
+ isLoading = value;
1082
979
  }
1083
980
  };
1084
981
  }
@@ -1109,7 +1006,7 @@ function useDebounce(value, delay = DEFAULT_DELAY) {
1109
1006
 
1110
1007
  // src/lib/use-async-cache.ts
1111
1008
 
1112
-
1009
+ var _indexjs = require('use-sync-external-store/shim/index.js');
1113
1010
 
1114
1011
  // src/lib/use-initial.ts
1115
1012
 
@@ -1135,16 +1032,16 @@ function useAsyncCache(cache, key, options) {
1135
1032
  void cacheItem2.get();
1136
1033
  return cacheItem2;
1137
1034
  }, [cache, key]);
1138
- const subscribe2 = _react.useCallback.call(void 0,
1139
- (callback) => _nullishCoalesce(_optionalChain([cacheItem, 'optionalAccess', _5 => _5.subscribe, 'call', _6 => _6(callback)]), () => ( noop)),
1035
+ const subscribe = _react.useCallback.call(void 0,
1036
+ (callback) => _nullishCoalesce(_optionalChain([cacheItem, 'optionalAccess', _4 => _4.subscribe, 'call', _5 => _5(callback)]), () => ( noop)),
1140
1037
  [cacheItem]
1141
1038
  );
1142
1039
  const getState = _react.useCallback.call(void 0,
1143
- () => _nullishCoalesce(_optionalChain([cacheItem, 'optionalAccess', _7 => _7.getState, 'call', _8 => _8()]), () => ( INITIAL_ASYNC_STATE)),
1040
+ () => _nullishCoalesce(_optionalChain([cacheItem, 'optionalAccess', _6 => _6.getState, 'call', _7 => _7()]), () => ( INITIAL_ASYNC_STATE)),
1144
1041
  [cacheItem]
1145
1042
  );
1146
- const revalidate = _react.useCallback.call(void 0, () => _optionalChain([cacheItem, 'optionalAccess', _9 => _9.revalidate, 'call', _10 => _10()]), [cacheItem]);
1147
- const state = _indexjs.useSyncExternalStore.call(void 0, subscribe2, getState, getState);
1043
+ const revalidate = _react.useCallback.call(void 0, () => _optionalChain([cacheItem, 'optionalAccess', _8 => _8.revalidate, 'call', _9 => _9()]), [cacheItem]);
1044
+ const state = _indexjs.useSyncExternalStore.call(void 0, subscribe, getState, getState);
1148
1045
  const previousData = _react.useRef.call(void 0, );
1149
1046
  let data = state.data;
1150
1047
  _react.useEffect.call(void 0, () => {
@@ -1159,7 +1056,7 @@ function useAsyncCache(cache, key, options) {
1159
1056
  revalidate
1160
1057
  };
1161
1058
  }
1162
- if (_optionalChain([frozenOptions, 'optionalAccess', _11 => _11.suspense])) {
1059
+ if (_optionalChain([frozenOptions, 'optionalAccess', _10 => _10.suspense])) {
1163
1060
  const error = getState().error;
1164
1061
  if (error) {
1165
1062
  throw error;
@@ -1173,7 +1070,7 @@ function useAsyncCache(cache, key, options) {
1173
1070
  });
1174
1071
  }
1175
1072
  }
1176
- if (state.isLoading && _optionalChain([frozenOptions, 'optionalAccess', _12 => _12.keepPreviousDataWhileLoading]) && typeof state.data === "undefined" && _optionalChain([previousData, 'access', _13 => _13.current, 'optionalAccess', _14 => _14.key]) !== key && typeof _optionalChain([previousData, 'access', _15 => _15.current, 'optionalAccess', _16 => _16.data]) !== "undefined") {
1073
+ if (state.isLoading && _optionalChain([frozenOptions, 'optionalAccess', _11 => _11.keepPreviousDataWhileLoading]) && typeof state.data === "undefined" && _optionalChain([previousData, 'access', _12 => _12.current, 'optionalAccess', _13 => _13.key]) !== key && typeof _optionalChain([previousData, 'access', _14 => _14.current, 'optionalAccess', _15 => _15.data]) !== "undefined") {
1177
1074
  data = previousData.current.data;
1178
1075
  }
1179
1076
  return {
@@ -1224,7 +1121,7 @@ var missing_unstable_batchedUpdates = (reactVersion, roomId) => `We noticed you\
1224
1121
 
1225
1122
  Why? Please see https://liveblocks.io/docs/platform/troubleshooting#stale-props-zombie-child for more information`;
1226
1123
  var superfluous_unstable_batchedUpdates = "You don\u2019t need to pass unstable_batchedUpdates to RoomProvider anymore, since you\u2019re on React 18+ already.";
1227
- function useSyncExternalStore5(s, gs, gss) {
1124
+ function useSyncExternalStore2(s, gs, gss) {
1228
1125
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0, s, gs, gss, identity);
1229
1126
  }
1230
1127
  var STABLE_EMPTY_LIST = Object.freeze([]);
@@ -1373,16 +1270,16 @@ function createRoomContext(client, options) {
1373
1270
  }
1374
1271
  function useStatus() {
1375
1272
  const room = useRoom();
1376
- const subscribe2 = room.events.status.subscribe;
1377
- const getSnapshot2 = room.getStatus;
1273
+ const subscribe = room.events.status.subscribe;
1274
+ const getSnapshot = room.getStatus;
1378
1275
  const getServerSnapshot = room.getStatus;
1379
- return useSyncExternalStore5(subscribe2, getSnapshot2, getServerSnapshot);
1276
+ return useSyncExternalStore2(subscribe, getSnapshot, getServerSnapshot);
1380
1277
  }
1381
1278
  function useMyPresence() {
1382
1279
  const room = useRoom();
1383
- const subscribe2 = room.events.myPresence.subscribe;
1384
- const getSnapshot2 = room.getPresence;
1385
- const presence = useSyncExternalStore5(subscribe2, getSnapshot2, getSnapshot2);
1280
+ const subscribe = room.events.myPresence.subscribe;
1281
+ const getSnapshot = room.getPresence;
1282
+ const presence = useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
1386
1283
  const setPresence = room.updatePresence;
1387
1284
  return [presence, setPresence];
1388
1285
  }
@@ -1391,12 +1288,12 @@ function createRoomContext(client, options) {
1391
1288
  }
1392
1289
  function useOthers(selector, isEqual) {
1393
1290
  const room = useRoom();
1394
- const subscribe2 = room.events.others.subscribe;
1395
- const getSnapshot2 = room.getOthers;
1291
+ const subscribe = room.events.others.subscribe;
1292
+ const getSnapshot = room.getOthers;
1396
1293
  const getServerSnapshot = alwaysEmptyList;
1397
1294
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1398
- subscribe2,
1399
- getSnapshot2,
1295
+ subscribe,
1296
+ getSnapshot,
1400
1297
  getServerSnapshot,
1401
1298
  _nullishCoalesce(selector, () => ( identity)),
1402
1299
  isEqual
@@ -1500,8 +1397,8 @@ function createRoomContext(client, options) {
1500
1397
  }
1501
1398
  function useSelf(maybeSelector, isEqual) {
1502
1399
  const room = useRoom();
1503
- const subscribe2 = room.events.self.subscribe;
1504
- const getSnapshot2 = room.getSelf;
1400
+ const subscribe = room.events.self.subscribe;
1401
+ const getSnapshot = room.getSelf;
1505
1402
  const selector = _nullishCoalesce(maybeSelector, () => ( identity));
1506
1403
  const wrappedSelector = React3.useCallback(
1507
1404
  (me) => me !== null ? selector(me) : null,
@@ -1509,8 +1406,8 @@ function createRoomContext(client, options) {
1509
1406
  );
1510
1407
  const getServerSnapshot = alwaysNull;
1511
1408
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1512
- subscribe2,
1513
- getSnapshot2,
1409
+ subscribe,
1410
+ getSnapshot,
1514
1411
  getServerSnapshot,
1515
1412
  wrappedSelector,
1516
1413
  isEqual
@@ -1518,10 +1415,10 @@ function createRoomContext(client, options) {
1518
1415
  }
1519
1416
  function useMutableStorageRoot() {
1520
1417
  const room = useRoom();
1521
- const subscribe2 = room.events.storageDidLoad.subscribeOnce;
1522
- const getSnapshot2 = room.getStorageSnapshot;
1418
+ const subscribe = room.events.storageDidLoad.subscribeOnce;
1419
+ const getSnapshot = room.getStorageSnapshot;
1523
1420
  const getServerSnapshot = alwaysNull;
1524
- return useSyncExternalStore5(subscribe2, getSnapshot2, getServerSnapshot);
1421
+ return useSyncExternalStore2(subscribe, getSnapshot, getServerSnapshot);
1525
1422
  }
1526
1423
  function useStorageRoot() {
1527
1424
  return [useMutableStorageRoot()];
@@ -1537,15 +1434,15 @@ function createRoomContext(client, options) {
1537
1434
  }
1538
1435
  function useCanUndo() {
1539
1436
  const room = useRoom();
1540
- const subscribe2 = room.events.history.subscribe;
1437
+ const subscribe = room.events.history.subscribe;
1541
1438
  const canUndo = room.history.canUndo;
1542
- return useSyncExternalStore5(subscribe2, canUndo, canUndo);
1439
+ return useSyncExternalStore2(subscribe, canUndo, canUndo);
1543
1440
  }
1544
1441
  function useCanRedo() {
1545
1442
  const room = useRoom();
1546
- const subscribe2 = room.events.history.subscribe;
1443
+ const subscribe = room.events.history.subscribe;
1547
1444
  const canRedo = room.history.canRedo;
1548
- return useSyncExternalStore5(subscribe2, canRedo, canRedo);
1445
+ return useSyncExternalStore2(subscribe, canRedo, canRedo);
1549
1446
  }
1550
1447
  function useBatch() {
1551
1448
  return useRoom().batch;
@@ -1567,7 +1464,7 @@ function createRoomContext(client, options) {
1567
1464
  function onRootChange() {
1568
1465
  const newValue = root.get(key);
1569
1466
  if (newValue !== curr) {
1570
- _optionalChain([unsubCurr, 'optionalCall', _17 => _17()]);
1467
+ _optionalChain([unsubCurr, 'optionalCall', _16 => _16()]);
1571
1468
  curr = newValue;
1572
1469
  subscribeToCurr();
1573
1470
  rerender();
@@ -1578,7 +1475,7 @@ function createRoomContext(client, options) {
1578
1475
  const unsubscribeRoot = room.subscribe(root, onRootChange);
1579
1476
  return () => {
1580
1477
  unsubscribeRoot();
1581
- _optionalChain([unsubCurr, 'optionalCall', _18 => _18()]);
1478
+ _optionalChain([unsubCurr, 'optionalCall', _17 => _17()]);
1582
1479
  };
1583
1480
  }, [rootOrNull, room, key, rerender]);
1584
1481
  if (rootOrNull === null) {
@@ -1594,11 +1491,11 @@ function createRoomContext(client, options) {
1594
1491
  (rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
1595
1492
  [selector]
1596
1493
  );
1597
- const subscribe2 = React3.useCallback(
1494
+ const subscribe = React3.useCallback(
1598
1495
  (onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop2,
1599
1496
  [room, rootOrNull]
1600
1497
  );
1601
- const getSnapshot2 = React3.useCallback(() => {
1498
+ const getSnapshot = React3.useCallback(() => {
1602
1499
  if (rootOrNull === null) {
1603
1500
  return null;
1604
1501
  } else {
@@ -1609,8 +1506,8 @@ function createRoomContext(client, options) {
1609
1506
  }, [rootOrNull]);
1610
1507
  const getServerSnapshot = alwaysNull;
1611
1508
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0,
1612
- subscribe2,
1613
- getSnapshot2,
1509
+ subscribe,
1510
+ getSnapshot,
1614
1511
  getServerSnapshot,
1615
1512
  wrappedSelector,
1616
1513
  isEqual
@@ -1743,7 +1640,7 @@ function createRoomContext(client, options) {
1743
1640
  const users = await resolveUsers(
1744
1641
  JSON.parse(stringifiedOptions)
1745
1642
  );
1746
- return _optionalChain([users, 'optionalAccess', _19 => _19[0]]);
1643
+ return _optionalChain([users, 'optionalAccess', _18 => _18[0]]);
1747
1644
  }) : void 0;
1748
1645
  function useUser(userId) {
1749
1646
  const room = useRoom();