@liveblocks/react 2.15.1 → 2.16.0-rc1

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.
@@ -85,6 +85,18 @@ function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnaps
85
85
  return value;
86
86
  }
87
87
 
88
+ // src/use-signal.ts
89
+ var identity = (value) => value;
90
+ function useSignal(signal, selector, isEqual) {
91
+ return useSyncExternalStoreWithSelector(
92
+ signal.subscribe,
93
+ signal.get,
94
+ signal.get,
95
+ _nullishCoalesce(selector, () => ( identity)),
96
+ isEqual
97
+ );
98
+ }
99
+
88
100
  // src/liveblocks.tsx
89
101
 
90
102
 
@@ -121,19 +133,30 @@ var config = {
121
133
  NOTIFICATION_SETTINGS_MAX_STALE_TIME: 5 * SECONDS
122
134
  };
123
135
 
124
- // src/lib/shallow2.ts
136
+ // src/lib/AsyncResult.ts
137
+ var ASYNC_LOADING = Object.freeze({ isLoading: true });
138
+ var ASYNC_ERR = (error) => Object.freeze({ isLoading: false, error });
139
+ function ASYNC_OK(fieldOrData, data) {
140
+ if (arguments.length === 1) {
141
+ return Object.freeze({ isLoading: false, data: fieldOrData });
142
+ } else {
143
+ return Object.freeze({ isLoading: false, [fieldOrData]: data });
144
+ }
145
+ }
125
146
 
126
- function shallow2(a, b) {
127
- if (!_core.isPlainObject.call(void 0, a) || !_core.isPlainObject.call(void 0, b)) {
128
- return _core.shallow.call(void 0, a, b);
147
+ // src/lib/itertools.ts
148
+ function find(it, predicate) {
149
+ for (const item of it) {
150
+ if (predicate(item)) return item;
129
151
  }
130
- const keysA = Object.keys(a);
131
- if (keysA.length !== Object.keys(b).length) {
132
- return false;
152
+ return void 0;
153
+ }
154
+ function count(it, predicate) {
155
+ let total = 0;
156
+ for (const item of it) {
157
+ if (predicate(item)) total++;
133
158
  }
134
- return keysA.every(
135
- (key) => Object.prototype.hasOwnProperty.call(b, key) && _core.shallow.call(void 0, a[key], b[key])
136
- );
159
+ return total;
137
160
  }
138
161
 
139
162
  // src/lib/use-initial.ts
@@ -210,7 +233,6 @@ var use = (
210
233
 
211
234
 
212
235
 
213
-
214
236
  // src/lib/autobind.ts
215
237
  function autobind(self) {
216
238
  const seen = /* @__PURE__ */ new Set();
@@ -228,27 +250,26 @@ function autobind(self) {
228
250
  } while ((obj = Reflect.getPrototypeOf(obj)) && obj !== Object.prototype);
229
251
  }
230
252
 
231
- // src/lib/itertools.ts
232
- function find(it, predicate) {
233
- for (const item of it) {
234
- if (predicate(item)) return item;
253
+ // src/lib/shallow2.ts
254
+
255
+ function shallow2(a, b) {
256
+ if (!_core.isPlainObject.call(void 0, a) || !_core.isPlainObject.call(void 0, b)) {
257
+ return _core.shallow.call(void 0, a, b);
235
258
  }
236
- return void 0;
259
+ const keysA = Object.keys(a);
260
+ if (keysA.length !== Object.keys(b).length) {
261
+ return false;
262
+ }
263
+ return keysA.every(
264
+ (key) => Object.prototype.hasOwnProperty.call(b, key) && _core.shallow.call(void 0, a[key], b[key])
265
+ );
237
266
  }
238
267
 
239
268
  // src/ThreadDB.ts
240
269
 
241
270
 
242
- // src/lib/guards.ts
243
-
244
- function isStartsWith(blob) {
245
- return _core.isPlainObject.call(void 0, blob) && isString(blob.startsWith);
246
- }
247
- function isString(value) {
248
- return typeof value === "string";
249
- }
250
-
251
271
  // src/lib/querying.ts
272
+
252
273
  function makeThreadsFilter(query) {
253
274
  return (thread) => matchesQuery(thread, query) && matchesMetadata(thread, query);
254
275
  }
@@ -259,17 +280,17 @@ function matchesMetadata(thread, q) {
259
280
  const metadata = thread.metadata;
260
281
  return q.metadata === void 0 || Object.entries(q.metadata).every(
261
282
  ([key, op]) => (
262
- // NOTE: `op` can be explicitly-`undefined` here, which ideally would not
263
- // mean "filter for absence" like it does now, as this does not match the
264
- // backend behavior at the moment. For an in-depth discussion, see
265
- // https://liveblocks.slack.com/archives/C02PZL7QAAW/p1728546988505989
266
- matchesOperator(metadata[key], op)
283
+ // Ignore explicit-undefined filters
284
+ // Boolean logic: op? => value matches the operator
285
+ op === void 0 || matchesOperator(metadata[key], op)
267
286
  )
268
287
  );
269
288
  }
270
289
  function matchesOperator(value, op) {
271
- if (isStartsWith(op)) {
272
- return isString(value) && value.startsWith(op.startsWith);
290
+ if (op === null) {
291
+ return value === void 0;
292
+ } else if (_core.isStartsWithOperator.call(void 0, op)) {
293
+ return typeof value === "string" && value.startsWith(op.startsWith);
273
294
  } else {
274
295
  return value === op;
275
296
  }
@@ -355,12 +376,12 @@ var ThreadDB = class _ThreadDB {
355
376
  this.upsert(thread);
356
377
  }
357
378
  }
358
- applyDelta(updates) {
379
+ applyDelta(newThreads, deletedThreads) {
359
380
  _core.batch.call(void 0, () => {
360
- for (const thread of updates.newThreads) {
381
+ for (const thread of newThreads) {
361
382
  this.upsertIfNewer(thread);
362
383
  }
363
- for (const { id, deletedAt } of updates.deletedThreads) {
384
+ for (const { id, deletedAt } of deletedThreads) {
364
385
  const existing = this.getEvenIfDeleted(id);
365
386
  if (!existing) continue;
366
387
  this.delete(id, deletedAt);
@@ -401,16 +422,10 @@ var ThreadDB = class _ThreadDB {
401
422
 
402
423
  // src/umbrella-store.ts
403
424
  function makeRoomThreadsQueryKey(roomId, query) {
404
- return `${roomId}-${_core.stringify.call(void 0, _nullishCoalesce(query, () => ( {})))}`;
425
+ return _core.stringify.call(void 0, [roomId, _nullishCoalesce(query, () => ( {}))]);
405
426
  }
406
427
  function makeUserThreadsQueryKey(query) {
407
- return `USER_THREADS:${_core.stringify.call(void 0, _nullishCoalesce(query, () => ( {})))}`;
408
- }
409
- function makeNotificationSettingsQueryKey(roomId) {
410
- return `${roomId}:NOTIFICATION_SETTINGS`;
411
- }
412
- function makeVersionsQueryKey(roomId) {
413
- return `${roomId}-VERSIONS`;
428
+ return _core.stringify.call(void 0, _nullishCoalesce(query, () => ( {})));
414
429
  }
415
430
  function usify(promise) {
416
431
  if ("status" in promise) {
@@ -431,53 +446,50 @@ function usify(promise) {
431
446
  return usable;
432
447
  }
433
448
  var noop2 = Promise.resolve();
434
- var ASYNC_LOADING = Object.freeze({ isLoading: true });
435
449
  var PaginatedResource = class {
450
+ #signal;
436
451
 
437
- #eventSource;
438
452
  #fetchPage;
439
- #paginationState;
440
- // Should be null while in loading or error state!
441
453
  #pendingFetchMore;
442
454
  constructor(fetchPage) {
443
- this.#paginationState = null;
455
+ this.#signal = new (0, _core.Signal)(ASYNC_LOADING);
444
456
  this.#fetchPage = fetchPage;
445
- this.#eventSource = _core.makeEventSource.call(void 0, );
446
457
  this.#pendingFetchMore = null;
447
- this.observable = this.#eventSource.observable;
458
+ this.signal = this.#signal.asReadonly();
448
459
  autobind(this);
449
460
  }
450
- #patchPaginationState(patch) {
451
- const state = this.#paginationState;
452
- if (state === null) return;
453
- this.#paginationState = { ...state, ...patch };
454
- this.#eventSource.notify();
461
+ get() {
462
+ return this.#signal.get();
463
+ }
464
+ #patch(patch) {
465
+ const state = this.#signal.get();
466
+ if (state.data === void 0) return;
467
+ this.#signal.set(ASYNC_OK({ ...state.data, ...patch }));
455
468
  }
456
469
  async #fetchMore() {
457
- const state = this.#paginationState;
458
- if (!_optionalChain([state, 'optionalAccess', _3 => _3.cursor])) {
470
+ const state = this.#signal.get();
471
+ if (!_optionalChain([state, 'access', _3 => _3.data, 'optionalAccess', _4 => _4.cursor]) || state.data.isFetchingMore) {
459
472
  return;
460
473
  }
461
- this.#patchPaginationState({ isFetchingMore: true });
474
+ this.#patch({ isFetchingMore: true });
462
475
  try {
463
- const nextCursor = await this.#fetchPage(state.cursor);
464
- this.#patchPaginationState({
476
+ const nextCursor = await this.#fetchPage(state.data.cursor);
477
+ this.#patch({
465
478
  cursor: nextCursor,
479
+ hasFetchedAll: nextCursor === null,
466
480
  fetchMoreError: void 0,
467
481
  isFetchingMore: false
468
482
  });
469
483
  } catch (err) {
470
- this.#patchPaginationState({
484
+ this.#patch({
471
485
  isFetchingMore: false,
472
486
  fetchMoreError: err
473
487
  });
474
488
  }
475
489
  }
476
490
  fetchMore() {
477
- const state = this.#paginationState;
478
- if (_optionalChain([state, 'optionalAccess', _4 => _4.cursor]) === null) {
479
- return noop2;
480
- }
491
+ const state = this.#signal.get();
492
+ if (!_optionalChain([state, 'access', _5 => _5.data, 'optionalAccess', _6 => _6.cursor])) return noop2;
481
493
  if (!this.#pendingFetchMore) {
482
494
  this.#pendingFetchMore = this.#fetchMore().finally(() => {
483
495
  this.#pendingFetchMore = null;
@@ -485,31 +497,12 @@ var PaginatedResource = class {
485
497
  }
486
498
  return this.#pendingFetchMore;
487
499
  }
488
- get() {
489
- const usable = this.#cachedPromise;
490
- if (usable === null || usable.status === "pending") {
491
- return ASYNC_LOADING;
492
- }
493
- if (usable.status === "rejected") {
494
- return { isLoading: false, error: usable.reason };
495
- }
496
- const state = this.#paginationState;
497
- return {
498
- isLoading: false,
499
- data: {
500
- fetchMore: this.fetchMore,
501
- isFetchingMore: state.isFetchingMore,
502
- fetchMoreError: state.fetchMoreError,
503
- hasFetchedAll: state.cursor === null
504
- }
505
- };
506
- }
507
500
  #cachedPromise = null;
508
501
  waitUntilLoaded() {
509
502
  if (this.#cachedPromise) {
510
503
  return this.#cachedPromise;
511
504
  }
512
- const initialFetcher = _core.autoRetry.call(void 0,
505
+ const initialPageFetch$ = _core.autoRetry.call(void 0,
513
506
  () => this.#fetchPage(
514
507
  /* cursor */
515
508
  void 0
@@ -517,67 +510,64 @@ var PaginatedResource = class {
517
510
  5,
518
511
  [5e3, 5e3, 1e4, 15e3]
519
512
  );
520
- const promise = usify(
521
- initialFetcher.then((cursor) => {
522
- this.#paginationState = {
523
- cursor,
524
- isFetchingMore: false,
525
- fetchMoreError: void 0
526
- };
527
- })
528
- );
513
+ const promise = usify(initialPageFetch$);
529
514
  promise.then(
530
- () => this.#eventSource.notify(),
531
- () => {
532
- this.#eventSource.notify();
515
+ (cursor) => {
516
+ this.#signal.set(
517
+ ASYNC_OK({
518
+ cursor,
519
+ hasFetchedAll: cursor === null,
520
+ isFetchingMore: false,
521
+ fetchMoreError: void 0,
522
+ fetchMore: this.fetchMore
523
+ })
524
+ );
525
+ },
526
+ (err) => {
527
+ this.#signal.set(ASYNC_ERR(err));
533
528
  setTimeout(() => {
534
529
  this.#cachedPromise = null;
535
- this.#eventSource.notify();
530
+ this.#signal.set(ASYNC_LOADING);
536
531
  }, 5e3);
537
532
  }
538
533
  );
539
534
  this.#cachedPromise = promise;
540
- return promise;
535
+ return this.#cachedPromise;
541
536
  }
542
537
  };
543
538
  var SinglePageResource = class {
539
+ #signal;
544
540
 
545
- #eventSource;
546
541
  #fetchPage;
547
542
  constructor(fetchPage) {
543
+ this.#signal = new (0, _core.Signal)(ASYNC_LOADING);
544
+ this.signal = this.#signal.asReadonly();
548
545
  this.#fetchPage = fetchPage;
549
- this.#eventSource = _core.makeEventSource.call(void 0, );
550
- this.observable = this.#eventSource.observable;
551
546
  autobind(this);
552
547
  }
553
548
  get() {
554
- const usable = this.#cachedPromise;
555
- if (usable === null || usable.status === "pending") {
556
- return ASYNC_LOADING;
557
- } else if (usable.status === "rejected") {
558
- return { isLoading: false, error: usable.reason };
559
- } else {
560
- return { isLoading: false, data: void 0 };
561
- }
549
+ return this.#signal.get();
562
550
  }
563
551
  #cachedPromise = null;
564
552
  waitUntilLoaded() {
565
553
  if (this.#cachedPromise) {
566
554
  return this.#cachedPromise;
567
555
  }
568
- const initialFetcher = _core.autoRetry.call(void 0,
556
+ const initialFetcher$ = _core.autoRetry.call(void 0,
569
557
  () => this.#fetchPage(),
570
558
  5,
571
559
  [5e3, 5e3, 1e4, 15e3]
572
560
  );
573
- const promise = usify(initialFetcher);
561
+ const promise = usify(initialFetcher$);
574
562
  promise.then(
575
- () => this.#eventSource.notify(),
576
563
  () => {
577
- this.#eventSource.notify();
564
+ this.#signal.set(ASYNC_OK(void 0));
565
+ },
566
+ (err) => {
567
+ this.#signal.set(ASYNC_ERR(err));
578
568
  setTimeout(() => {
579
569
  this.#cachedPromise = null;
580
- this.#eventSource.notify();
570
+ this.#signal.set(ASYNC_LOADING);
581
571
  }, 5e3);
582
572
  }
583
573
  );
@@ -610,10 +600,10 @@ function createStore_forNotifications() {
610
600
  function clear() {
611
601
  signal.mutate((lut) => lut.clear());
612
602
  }
613
- function applyDelta(newInboxNotifications, deletedNotifications) {
603
+ function applyDelta(newNotifications, deletedNotifications) {
614
604
  signal.mutate((lut) => {
615
605
  let mutated = false;
616
- for (const n of newInboxNotifications) {
606
+ for (const n of newNotifications) {
617
607
  const existing = lut.get(n.id);
618
608
  if (existing) {
619
609
  const result = compareInboxNotifications(existing, n);
@@ -644,6 +634,11 @@ function createStore_forNotifications() {
644
634
  return true;
645
635
  });
646
636
  }
637
+ function upsert(notification) {
638
+ signal.mutate((lut) => {
639
+ lut.set(notification.id, notification);
640
+ });
641
+ }
647
642
  return {
648
643
  signal: signal.asReadonly(),
649
644
  // Mutations
@@ -653,66 +648,70 @@ function createStore_forNotifications() {
653
648
  applyDelta,
654
649
  clear,
655
650
  updateAssociatedNotification,
656
- // XXX_vincent Remove this eventually
657
- force_set: (mutationCallback) => signal.mutate(mutationCallback),
658
- invalidate: () => signal.mutate()
651
+ upsert
659
652
  };
660
653
  }
661
- function createStore_forRoomNotificationSettings() {
662
- const signal = new (0, _core.MutableSignal)(/* @__PURE__ */ new Map());
654
+ function createStore_forRoomNotificationSettings(updates) {
655
+ const baseSignal = new (0, _core.MutableSignal)(/* @__PURE__ */ new Map());
663
656
  function update(roomId, settings) {
664
- signal.mutate((lut) => {
657
+ baseSignal.mutate((lut) => {
665
658
  lut.set(roomId, settings);
666
659
  });
667
660
  }
668
661
  return {
669
- signal: signal.asReadonly(),
662
+ signal: _core.DerivedSignal.from(
663
+ baseSignal,
664
+ updates,
665
+ (base, updates2) => applyOptimisticUpdates_forSettings(base, updates2)
666
+ ),
670
667
  // Mutations
671
- update,
672
- // XXX_vincent Remove this eventually
673
- invalidate: () => signal.mutate()
668
+ update
674
669
  };
675
670
  }
676
671
  function createStore_forHistoryVersions() {
677
- const signal = new (0, _core.MutableSignal)(/* @__PURE__ */ new Map());
672
+ const baseSignal = new (0, _core.MutableSignal)(
673
+ new (0, _core.DefaultMap)(() => /* @__PURE__ */ new Map())
674
+ );
678
675
  function update(roomId, versions) {
679
- signal.mutate((lut) => {
680
- const versionsById = _nullishCoalesce(lut.get(roomId), () => ( (lut.set(roomId, /* @__PURE__ */ new Map()), lut.get(roomId))));
676
+ baseSignal.mutate((lut) => {
677
+ const versionsById = lut.getOrCreate(roomId);
681
678
  for (const version of versions) {
682
679
  versionsById.set(version.id, version);
683
680
  }
684
681
  });
685
682
  }
686
683
  return {
687
- signal: signal.asReadonly(),
684
+ signal: _core.DerivedSignal.from(
685
+ baseSignal,
686
+ (hv) => Object.fromEntries(
687
+ [...hv].map(([roomId, versions]) => [
688
+ roomId,
689
+ Object.fromEntries(versions)
690
+ ])
691
+ )
692
+ ),
688
693
  // Mutations
689
- update,
690
- // XXX_vincent Remove these eventually
691
- force_set: (callback) => signal.mutate(callback),
692
- invalidate: () => signal.mutate()
694
+ update
693
695
  };
694
696
  }
695
697
  function createStore_forPermissionHints() {
696
- const signal = new (0, _core.Signal)({});
698
+ const signal = new (0, _core.MutableSignal)(
699
+ new (0, _core.DefaultMap)(() => /* @__PURE__ */ new Set())
700
+ );
697
701
  function update(newHints) {
698
- signal.set((prev) => {
699
- const permissionsByRoom = { ...prev };
702
+ signal.mutate((lut) => {
700
703
  for (const [roomId, newPermissions] of Object.entries(newHints)) {
701
- const existing = _nullishCoalesce(permissionsByRoom[roomId], () => ( /* @__PURE__ */ new Set()));
704
+ const existing = lut.getOrCreate(roomId);
702
705
  for (const permission of newPermissions) {
703
706
  existing.add(permission);
704
707
  }
705
- permissionsByRoom[roomId] = existing;
706
708
  }
707
- return permissionsByRoom;
708
709
  });
709
710
  }
710
711
  return {
711
712
  signal: signal.asReadonly(),
712
713
  // Mutations
713
- update,
714
- // XXX_vincent Remove this eventually
715
- invalidate: () => signal.set((store) => ({ ...store }))
714
+ update
716
715
  };
717
716
  }
718
717
  function createStore_forOptimistic(client) {
@@ -736,9 +735,7 @@ function createStore_forOptimistic(client) {
736
735
  signal: signal.asReadonly(),
737
736
  // Mutations
738
737
  add,
739
- remove,
740
- // XXX_vincent Remove this eventually
741
- invalidate: () => signal.set((store) => [...store])
738
+ remove
742
739
  };
743
740
  }
744
741
  var UmbrellaStore = class {
@@ -788,48 +785,37 @@ var UmbrellaStore = class {
788
785
  // threads and notifications separately, but the threadifications signal will
789
786
  // be updated whenever either of them change.
790
787
  //
791
- // XXX_vincent APIs like getRoomThreadsLoadingState should really also be modeled as output signals.
792
- //
793
788
 
794
789
  // Notifications
795
790
  #notificationsLastRequestedAt = null;
796
791
  // Keeps track of when we successfully requested an inbox notifications update for the last time. Will be `null` as long as the first successful fetch hasn't happened yet.
797
- #notifications;
792
+ #notificationsPaginationState;
798
793
  // Room Threads
799
794
  #roomThreadsLastRequestedAtByRoom = /* @__PURE__ */ new Map();
800
- #roomThreads = /* @__PURE__ */ new Map();
801
795
  // User Threads
802
796
  #userThreadsLastRequestedAt = null;
803
- #userThreads = /* @__PURE__ */ new Map();
804
797
  // Room versions
805
- #roomVersions = /* @__PURE__ */ new Map();
806
798
  #roomVersionsLastRequestedAtByRoom = /* @__PURE__ */ new Map();
807
- // Room notification settings
808
- #roomNotificationSettings = /* @__PURE__ */ new Map();
809
799
  constructor(client) {
810
800
  this.#client = client[_core.kInternal].as();
811
801
  this.optimisticUpdates = createStore_forOptimistic(this.#client);
812
802
  this.permissionHints = createStore_forPermissionHints();
813
- const inboxFetcher = async (cursor) => {
814
- const result = await this.#client.getInboxNotifications({ cursor });
815
- this.updateThreadifications(result.threads, result.inboxNotifications);
816
- if (this.#notificationsLastRequestedAt === null) {
817
- this.#notificationsLastRequestedAt = result.requestedAt;
803
+ this.#notificationsPaginationState = new PaginatedResource(
804
+ async (cursor) => {
805
+ const result = await this.#client.getInboxNotifications({ cursor });
806
+ this.updateThreadifications(result.threads, result.inboxNotifications);
807
+ if (this.#notificationsLastRequestedAt === null) {
808
+ this.#notificationsLastRequestedAt = result.requestedAt;
809
+ }
810
+ const nextCursor = result.nextCursor;
811
+ return nextCursor;
818
812
  }
819
- const nextCursor = result.nextCursor;
820
- return nextCursor;
821
- };
822
- this.#notifications = new PaginatedResource(inboxFetcher);
823
- this.#notifications.observable.subscribe(
824
- () => (
825
- // Note that the store itself does not change, but it's only vehicle at
826
- // the moment to trigger a re-render, so we'll do a no-op update here.
827
- this.invalidateEntireStore()
828
- )
829
813
  );
830
814
  this.threads = new ThreadDB();
831
815
  this.notifications = createStore_forNotifications();
832
- this.roomNotificationSettings = createStore_forRoomNotificationSettings();
816
+ this.roomNotificationSettings = createStore_forRoomNotificationSettings(
817
+ this.optimisticUpdates.signal
818
+ );
833
819
  this.historyVersions = createStore_forHistoryVersions();
834
820
  const threadifications = _core.DerivedSignal.from(
835
821
  this.threads.signal,
@@ -837,13 +823,7 @@ var UmbrellaStore = class {
837
823
  this.optimisticUpdates.signal,
838
824
  (ts, ns, updates) => applyOptimisticUpdates_forThreadifications(ts, ns, updates)
839
825
  );
840
- const threads = _core.DerivedSignal.from(
841
- threadifications,
842
- (s) => ({
843
- threadsDB: s.threadsDB
844
- }),
845
- _core.shallow
846
- );
826
+ const threads = _core.DerivedSignal.from(threadifications, (s) => s.threadsDB);
847
827
  const notifications = _core.DerivedSignal.from(
848
828
  threadifications,
849
829
  (s) => ({
@@ -852,177 +832,174 @@ var UmbrellaStore = class {
852
832
  }),
853
833
  _core.shallow
854
834
  );
855
- const settingsByRoomId = _core.DerivedSignal.from(
856
- this.roomNotificationSettings.signal,
857
- this.optimisticUpdates.signal,
858
- (settings, updates) => applyOptimisticUpdates_forSettings(settings, updates)
835
+ const loadingUserThreads = new (0, _core.DefaultMap)(
836
+ (queryKey) => {
837
+ const query = JSON.parse(queryKey);
838
+ const resource = new PaginatedResource(async (cursor) => {
839
+ const result = await this.#client[_core.kInternal].httpClient.getUserThreads_experimental({
840
+ cursor,
841
+ query
842
+ });
843
+ this.updateThreadifications(
844
+ result.threads,
845
+ result.inboxNotifications
846
+ );
847
+ this.permissionHints.update(result.permissionHints);
848
+ if (this.#userThreadsLastRequestedAt === null) {
849
+ this.#userThreadsLastRequestedAt = result.requestedAt;
850
+ }
851
+ return result.nextCursor;
852
+ });
853
+ const signal = _core.DerivedSignal.from(() => {
854
+ const result = resource.get();
855
+ if (result.isLoading || result.error) {
856
+ return result;
857
+ }
858
+ const threads2 = this.outputs.threads.get().findMany(
859
+ void 0,
860
+ // Do _not_ filter by roomId
861
+ _nullishCoalesce(query, () => ( {})),
862
+ "desc"
863
+ );
864
+ const page = result.data;
865
+ return {
866
+ isLoading: false,
867
+ threads: threads2,
868
+ hasFetchedAll: page.hasFetchedAll,
869
+ isFetchingMore: page.isFetchingMore,
870
+ fetchMoreError: page.fetchMoreError,
871
+ fetchMore: page.fetchMore
872
+ };
873
+ }, shallow2);
874
+ return { signal, waitUntilLoaded: resource.waitUntilLoaded };
875
+ }
859
876
  );
860
- const versionsByRoomId = _core.DerivedSignal.from(
861
- this.historyVersions.signal,
862
- (hv) => Object.fromEntries(
863
- [...hv].map(([roomId, versions]) => [
864
- roomId,
865
- Object.fromEntries(versions)
866
- ])
867
- )
877
+ const loadingRoomThreads = new (0, _core.DefaultMap)(
878
+ (queryKey) => {
879
+ const [roomId, query] = JSON.parse(queryKey);
880
+ const resource = new PaginatedResource(async (cursor) => {
881
+ const result = await this.#client[_core.kInternal].httpClient.getThreads({
882
+ roomId,
883
+ cursor,
884
+ query
885
+ });
886
+ this.updateThreadifications(
887
+ result.threads,
888
+ result.inboxNotifications
889
+ );
890
+ this.permissionHints.update(result.permissionHints);
891
+ const lastRequestedAt = this.#roomThreadsLastRequestedAtByRoom.get(roomId);
892
+ if (lastRequestedAt === void 0 || lastRequestedAt > result.requestedAt) {
893
+ this.#roomThreadsLastRequestedAtByRoom.set(
894
+ roomId,
895
+ result.requestedAt
896
+ );
897
+ }
898
+ return result.nextCursor;
899
+ });
900
+ const signal = _core.DerivedSignal.from(() => {
901
+ const result = resource.get();
902
+ if (result.isLoading || result.error) {
903
+ return result;
904
+ }
905
+ const threads2 = this.outputs.threads.get().findMany(roomId, _nullishCoalesce(query, () => ( {})), "asc");
906
+ const page = result.data;
907
+ return {
908
+ isLoading: false,
909
+ threads: threads2,
910
+ hasFetchedAll: page.hasFetchedAll,
911
+ isFetchingMore: page.isFetchingMore,
912
+ fetchMoreError: page.fetchMoreError,
913
+ fetchMore: page.fetchMore
914
+ };
915
+ }, shallow2);
916
+ return { signal, waitUntilLoaded: resource.waitUntilLoaded };
917
+ }
918
+ );
919
+ const loadingNotifications = {
920
+ signal: _core.DerivedSignal.from(() => {
921
+ const resource = this.#notificationsPaginationState;
922
+ const result = resource.get();
923
+ if (result.isLoading || result.error) {
924
+ return result;
925
+ }
926
+ const page = result.data;
927
+ return {
928
+ isLoading: false,
929
+ inboxNotifications: this.outputs.notifications.get().sortedNotifications,
930
+ hasFetchedAll: page.hasFetchedAll,
931
+ isFetchingMore: page.isFetchingMore,
932
+ fetchMoreError: page.fetchMoreError,
933
+ fetchMore: page.fetchMore
934
+ };
935
+ }),
936
+ waitUntilLoaded: this.#notificationsPaginationState.waitUntilLoaded
937
+ };
938
+ const settingsByRoomId = new (0, _core.DefaultMap)((roomId) => {
939
+ const resource = new SinglePageResource(async () => {
940
+ const room = this.#client.getRoom(roomId);
941
+ if (room === null) {
942
+ throw new Error(`Room '${roomId}' is not available on client`);
943
+ }
944
+ const result = await room.getNotificationSettings();
945
+ this.roomNotificationSettings.update(roomId, result);
946
+ });
947
+ const signal = _core.DerivedSignal.from(() => {
948
+ const result = resource.get();
949
+ if (result.isLoading || result.error) {
950
+ return result;
951
+ } else {
952
+ return ASYNC_OK(
953
+ "settings",
954
+ _core.nn.call(void 0, this.roomNotificationSettings.signal.get()[roomId])
955
+ );
956
+ }
957
+ }, _core.shallow);
958
+ return { signal, waitUntilLoaded: resource.waitUntilLoaded };
959
+ });
960
+ const versionsByRoomId = new (0, _core.DefaultMap)(
961
+ (roomId) => {
962
+ const resource = new SinglePageResource(async () => {
963
+ const room = this.#client.getRoom(roomId);
964
+ if (room === null) {
965
+ throw new Error(`Room '${roomId}' is not available on client`);
966
+ }
967
+ const result = await room[_core.kInternal].listTextVersions();
968
+ this.historyVersions.update(roomId, result.versions);
969
+ const lastRequestedAt = this.#roomVersionsLastRequestedAtByRoom.get(roomId);
970
+ if (lastRequestedAt === void 0 || lastRequestedAt > result.requestedAt) {
971
+ this.#roomVersionsLastRequestedAtByRoom.set(
972
+ roomId,
973
+ result.requestedAt
974
+ );
975
+ }
976
+ });
977
+ const signal = _core.DerivedSignal.from(() => {
978
+ const result = resource.get();
979
+ if (result.isLoading || result.error) {
980
+ return result;
981
+ } else {
982
+ return ASYNC_OK(
983
+ "versions",
984
+ Object.values(_nullishCoalesce(this.historyVersions.signal.get()[roomId], () => ( {})))
985
+ );
986
+ }
987
+ }, _core.shallow);
988
+ return { signal, waitUntilLoaded: resource.waitUntilLoaded };
989
+ }
868
990
  );
869
991
  this.outputs = {
870
992
  threadifications,
871
993
  threads,
994
+ loadingRoomThreads,
995
+ loadingUserThreads,
872
996
  notifications,
997
+ loadingNotifications,
873
998
  settingsByRoomId,
874
999
  versionsByRoomId
875
1000
  };
876
1001
  autobind(this);
877
1002
  }
878
- get1_both() {
879
- return this.outputs.threadifications.get();
880
- }
881
- subscribe1_both(callback) {
882
- return this.outputs.threadifications.subscribe(callback);
883
- }
884
- get1_threads() {
885
- return this.outputs.threads.get();
886
- }
887
- subscribe1_threads(callback) {
888
- return this.outputs.threads.subscribe(callback);
889
- }
890
- get1_notifications() {
891
- return this.outputs.notifications.get();
892
- }
893
- subscribe1_notifications(callback) {
894
- return this.outputs.notifications.subscribe(callback);
895
- }
896
- get2() {
897
- return this.outputs.settingsByRoomId.get();
898
- }
899
- subscribe2(callback) {
900
- return this.outputs.settingsByRoomId.subscribe(callback);
901
- }
902
- get3() {
903
- return this.outputs.versionsByRoomId.get();
904
- }
905
- subscribe3(callback) {
906
- return this.outputs.versionsByRoomId.subscribe(callback);
907
- }
908
- /**
909
- * Returns the async result of the given query and room id. If the query is success,
910
- * then it will return the threads that match that provided query and room id.
911
- *
912
- */
913
- getRoomThreadsLoadingState(roomId, query) {
914
- const queryKey = makeRoomThreadsQueryKey(roomId, query);
915
- const paginatedResource = this.#roomThreads.get(queryKey);
916
- if (paginatedResource === void 0) {
917
- return ASYNC_LOADING;
918
- }
919
- const asyncResult = paginatedResource.get();
920
- if (asyncResult.isLoading || asyncResult.error) {
921
- return asyncResult;
922
- }
923
- const threads = this.get1_threads().threadsDB.findMany(
924
- roomId,
925
- _nullishCoalesce(query, () => ( {})),
926
- "asc"
927
- );
928
- const page = asyncResult.data;
929
- return {
930
- isLoading: false,
931
- threads,
932
- hasFetchedAll: page.hasFetchedAll,
933
- isFetchingMore: page.isFetchingMore,
934
- fetchMoreError: page.fetchMoreError,
935
- fetchMore: page.fetchMore
936
- };
937
- }
938
- getUserThreadsLoadingState(query) {
939
- const queryKey = makeUserThreadsQueryKey(query);
940
- const paginatedResource = this.#userThreads.get(queryKey);
941
- if (paginatedResource === void 0) {
942
- return ASYNC_LOADING;
943
- }
944
- const asyncResult = paginatedResource.get();
945
- if (asyncResult.isLoading || asyncResult.error) {
946
- return asyncResult;
947
- }
948
- const threads = this.get1_threads().threadsDB.findMany(
949
- void 0,
950
- // Do _not_ filter by roomId
951
- _nullishCoalesce(query, () => ( {})),
952
- "desc"
953
- );
954
- const page = asyncResult.data;
955
- return {
956
- isLoading: false,
957
- threads,
958
- hasFetchedAll: page.hasFetchedAll,
959
- isFetchingMore: page.isFetchingMore,
960
- fetchMoreError: page.fetchMoreError,
961
- fetchMore: page.fetchMore
962
- };
963
- }
964
- // NOTE: This will read the async result, but WILL NOT start loading at the moment!
965
- getInboxNotificationsLoadingState() {
966
- const asyncResult = this.#notifications.get();
967
- if (asyncResult.isLoading || asyncResult.error) {
968
- return asyncResult;
969
- }
970
- const page = asyncResult.data;
971
- return {
972
- isLoading: false,
973
- inboxNotifications: this.get1_notifications().sortedNotifications,
974
- hasFetchedAll: page.hasFetchedAll,
975
- isFetchingMore: page.isFetchingMore,
976
- fetchMoreError: page.fetchMoreError,
977
- fetchMore: page.fetchMore
978
- };
979
- }
980
- // NOTE: This will read the async result, but WILL NOT start loading at the moment!
981
- // XXX_vincent This should really be a derived Signal!
982
- getNotificationSettingsLoadingState(roomId) {
983
- const queryKey = makeNotificationSettingsQueryKey(roomId);
984
- const resource = this.#roomNotificationSettings.get(queryKey);
985
- if (resource === void 0) {
986
- return ASYNC_LOADING;
987
- }
988
- const asyncResult = resource.get();
989
- if (asyncResult.isLoading || asyncResult.error) {
990
- return asyncResult;
991
- }
992
- return {
993
- isLoading: false,
994
- settings: _core.nn.call(void 0, this.get2()[roomId])
995
- };
996
- }
997
- getRoomVersionsLoadingState(roomId) {
998
- const queryKey = makeVersionsQueryKey(roomId);
999
- const resource = this.#roomVersions.get(queryKey);
1000
- if (resource === void 0) {
1001
- return ASYNC_LOADING;
1002
- }
1003
- const asyncResult = resource.get();
1004
- if (asyncResult.isLoading || asyncResult.error) {
1005
- return asyncResult;
1006
- }
1007
- return {
1008
- isLoading: false,
1009
- versions: Object.values(_nullishCoalesce(this.get3()[roomId], () => ( {})))
1010
- };
1011
- }
1012
- /** @internal - Only call this method from unit tests. */
1013
- force_set_versions(callback) {
1014
- _core.batch.call(void 0, () => {
1015
- this.historyVersions.force_set(callback);
1016
- this.invalidateEntireStore();
1017
- });
1018
- }
1019
- /** @internal - Only call this method from unit tests. */
1020
- force_set_notifications(callback) {
1021
- _core.batch.call(void 0, () => {
1022
- this.notifications.force_set(callback);
1023
- this.invalidateEntireStore();
1024
- });
1025
- }
1026
1003
  /**
1027
1004
  * Updates an existing inbox notification with a new value, replacing the
1028
1005
  * corresponding optimistic update.
@@ -1164,7 +1141,7 @@ var UmbrellaStore = class {
1164
1141
  }
1165
1142
  updateThreadifications(threads, notifications, deletedThreads = [], deletedNotifications = []) {
1166
1143
  _core.batch.call(void 0, () => {
1167
- this.threads.applyDelta({ newThreads: threads, deletedThreads });
1144
+ this.threads.applyDelta(threads, deletedThreads);
1168
1145
  this.notifications.applyDelta(notifications, deletedNotifications);
1169
1146
  });
1170
1147
  }
@@ -1197,39 +1174,6 @@ var UmbrellaStore = class {
1197
1174
  result.inboxNotifications.deleted
1198
1175
  );
1199
1176
  }
1200
- waitUntilNotificationsLoaded() {
1201
- return this.#notifications.waitUntilLoaded();
1202
- }
1203
- waitUntilRoomThreadsLoaded(roomId, query) {
1204
- const threadsFetcher = async (cursor) => {
1205
- const result = await this.#client[_core.kInternal].httpClient.getThreads({
1206
- roomId,
1207
- cursor,
1208
- query
1209
- });
1210
- this.updateThreadifications(result.threads, result.inboxNotifications);
1211
- this.permissionHints.update(result.permissionHints);
1212
- const lastRequestedAt = this.#roomThreadsLastRequestedAtByRoom.get(roomId);
1213
- if (lastRequestedAt === void 0 || lastRequestedAt > result.requestedAt) {
1214
- this.#roomThreadsLastRequestedAtByRoom.set(roomId, result.requestedAt);
1215
- }
1216
- return result.nextCursor;
1217
- };
1218
- const queryKey = makeRoomThreadsQueryKey(roomId, query);
1219
- let paginatedResource = this.#roomThreads.get(queryKey);
1220
- if (paginatedResource === void 0) {
1221
- paginatedResource = new PaginatedResource(threadsFetcher);
1222
- }
1223
- paginatedResource.observable.subscribe(
1224
- () => (
1225
- // Note that the store itself does not change, but it's only vehicle at
1226
- // the moment to trigger a re-render, so we'll do a no-op update here.
1227
- this.invalidateEntireStore()
1228
- )
1229
- );
1230
- this.#roomThreads.set(queryKey, paginatedResource);
1231
- return paginatedResource.waitUntilLoaded();
1232
- }
1233
1177
  async fetchRoomThreadsDeltaUpdate(roomId, signal) {
1234
1178
  const lastRequestedAt = this.#roomThreadsLastRequestedAtByRoom.get(roomId);
1235
1179
  if (lastRequestedAt === void 0) {
@@ -1251,45 +1195,6 @@ var UmbrellaStore = class {
1251
1195
  this.#roomThreadsLastRequestedAtByRoom.set(roomId, updates.requestedAt);
1252
1196
  }
1253
1197
  }
1254
- waitUntilUserThreadsLoaded(query) {
1255
- const queryKey = makeUserThreadsQueryKey(query);
1256
- const threadsFetcher = async (cursor) => {
1257
- const result = await this.#client[_core.kInternal].httpClient.getUserThreads_experimental({
1258
- cursor,
1259
- query
1260
- });
1261
- this.updateThreadifications(result.threads, result.inboxNotifications);
1262
- this.permissionHints.update(result.permissionHints);
1263
- if (this.#userThreadsLastRequestedAt === null) {
1264
- this.#userThreadsLastRequestedAt = result.requestedAt;
1265
- }
1266
- return result.nextCursor;
1267
- };
1268
- let paginatedResource = this.#userThreads.get(queryKey);
1269
- if (paginatedResource === void 0) {
1270
- paginatedResource = new PaginatedResource(threadsFetcher);
1271
- }
1272
- paginatedResource.observable.subscribe(
1273
- () => (
1274
- // Note that the store itself does not change, but it's only vehicle at
1275
- // the moment to trigger a re-render, so we'll do a no-op update here.
1276
- this.invalidateEntireStore()
1277
- )
1278
- );
1279
- this.#userThreads.set(queryKey, paginatedResource);
1280
- return paginatedResource.waitUntilLoaded();
1281
- }
1282
- // XXX_vincent We should really be going over all call sites, and replace this call
1283
- // with a more specific invalidation!
1284
- invalidateEntireStore() {
1285
- _core.batch.call(void 0, () => {
1286
- this.historyVersions.invalidate();
1287
- this.notifications.invalidate();
1288
- this.optimisticUpdates.invalidate();
1289
- this.permissionHints.invalidate();
1290
- this.roomNotificationSettings.invalidate();
1291
- });
1292
- }
1293
1198
  async fetchUserThreadsDeltaUpdate(signal) {
1294
1199
  const lastRequestedAt = this.#userThreadsLastRequestedAt;
1295
1200
  if (lastRequestedAt === null) {
@@ -1310,40 +1215,6 @@ var UmbrellaStore = class {
1310
1215
  );
1311
1216
  this.permissionHints.update(result.permissionHints);
1312
1217
  }
1313
- waitUntilRoomVersionsLoaded(roomId) {
1314
- const queryKey = makeVersionsQueryKey(roomId);
1315
- let resource = this.#roomVersions.get(queryKey);
1316
- if (resource === void 0) {
1317
- const versionsFetcher = async () => {
1318
- const room = this.#client.getRoom(roomId);
1319
- if (room === null) {
1320
- throw new (0, _core.HttpError)(
1321
- `Room '${roomId}' is not available on client`,
1322
- 479
1323
- );
1324
- }
1325
- const result = await room[_core.kInternal].listTextVersions();
1326
- this.historyVersions.update(roomId, result.versions);
1327
- const lastRequestedAt = this.#roomVersionsLastRequestedAtByRoom.get(roomId);
1328
- if (lastRequestedAt === void 0 || lastRequestedAt > result.requestedAt) {
1329
- this.#roomVersionsLastRequestedAtByRoom.set(
1330
- roomId,
1331
- result.requestedAt
1332
- );
1333
- }
1334
- };
1335
- resource = new SinglePageResource(versionsFetcher);
1336
- }
1337
- resource.observable.subscribe(
1338
- () => (
1339
- // Note that the store itself does not change, but it's only vehicle at
1340
- // the moment to trigger a re-render, so we'll do a no-op update here.
1341
- this.invalidateEntireStore()
1342
- )
1343
- );
1344
- this.#roomVersions.set(queryKey, resource);
1345
- return resource.waitUntilLoaded();
1346
- }
1347
1218
  async fetchRoomVersionsDeltaUpdate(roomId, signal) {
1348
1219
  const lastRequestedAt = this.#roomVersionsLastRequestedAtByRoom.get(roomId);
1349
1220
  if (lastRequestedAt === void 0) {
@@ -1362,33 +1233,6 @@ var UmbrellaStore = class {
1362
1233
  this.#roomVersionsLastRequestedAtByRoom.set(roomId, updates.requestedAt);
1363
1234
  }
1364
1235
  }
1365
- waitUntilRoomNotificationSettingsLoaded(roomId) {
1366
- const queryKey = makeNotificationSettingsQueryKey(roomId);
1367
- let resource = this.#roomNotificationSettings.get(queryKey);
1368
- if (resource === void 0) {
1369
- const notificationSettingsFetcher = async () => {
1370
- const room = this.#client.getRoom(roomId);
1371
- if (room === null) {
1372
- throw new (0, _core.HttpError)(
1373
- `Room '${roomId}' is not available on client`,
1374
- 479
1375
- );
1376
- }
1377
- const result = await room.getNotificationSettings();
1378
- this.roomNotificationSettings.update(roomId, result);
1379
- };
1380
- resource = new SinglePageResource(notificationSettingsFetcher);
1381
- }
1382
- resource.observable.subscribe(
1383
- () => (
1384
- // Note that the store itself does not change, but it's only vehicle at
1385
- // the moment to trigger a re-render, so we'll do a no-op update here.
1386
- this.invalidateEntireStore()
1387
- )
1388
- );
1389
- this.#roomNotificationSettings.set(queryKey, resource);
1390
- return resource.waitUntilLoaded();
1391
- }
1392
1236
  async refreshRoomNotificationSettings(roomId, signal) {
1393
1237
  const room = _core.nn.call(void 0,
1394
1238
  this.#client.getRoom(roomId),
@@ -1620,7 +1464,7 @@ function applyUpsertComment(thread, comment) {
1620
1464
  updatedAt: new Date(
1621
1465
  Math.max(
1622
1466
  thread.updatedAt.getTime(),
1623
- _optionalChain([comment, 'access', _5 => _5.editedAt, 'optionalAccess', _6 => _6.getTime, 'call', _7 => _7()]) || comment.createdAt.getTime()
1467
+ _optionalChain([comment, 'access', _7 => _7.editedAt, 'optionalAccess', _8 => _8.getTime, 'call', _9 => _9()]) || comment.createdAt.getTime()
1624
1468
  )
1625
1469
  ),
1626
1470
  comments: updatedComments
@@ -1760,32 +1604,26 @@ function missingRoomInfoError(roomId) {
1760
1604
  `resolveRoomsInfo didn't return anything for room '${roomId}'`
1761
1605
  );
1762
1606
  }
1763
- function identity(x) {
1607
+ function identity2(x) {
1764
1608
  return x;
1765
1609
  }
1766
1610
  var _umbrellaStores = /* @__PURE__ */ new WeakMap();
1767
1611
  var _extras = /* @__PURE__ */ new WeakMap();
1768
1612
  var _bundles = /* @__PURE__ */ new WeakMap();
1769
- function selectUnreadInboxNotificationsCount(inboxNotifications) {
1770
- let count = 0;
1771
- for (const notification of inboxNotifications) {
1772
- if (notification.readAt === null || notification.readAt < notification.notifiedAt) {
1773
- count++;
1774
- }
1775
- }
1776
- return count;
1777
- }
1778
1613
  function selectorFor_useUnreadInboxNotificationsCount(result) {
1779
1614
  if (!result.inboxNotifications) {
1780
1615
  return result;
1781
1616
  }
1782
- return {
1783
- isLoading: false,
1784
- count: selectUnreadInboxNotificationsCount(result.inboxNotifications)
1785
- };
1617
+ return ASYNC_OK(
1618
+ "count",
1619
+ count(
1620
+ result.inboxNotifications,
1621
+ (n) => n.readAt === null || n.readAt < n.notifiedAt
1622
+ )
1623
+ );
1786
1624
  }
1787
1625
  function selectorFor_useUser(state, userId) {
1788
- if (state === void 0 || _optionalChain([state, 'optionalAccess', _8 => _8.isLoading])) {
1626
+ if (state === void 0 || _optionalChain([state, 'optionalAccess', _10 => _10.isLoading])) {
1789
1627
  return _nullishCoalesce(state, () => ( { isLoading: true }));
1790
1628
  }
1791
1629
  if (state.error) {
@@ -1803,7 +1641,7 @@ function selectorFor_useUser(state, userId) {
1803
1641
  };
1804
1642
  }
1805
1643
  function selectorFor_useRoomInfo(state, roomId) {
1806
- if (state === void 0 || _optionalChain([state, 'optionalAccess', _9 => _9.isLoading])) {
1644
+ if (state === void 0 || _optionalChain([state, 'optionalAccess', _11 => _11.isLoading])) {
1807
1645
  return _nullishCoalesce(state, () => ( { isLoading: true }));
1808
1646
  }
1809
1647
  if (state.error) {
@@ -1889,7 +1727,7 @@ function makeLiveblocksContextBundle(client) {
1889
1727
  const shared = createSharedContext(client);
1890
1728
  const bundle = {
1891
1729
  LiveblocksProvider: LiveblocksProvider2,
1892
- useInboxNotifications: () => useInboxNotifications_withClient(client, identity, _core.shallow),
1730
+ useInboxNotifications: () => useInboxNotifications_withClient(client, identity2, _core.shallow),
1893
1731
  useUnreadInboxNotificationsCount: () => useUnreadInboxNotificationsCount_withClient(client),
1894
1732
  useMarkInboxNotificationAsRead: useMarkInboxNotificationAsRead2,
1895
1733
  useMarkAllInboxNotificationsAsRead: useMarkAllInboxNotificationsAsRead2,
@@ -1915,9 +1753,17 @@ function makeLiveblocksContextBundle(client) {
1915
1753
  }
1916
1754
  function useInboxNotifications_withClient(client, selector, isEqual) {
1917
1755
  const { store, notificationsPoller: poller } = getLiveblocksExtrasForClient(client);
1918
- _react.useEffect.call(void 0, () => {
1919
- void store.waitUntilNotificationsLoaded();
1920
- });
1756
+ _react.useEffect.call(void 0,
1757
+ () => void store.outputs.loadingNotifications.waitUntilLoaded()
1758
+ // NOTE: Deliberately *not* using a dependency array here!
1759
+ //
1760
+ // It is important to call waitUntil on *every* render.
1761
+ // This is harmless though, on most renders, except:
1762
+ // 1. The very first render, in which case we'll want to trigger the initial page fetch.
1763
+ // 2. All other subsequent renders now "just" return the same promise (a quick operation).
1764
+ // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very
1765
+ // *next* render after that, a *new* fetch/promise will get created.
1766
+ );
1921
1767
  _react.useEffect.call(void 0, () => {
1922
1768
  poller.inc();
1923
1769
  poller.pollNowIfStale();
@@ -1925,18 +1771,16 @@ function useInboxNotifications_withClient(client, selector, isEqual) {
1925
1771
  poller.dec();
1926
1772
  };
1927
1773
  }, [poller]);
1928
- return useSyncExternalStoreWithSelector(
1929
- store.subscribe1_notifications,
1930
- store.getInboxNotificationsLoadingState,
1931
- store.getInboxNotificationsLoadingState,
1774
+ return useSignal(
1775
+ store.outputs.loadingNotifications.signal,
1932
1776
  selector,
1933
1777
  isEqual
1934
1778
  );
1935
1779
  }
1936
1780
  function useInboxNotificationsSuspense_withClient(client) {
1937
1781
  const store = getLiveblocksExtrasForClient(client).store;
1938
- use(store.waitUntilNotificationsLoaded());
1939
- const result = useInboxNotifications_withClient(client, identity, _core.shallow);
1782
+ use(store.outputs.loadingNotifications.waitUntilLoaded());
1783
+ const result = useInboxNotifications_withClient(client, identity2, _core.shallow);
1940
1784
  _core.assert.call(void 0, !result.error, "Did not expect error");
1941
1785
  _core.assert.call(void 0, !result.isLoading, "Did not expect loading");
1942
1786
  return result;
@@ -1950,7 +1794,7 @@ function useUnreadInboxNotificationsCount_withClient(client) {
1950
1794
  }
1951
1795
  function useUnreadInboxNotificationsCountSuspense_withClient(client) {
1952
1796
  const store = getLiveblocksExtrasForClient(client).store;
1953
- use(store.waitUntilNotificationsLoaded());
1797
+ use(store.outputs.loadingNotifications.waitUntilLoaded());
1954
1798
  const result = useUnreadInboxNotificationsCount_withClient(client);
1955
1799
  _core.assert.call(void 0, !result.isLoading, "Did not expect loading");
1956
1800
  _core.assert.call(void 0, !result.error, "Did not expect error");
@@ -1974,8 +1818,15 @@ function useMarkInboxNotificationAsRead_withClient(client) {
1974
1818
  optimisticId
1975
1819
  );
1976
1820
  },
1977
- () => {
1821
+ (err) => {
1978
1822
  store.optimisticUpdates.remove(optimisticId);
1823
+ client[_core.kInternal].emitError(
1824
+ {
1825
+ type: "MARK_INBOX_NOTIFICATION_AS_READ_ERROR",
1826
+ inboxNotificationId
1827
+ },
1828
+ err
1829
+ );
1979
1830
  }
1980
1831
  );
1981
1832
  },
@@ -1994,8 +1845,13 @@ function useMarkAllInboxNotificationsAsRead_withClient(client) {
1994
1845
  () => {
1995
1846
  store.markAllInboxNotificationsRead(optimisticId, readAt);
1996
1847
  },
1997
- () => {
1848
+ (err) => {
1998
1849
  store.optimisticUpdates.remove(optimisticId);
1850
+ client[_core.kInternal].emitError(
1851
+ // No roomId, threadId, commentId to include for this error
1852
+ { type: "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR" },
1853
+ err
1854
+ );
1999
1855
  }
2000
1856
  );
2001
1857
  }, [client]);
@@ -2014,8 +1870,12 @@ function useDeleteInboxNotification_withClient(client) {
2014
1870
  () => {
2015
1871
  store.deleteInboxNotification(inboxNotificationId, optimisticId);
2016
1872
  },
2017
- () => {
1873
+ (err) => {
2018
1874
  store.optimisticUpdates.remove(optimisticId);
1875
+ client[_core.kInternal].emitError(
1876
+ { type: "DELETE_INBOX_NOTIFICATION_ERROR", inboxNotificationId },
1877
+ err
1878
+ );
2019
1879
  }
2020
1880
  );
2021
1881
  },
@@ -2034,42 +1894,43 @@ function useDeleteAllInboxNotifications_withClient(client) {
2034
1894
  () => {
2035
1895
  store.deleteAllInboxNotifications(optimisticId);
2036
1896
  },
2037
- () => {
1897
+ (err) => {
2038
1898
  store.optimisticUpdates.remove(optimisticId);
1899
+ client[_core.kInternal].emitError(
1900
+ { type: "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR" },
1901
+ err
1902
+ );
2039
1903
  }
2040
1904
  );
2041
1905
  }, [client]);
2042
1906
  }
2043
1907
  function useInboxNotificationThread_withClient(client, inboxNotificationId) {
2044
1908
  const { store } = getLiveblocksExtrasForClient(client);
2045
- const getter = store.get1_both;
2046
- const selector = _react.useCallback.call(void 0,
2047
- (state) => {
2048
- const inboxNotification = _nullishCoalesce(state.notificationsById[inboxNotificationId], () => ( _core.raise.call(void 0, `Inbox notification with ID "${inboxNotificationId}" not found`)));
2049
- if (inboxNotification.kind !== "thread") {
2050
- _core.raise.call(void 0,
2051
- `Inbox notification with ID "${inboxNotificationId}" is not of kind "thread"`
2052
- );
2053
- }
2054
- const thread = _nullishCoalesce(state.threadsDB.get(inboxNotification.threadId), () => ( _core.raise.call(void 0,
2055
- `Thread with ID "${inboxNotification.threadId}" not found, this inbox notification might not be of kind "thread"`
2056
- )));
2057
- return thread;
2058
- },
2059
- [inboxNotificationId]
2060
- );
2061
- return useSyncExternalStoreWithSelector(
2062
- store.subscribe1_both,
2063
- // Re-evaluate if we need to update any time the notification changes over time
2064
- getter,
2065
- getter,
2066
- selector
1909
+ return useSignal(
1910
+ store.outputs.threadifications,
1911
+ _react.useCallback.call(void 0,
1912
+ (state) => {
1913
+ const inboxNotification = _nullishCoalesce(state.notificationsById[inboxNotificationId], () => ( _core.raise.call(void 0,
1914
+ `Inbox notification with ID "${inboxNotificationId}" not found`
1915
+ )));
1916
+ if (inboxNotification.kind !== "thread") {
1917
+ _core.raise.call(void 0,
1918
+ `Inbox notification with ID "${inboxNotificationId}" is not of kind "thread"`
1919
+ );
1920
+ }
1921
+ const thread = _nullishCoalesce(state.threadsDB.get(inboxNotification.threadId), () => ( _core.raise.call(void 0,
1922
+ `Thread with ID "${inboxNotification.threadId}" not found, this inbox notification might not be of kind "thread"`
1923
+ )));
1924
+ return thread;
1925
+ },
1926
+ [inboxNotificationId]
1927
+ )
2067
1928
  );
2068
1929
  }
2069
1930
  function useUser_withClient(client, userId) {
2070
1931
  const usersStore = client[_core.kInternal].usersStore;
2071
1932
  const getUserState = _react.useCallback.call(void 0,
2072
- () => usersStore.getState(userId),
1933
+ () => usersStore.getItemState(userId),
2073
1934
  [usersStore, userId]
2074
1935
  );
2075
1936
  const selector = _react.useCallback.call(void 0,
@@ -2083,20 +1944,29 @@ function useUser_withClient(client, userId) {
2083
1944
  selector,
2084
1945
  _core.shallow
2085
1946
  );
2086
- _react.useEffect.call(void 0, () => {
2087
- void usersStore.get(userId);
2088
- }, [usersStore, userId, result]);
1947
+ _react.useEffect.call(void 0,
1948
+ () => void usersStore.enqueue(userId)
1949
+ // NOTE: Deliberately *not* using a dependency array here!
1950
+ //
1951
+ // It is important to call usersStore.enqueue on *every* render.
1952
+ // This is harmless though, on most renders, except:
1953
+ // 1. The very first render, in which case we'll want to trigger evaluation
1954
+ // of the userId.
1955
+ // 2. All other subsequent renders now are a no-op (from the implementation
1956
+ // of .enqueue)
1957
+ // 3. If ever the userId gets invalidated, the user would be fetched again.
1958
+ );
2089
1959
  return result;
2090
1960
  }
2091
1961
  function useUserSuspense_withClient(client, userId) {
2092
1962
  const usersStore = client[_core.kInternal].usersStore;
2093
1963
  const getUserState = _react.useCallback.call(void 0,
2094
- () => usersStore.getState(userId),
1964
+ () => usersStore.getItemState(userId),
2095
1965
  [usersStore, userId]
2096
1966
  );
2097
1967
  const userState = getUserState();
2098
1968
  if (!userState || userState.isLoading) {
2099
- throw usersStore.get(userId);
1969
+ throw usersStore.enqueue(userId);
2100
1970
  }
2101
1971
  if (userState.error) {
2102
1972
  throw userState.error;
@@ -2121,7 +1991,7 @@ function useUserSuspense_withClient(client, userId) {
2121
1991
  function useRoomInfo_withClient(client, roomId) {
2122
1992
  const roomsInfoStore = client[_core.kInternal].roomsInfoStore;
2123
1993
  const getRoomInfoState = _react.useCallback.call(void 0,
2124
- () => roomsInfoStore.getState(roomId),
1994
+ () => roomsInfoStore.getItemState(roomId),
2125
1995
  [roomsInfoStore, roomId]
2126
1996
  );
2127
1997
  const selector = _react.useCallback.call(void 0,
@@ -2135,20 +2005,29 @@ function useRoomInfo_withClient(client, roomId) {
2135
2005
  selector,
2136
2006
  _core.shallow
2137
2007
  );
2138
- _react.useEffect.call(void 0, () => {
2139
- void roomsInfoStore.get(roomId);
2140
- }, [roomsInfoStore, roomId, result]);
2008
+ _react.useEffect.call(void 0,
2009
+ () => void roomsInfoStore.enqueue(roomId)
2010
+ // NOTE: Deliberately *not* using a dependency array here!
2011
+ //
2012
+ // It is important to call roomsInfoStore.enqueue on *every* render.
2013
+ // This is harmless though, on most renders, except:
2014
+ // 1. The very first render, in which case we'll want to trigger evaluation
2015
+ // of the roomId.
2016
+ // 2. All other subsequent renders now are a no-op (from the implementation
2017
+ // of .enqueue)
2018
+ // 3. If ever the roomId gets invalidated, the room info would be fetched again.
2019
+ );
2141
2020
  return result;
2142
2021
  }
2143
2022
  function useRoomInfoSuspense_withClient(client, roomId) {
2144
2023
  const roomsInfoStore = client[_core.kInternal].roomsInfoStore;
2145
2024
  const getRoomInfoState = _react.useCallback.call(void 0,
2146
- () => roomsInfoStore.getState(roomId),
2025
+ () => roomsInfoStore.getItemState(roomId),
2147
2026
  [roomsInfoStore, roomId]
2148
2027
  );
2149
2028
  const roomInfoState = getRoomInfoState();
2150
2029
  if (!roomInfoState || roomInfoState.isLoading) {
2151
- throw roomsInfoStore.get(roomId);
2030
+ throw roomsInfoStore.enqueue(roomId);
2152
2031
  }
2153
2032
  if (roomInfoState.error) {
2154
2033
  throw roomInfoState.error;
@@ -2182,6 +2061,7 @@ function createSharedContext(client) {
2182
2061
  useUser: (userId) => useUser_withClient(client, userId),
2183
2062
  useRoomInfo: (roomId) => useRoomInfo_withClient(client, roomId),
2184
2063
  useIsInsideRoom,
2064
+ useErrorListener,
2185
2065
  useSyncStatus: useSyncStatus2
2186
2066
  },
2187
2067
  suspense: {
@@ -2189,13 +2069,14 @@ function createSharedContext(client) {
2189
2069
  useUser: (userId) => useUserSuspense_withClient(client, userId),
2190
2070
  useRoomInfo: (roomId) => useRoomInfoSuspense_withClient(client, roomId),
2191
2071
  useIsInsideRoom,
2072
+ useErrorListener,
2192
2073
  useSyncStatus: useSyncStatus2
2193
2074
  }
2194
2075
  };
2195
2076
  }
2196
2077
  function useEnsureNoLiveblocksProvider(options) {
2197
2078
  const existing = useClientOrNull();
2198
- if (!_optionalChain([options, 'optionalAccess', _10 => _10.allowNesting]) && existing !== null) {
2079
+ if (!_optionalChain([options, 'optionalAccess', _12 => _12.allowNesting]) && existing !== null) {
2199
2080
  throw new Error(
2200
2081
  "You cannot nest multiple LiveblocksProvider instances in the same React tree."
2201
2082
  );
@@ -2243,17 +2124,12 @@ function LiveblocksProvider(props) {
2243
2124
  function createLiveblocksContext(client) {
2244
2125
  return getOrCreateContextBundle(client);
2245
2126
  }
2246
- function useUserThreads_experimental(options = {
2247
- query: {
2248
- metadata: {}
2249
- }
2250
- }) {
2127
+ function useUserThreads_experimental(options = {}) {
2251
2128
  const client = useClient();
2252
2129
  const { store, userThreadsPoller: poller } = getLiveblocksExtrasForClient(client);
2130
+ const queryKey = makeUserThreadsQueryKey(options.query);
2253
2131
  _react.useEffect.call(void 0,
2254
- () => {
2255
- void store.waitUntilUserThreadsLoaded(options.query);
2256
- }
2132
+ () => void store.outputs.loadingUserThreads.getOrCreate(queryKey).waitUntilLoaded()
2257
2133
  // NOTE: Deliberately *not* using a dependency array here!
2258
2134
  //
2259
2135
  // It is important to call waitUntil on *every* render.
@@ -2270,34 +2146,22 @@ function useUserThreads_experimental(options = {
2270
2146
  poller.dec();
2271
2147
  };
2272
2148
  }, [poller]);
2273
- const getter = _react.useCallback.call(void 0,
2274
- () => store.getUserThreadsLoadingState(options.query),
2275
- [store, options.query]
2276
- );
2277
- return useSyncExternalStoreWithSelector(
2278
- store.subscribe1_threads,
2279
- getter,
2280
- getter,
2281
- identity,
2282
- shallow2
2283
- // NOTE: Using 2-level-deep shallow check here, because the result of selectThreads() is not stable!
2149
+ return useSignal(
2150
+ store.outputs.loadingUserThreads.getOrCreate(queryKey).signal
2284
2151
  );
2285
2152
  }
2286
- function useUserThreadsSuspense_experimental(options = {
2287
- query: {
2288
- metadata: {}
2289
- }
2290
- }) {
2153
+ function useUserThreadsSuspense_experimental(options = {}) {
2291
2154
  const client = useClient();
2292
2155
  const { store } = getLiveblocksExtrasForClient(client);
2293
- use(store.waitUntilUserThreadsLoaded(options.query));
2156
+ const queryKey = makeUserThreadsQueryKey(options.query);
2157
+ use(store.outputs.loadingUserThreads.getOrCreate(queryKey).waitUntilLoaded());
2294
2158
  const result = useUserThreads_experimental(options);
2295
2159
  _core.assert.call(void 0, !result.error, "Did not expect error");
2296
2160
  _core.assert.call(void 0, !result.isLoading, "Did not expect loading");
2297
2161
  return result;
2298
2162
  }
2299
2163
  function useInboxNotifications() {
2300
- return useInboxNotifications_withClient(useClient(), identity, _core.shallow);
2164
+ return useInboxNotifications_withClient(useClient(), identity2, _core.shallow);
2301
2165
  }
2302
2166
  function useInboxNotificationsSuspense() {
2303
2167
  return useInboxNotificationsSuspense_withClient(useClient());
@@ -2346,7 +2210,7 @@ var _useUserSuspense = useUserSuspense;
2346
2210
  var _useUserThreads_experimental = useUserThreads_experimental;
2347
2211
  var _useUserThreadsSuspense_experimental = useUserThreadsSuspense_experimental;
2348
2212
  function useSyncStatus_withClient(client, options) {
2349
- const smooth = useInitial(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _11 => _11.smooth]), () => ( false)));
2213
+ const smooth = useInitial(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _13 => _13.smooth]), () => ( false)));
2350
2214
  if (smooth) {
2351
2215
  return useSyncStatusSmooth_withClient(client);
2352
2216
  } else {
@@ -2385,114 +2249,12 @@ function useSyncStatusSmooth_withClient(client) {
2385
2249
  function useSyncStatus(options) {
2386
2250
  return useSyncStatus_withClient(useClient(), options);
2387
2251
  }
2388
-
2389
- // src/types/errors.ts
2390
- var CreateThreadError = class extends Error {
2391
- constructor(cause, context) {
2392
- super("Create thread failed.");
2393
- this.cause = cause;
2394
- this.context = context;
2395
- this.name = "CreateThreadError";
2396
- }
2397
- };
2398
- var DeleteThreadError = class extends Error {
2399
- constructor(cause, context) {
2400
- super("Delete thread failed.");
2401
- this.cause = cause;
2402
- this.context = context;
2403
- this.name = "DeleteThreadError";
2404
- }
2405
- };
2406
- var EditThreadMetadataError = class extends Error {
2407
- constructor(cause, context) {
2408
- super("Edit thread metadata failed.");
2409
- this.cause = cause;
2410
- this.context = context;
2411
- this.name = "EditThreadMetadataError";
2412
- }
2413
- };
2414
- var MarkThreadAsResolvedError = class extends Error {
2415
- constructor(cause, context) {
2416
- super("Mark thread as resolved failed.");
2417
- this.cause = cause;
2418
- this.context = context;
2419
- this.name = "MarkThreadAsResolvedError";
2420
- }
2421
- };
2422
- var MarkThreadAsUnresolvedError = class extends Error {
2423
- constructor(cause, context) {
2424
- super("Mark thread as unresolved failed.");
2425
- this.cause = cause;
2426
- this.context = context;
2427
- this.name = "MarkThreadAsUnresolvedError";
2428
- }
2429
- };
2430
- var CreateCommentError = class extends Error {
2431
- constructor(cause, context) {
2432
- super("Create comment failed.");
2433
- this.cause = cause;
2434
- this.context = context;
2435
- this.name = "CreateCommentError";
2436
- }
2437
- };
2438
- var EditCommentError = class extends Error {
2439
- constructor(cause, context) {
2440
- super("Edit comment failed.");
2441
- this.cause = cause;
2442
- this.context = context;
2443
- this.name = "EditCommentError";
2444
- }
2445
- };
2446
- var DeleteCommentError = class extends Error {
2447
- constructor(cause, context) {
2448
- super("Delete comment failed.");
2449
- this.cause = cause;
2450
- this.context = context;
2451
- this.name = "DeleteCommentError";
2452
- }
2453
- };
2454
- var AddReactionError = class extends Error {
2455
- constructor(cause, context) {
2456
- super("Add reaction failed.");
2457
- this.cause = cause;
2458
- this.context = context;
2459
- this.name = "AddReactionError";
2460
- }
2461
- };
2462
- var RemoveReactionError = class extends Error {
2463
- constructor(cause, context) {
2464
- super("Remove reaction failed.");
2465
- this.cause = cause;
2466
- this.context = context;
2467
- this.name = "RemoveReactionError";
2468
- }
2469
- };
2470
- var MarkInboxNotificationAsReadError = class extends Error {
2471
- constructor(cause, context) {
2472
- super("Mark inbox notification as read failed.");
2473
- this.cause = cause;
2474
- this.context = context;
2475
- this.name = "MarkInboxNotificationAsReadError";
2476
- }
2477
- };
2478
- var UpdateNotificationSettingsError = class extends Error {
2479
- constructor(cause, context) {
2480
- super("Update notification settings failed.");
2481
- this.cause = cause;
2482
- this.context = context;
2483
- this.name = "UpdateNotificationSettingsError";
2484
- }
2485
- };
2486
-
2487
- // src/use-signal.ts
2488
- var identity2 = (value) => value;
2489
- function useSignal(signal, selector, isEqual) {
2490
- return useSyncExternalStoreWithSelector(
2491
- signal.subscribe,
2492
- signal.get,
2493
- signal.get,
2494
- _nullishCoalesce(selector, () => ( identity2)),
2495
- isEqual
2252
+ function useErrorListener(callback) {
2253
+ const client = useClient();
2254
+ const savedCallback = useLatest(callback);
2255
+ _react.useEffect.call(void 0,
2256
+ () => client.events.error.subscribe((e) => savedCallback.current(e)),
2257
+ [client, savedCallback]
2496
2258
  );
2497
2259
  }
2498
2260
 
@@ -2600,14 +2362,6 @@ function getCurrentUserId(client) {
2600
2362
  }
2601
2363
  return userId;
2602
2364
  }
2603
- function handleApiError(err) {
2604
- const message = `Request failed with status ${err.status}: ${err.message}`;
2605
- if (_optionalChain([err, 'access', _12 => _12.details, 'optionalAccess', _13 => _13.error]) === "FORBIDDEN") {
2606
- const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
2607
- _core.console.error(detailedMessage);
2608
- }
2609
- return new Error(message);
2610
- }
2611
2365
  var _extras2 = /* @__PURE__ */ new WeakMap();
2612
2366
  var _bundles2 = /* @__PURE__ */ new WeakMap();
2613
2367
  function getOrCreateRoomContextBundle(client) {
@@ -2628,87 +2382,74 @@ function getRoomExtrasForClient(client) {
2628
2382
  }
2629
2383
  function makeRoomExtrasForClient(client) {
2630
2384
  const store = getUmbrellaStoreForClient(client);
2631
- const commentsErrorEventSource = _core.makeEventSource.call(void 0, );
2632
- function onMutationFailure(innerError, optimisticId, createPublicError) {
2385
+ function onMutationFailure(optimisticId, context, innerError) {
2633
2386
  store.optimisticUpdates.remove(optimisticId);
2634
2387
  if (innerError instanceof _core.HttpError) {
2635
- const error = handleApiError(innerError);
2636
- commentsErrorEventSource.notify(createPublicError(error));
2637
- return;
2638
- }
2639
- if (innerError instanceof _core.HttpError) {
2640
- handleApiError(innerError);
2641
- return;
2642
- }
2643
- throw innerError;
2644
- }
2645
- const threadsPollersByRoomId = /* @__PURE__ */ new Map();
2646
- const versionsPollersByRoomId = /* @__PURE__ */ new Map();
2647
- const roomNotificationSettingsPollersByRoomId = /* @__PURE__ */ new Map();
2648
- function getOrCreateThreadsPollerForRoomId(roomId) {
2649
- let poller = threadsPollersByRoomId.get(roomId);
2650
- if (!poller) {
2651
- poller = _core.makePoller.call(void 0,
2652
- async (signal) => {
2653
- try {
2654
- return await store.fetchRoomThreadsDeltaUpdate(roomId, signal);
2655
- } catch (err) {
2656
- _core.console.warn(`Polling new threads for '${roomId}' failed: ${String(err)}`);
2657
- throw err;
2658
- }
2659
- },
2660
- config.ROOM_THREADS_POLL_INTERVAL,
2661
- { maxStaleTimeMs: config.ROOM_THREADS_MAX_STALE_TIME }
2662
- );
2663
- threadsPollersByRoomId.set(roomId, poller);
2664
- }
2665
- return poller;
2666
- }
2667
- function getOrCreateVersionsPollerForRoomId(roomId) {
2668
- let poller = versionsPollersByRoomId.get(roomId);
2669
- if (!poller) {
2670
- poller = _core.makePoller.call(void 0,
2671
- async (signal) => {
2672
- try {
2673
- return await store.fetchRoomVersionsDeltaUpdate(roomId, signal);
2674
- } catch (err) {
2675
- _core.console.warn(`Polling new history versions for '${roomId}' failed: ${String(err)}`);
2676
- throw err;
2677
- }
2678
- },
2679
- config.HISTORY_VERSIONS_POLL_INTERVAL,
2680
- { maxStaleTimeMs: config.HISTORY_VERSIONS_MAX_STALE_TIME }
2681
- );
2682
- versionsPollersByRoomId.set(roomId, poller);
2683
- }
2684
- return poller;
2685
- }
2686
- function getOrCreateNotificationsSettingsPollerForRoomId(roomId) {
2687
- let poller = roomNotificationSettingsPollersByRoomId.get(roomId);
2688
- if (!poller) {
2689
- poller = _core.makePoller.call(void 0,
2690
- async (signal) => {
2691
- try {
2692
- return await store.refreshRoomNotificationSettings(roomId, signal);
2693
- } catch (err) {
2694
- _core.console.warn(`Polling notification settings for '${roomId}' failed: ${String(err)}`);
2695
- throw err;
2696
- }
2697
- },
2698
- config.NOTIFICATION_SETTINGS_POLL_INTERVAL,
2699
- { maxStaleTimeMs: config.NOTIFICATION_SETTINGS_MAX_STALE_TIME }
2700
- );
2701
- roomNotificationSettingsPollersByRoomId.set(roomId, poller);
2388
+ if (innerError.status === 403) {
2389
+ const detailedMessage = [
2390
+ innerError.message,
2391
+ _optionalChain([innerError, 'access', _14 => _14.details, 'optionalAccess', _15 => _15.suggestion]),
2392
+ _optionalChain([innerError, 'access', _16 => _16.details, 'optionalAccess', _17 => _17.docs])
2393
+ ].filter(Boolean).join("\n");
2394
+ _core.console.error(detailedMessage);
2395
+ }
2396
+ client[_core.kInternal].emitError(context, innerError);
2397
+ } else {
2398
+ throw innerError;
2702
2399
  }
2703
- return poller;
2704
2400
  }
2401
+ const threadsPollersByRoomId = new (0, _core.DefaultMap)(
2402
+ (roomId) => _core.makePoller.call(void 0,
2403
+ async (signal) => {
2404
+ try {
2405
+ return await store.fetchRoomThreadsDeltaUpdate(roomId, signal);
2406
+ } catch (err) {
2407
+ _core.console.warn(`Polling new threads for '${roomId}' failed: ${String(err)}`);
2408
+ throw err;
2409
+ }
2410
+ },
2411
+ config.ROOM_THREADS_POLL_INTERVAL,
2412
+ { maxStaleTimeMs: config.ROOM_THREADS_MAX_STALE_TIME }
2413
+ )
2414
+ );
2415
+ const versionsPollersByRoomId = new (0, _core.DefaultMap)(
2416
+ (roomId) => _core.makePoller.call(void 0,
2417
+ async (signal) => {
2418
+ try {
2419
+ return await store.fetchRoomVersionsDeltaUpdate(roomId, signal);
2420
+ } catch (err) {
2421
+ _core.console.warn(`Polling new history versions for '${roomId}' failed: ${String(err)}`);
2422
+ throw err;
2423
+ }
2424
+ },
2425
+ config.HISTORY_VERSIONS_POLL_INTERVAL,
2426
+ { maxStaleTimeMs: config.HISTORY_VERSIONS_MAX_STALE_TIME }
2427
+ )
2428
+ );
2429
+ const roomNotificationSettingsPollersByRoomId = new (0, _core.DefaultMap)(
2430
+ (roomId) => _core.makePoller.call(void 0,
2431
+ async (signal) => {
2432
+ try {
2433
+ return await store.refreshRoomNotificationSettings(roomId, signal);
2434
+ } catch (err) {
2435
+ _core.console.warn(`Polling notification settings for '${roomId}' failed: ${String(err)}`);
2436
+ throw err;
2437
+ }
2438
+ },
2439
+ config.NOTIFICATION_SETTINGS_POLL_INTERVAL,
2440
+ { maxStaleTimeMs: config.NOTIFICATION_SETTINGS_MAX_STALE_TIME }
2441
+ )
2442
+ );
2705
2443
  return {
2706
2444
  store,
2707
- commentsErrorEventSource: commentsErrorEventSource.observable,
2708
2445
  onMutationFailure,
2709
- getOrCreateThreadsPollerForRoomId,
2710
- getOrCreateVersionsPollerForRoomId,
2711
- getOrCreateNotificationsSettingsPollerForRoomId
2446
+ getOrCreateThreadsPollerForRoomId: threadsPollersByRoomId.getOrCreate.bind(
2447
+ threadsPollersByRoomId
2448
+ ),
2449
+ getOrCreateVersionsPollerForRoomId: versionsPollersByRoomId.getOrCreate.bind(versionsPollersByRoomId),
2450
+ getOrCreateNotificationsSettingsPollerForRoomId: roomNotificationSettingsPollersByRoomId.getOrCreate.bind(
2451
+ roomNotificationSettingsPollersByRoomId
2452
+ )
2712
2453
  };
2713
2454
  }
2714
2455
  function makeRoomContextBundle(client) {
@@ -2726,7 +2467,6 @@ function makeRoomContextBundle(client) {
2726
2467
  useBroadcastEvent,
2727
2468
  useOthersListener,
2728
2469
  useLostConnectionListener,
2729
- useErrorListener,
2730
2470
  useEventListener,
2731
2471
  useHistory,
2732
2472
  useUndo,
@@ -2772,7 +2512,6 @@ function makeRoomContextBundle(client) {
2772
2512
  useBroadcastEvent,
2773
2513
  useOthersListener,
2774
2514
  useLostConnectionListener,
2775
- useErrorListener,
2776
2515
  useEventListener,
2777
2516
  useHistory,
2778
2517
  useUndo,
@@ -2808,8 +2547,7 @@ function makeRoomContextBundle(client) {
2808
2547
  useRoomNotificationSettings: useRoomNotificationSettingsSuspense,
2809
2548
  useUpdateRoomNotificationSettings,
2810
2549
  ...shared.suspense
2811
- },
2812
- useCommentsErrorListener
2550
+ }
2813
2551
  };
2814
2552
  return Object.defineProperty(bundle, _core.kInternal, {
2815
2553
  enumerable: false
@@ -2852,7 +2590,7 @@ function RoomProviderInner(props) {
2852
2590
  "RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required"
2853
2591
  );
2854
2592
  }
2855
- if (!isString(roomId)) {
2593
+ if (typeof roomId !== "string") {
2856
2594
  throw new Error("RoomProvider id property should be a string.");
2857
2595
  }
2858
2596
  const majorReactVersion = parseInt(_react.version) || 1;
@@ -2887,7 +2625,7 @@ function RoomProviderInner(props) {
2887
2625
  return;
2888
2626
  }
2889
2627
  const { thread, inboxNotification: maybeNotification } = info;
2890
- const existingThread = store.get1_threads().threadsDB.getEvenIfDeleted(message.threadId);
2628
+ const existingThread = store.outputs.threads.get().getEvenIfDeleted(message.threadId);
2891
2629
  switch (message.type) {
2892
2630
  case _core.ServerMsgCode.COMMENT_EDITED:
2893
2631
  case _core.ServerMsgCode.THREAD_METADATA_UPDATED:
@@ -3005,7 +2743,7 @@ function useMentionSuggestionsCache() {
3005
2743
  return client[_core.kInternal].mentionSuggestionsCache;
3006
2744
  }
3007
2745
  function useStorageStatus(options) {
3008
- const smooth = useInitial(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _14 => _14.smooth]), () => ( false)));
2746
+ const smooth = useInitial(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _18 => _18.smooth]), () => ( false)));
3009
2747
  if (smooth) {
3010
2748
  return useStorageStatusSmooth();
3011
2749
  } else {
@@ -3070,14 +2808,6 @@ function useLostConnectionListener(callback) {
3070
2808
  [room, savedCallback]
3071
2809
  );
3072
2810
  }
3073
- function useErrorListener(callback) {
3074
- const room = useRoom();
3075
- const savedCallback = useLatest(callback);
3076
- _react.useEffect.call(void 0,
3077
- () => room.events.error.subscribe((e) => savedCallback.current(e)),
3078
- [room, savedCallback]
3079
- );
3080
- }
3081
2811
  function useEventListener(callback) {
3082
2812
  const room = useRoom();
3083
2813
  const savedCallback = useLatest(callback);
@@ -3258,18 +2988,15 @@ function useMutation(callback, deps) {
3258
2988
  [room, ...deps]
3259
2989
  );
3260
2990
  }
3261
- function useThreads(options = {
3262
- query: { metadata: {} }
3263
- }) {
2991
+ function useThreads(options = {}) {
3264
2992
  const { scrollOnLoad = true } = options;
3265
2993
  const client = useClient();
3266
2994
  const room = useRoom();
3267
2995
  const { store, getOrCreateThreadsPollerForRoomId } = getRoomExtrasForClient(client);
2996
+ const queryKey = makeRoomThreadsQueryKey(room.id, options.query);
3268
2997
  const poller = getOrCreateThreadsPollerForRoomId(room.id);
3269
2998
  _react.useEffect.call(void 0,
3270
- () => {
3271
- void store.waitUntilRoomThreadsLoaded(room.id, options.query);
3272
- }
2999
+ () => void store.outputs.loadingRoomThreads.getOrCreate(queryKey).waitUntilLoaded()
3273
3000
  // NOTE: Deliberately *not* using a dependency array here!
3274
3001
  //
3275
3002
  // It is important to call waitUntil on *every* render.
@@ -3284,28 +3011,11 @@ function useThreads(options = {
3284
3011
  poller.pollNowIfStale();
3285
3012
  return () => poller.dec();
3286
3013
  }, [poller]);
3287
- const getter = _react.useCallback.call(void 0,
3288
- () => store.getRoomThreadsLoadingState(room.id, options.query),
3289
- [store, room.id, options.query]
3014
+ const result = useSignal(
3015
+ store.outputs.loadingRoomThreads.getOrCreate(queryKey).signal
3290
3016
  );
3291
- const state = useSyncExternalStoreWithSelector(
3292
- store.subscribe1_threads,
3293
- getter,
3294
- getter,
3295
- identity3,
3296
- shallow2
3297
- // NOTE: Using 2-level-deep shallow check here, because the result of selectThreads() is not stable!
3298
- );
3299
- useScrollToCommentOnLoadEffect(scrollOnLoad, state);
3300
- return state;
3301
- }
3302
- function useCommentsErrorListener(callback) {
3303
- const client = useClient();
3304
- const savedCallback = useLatest(callback);
3305
- const { commentsErrorEventSource } = getRoomExtrasForClient(client);
3306
- _react.useEffect.call(void 0, () => {
3307
- return commentsErrorEventSource.subscribe(savedCallback.current);
3308
- }, [savedCallback, commentsErrorEventSource]);
3017
+ useScrollToCommentOnLoadEffect(scrollOnLoad, result);
3018
+ return result;
3309
3019
  }
3310
3020
  function useCreateThread() {
3311
3021
  return useCreateRoomThread(useRoom().id);
@@ -3347,7 +3057,7 @@ function useCreateRoomThread(roomId) {
3347
3057
  thread: newThread,
3348
3058
  roomId
3349
3059
  });
3350
- const attachmentIds = _optionalChain([attachments, 'optionalAccess', _15 => _15.map, 'call', _16 => _16((attachment) => attachment.id)]);
3060
+ const attachmentIds = _optionalChain([attachments, 'optionalAccess', _19 => _19.map, 'call', _20 => _20((attachment) => attachment.id)]);
3351
3061
  client[_core.kInternal].httpClient.createThread({
3352
3062
  roomId,
3353
3063
  threadId,
@@ -3360,15 +3070,16 @@ function useCreateRoomThread(roomId) {
3360
3070
  store.createThread(optimisticId, thread);
3361
3071
  },
3362
3072
  (err) => onMutationFailure(
3363
- err,
3364
3073
  optimisticId,
3365
- (err2) => new CreateThreadError(err2, {
3074
+ {
3075
+ type: "CREATE_THREAD_ERROR",
3366
3076
  roomId,
3367
3077
  threadId,
3368
3078
  commentId,
3369
3079
  body,
3370
3080
  metadata
3371
- })
3081
+ },
3082
+ err
3372
3083
  )
3373
3084
  );
3374
3085
  return newThread;
@@ -3385,8 +3096,8 @@ function useDeleteRoomThread(roomId) {
3385
3096
  (threadId) => {
3386
3097
  const { store, onMutationFailure } = getRoomExtrasForClient(client);
3387
3098
  const userId = getCurrentUserId(client);
3388
- const existing = store.get1_threads().threadsDB.get(threadId);
3389
- if (_optionalChain([existing, 'optionalAccess', _17 => _17.comments, 'optionalAccess', _18 => _18[0], 'optionalAccess', _19 => _19.userId]) !== userId) {
3099
+ const existing = store.outputs.threads.get().get(threadId);
3100
+ if (_optionalChain([existing, 'optionalAccess', _21 => _21.comments, 'optionalAccess', _22 => _22[0], 'optionalAccess', _23 => _23.userId]) !== userId) {
3390
3101
  throw new Error("Only the thread creator can delete the thread");
3391
3102
  }
3392
3103
  const optimisticId = store.optimisticUpdates.add({
@@ -3400,9 +3111,9 @@ function useDeleteRoomThread(roomId) {
3400
3111
  store.deleteThread(threadId, optimisticId);
3401
3112
  },
3402
3113
  (err) => onMutationFailure(
3403
- err,
3404
3114
  optimisticId,
3405
- (err2) => new DeleteThreadError(err2, { roomId, threadId })
3115
+ { type: "DELETE_THREAD_ERROR", roomId, threadId },
3116
+ err
3406
3117
  )
3407
3118
  );
3408
3119
  },
@@ -3435,13 +3146,14 @@ function useEditRoomThreadMetadata(roomId) {
3435
3146
  store.patchThread(threadId, optimisticId, { metadata: metadata2 }, updatedAt)
3436
3147
  ),
3437
3148
  (err) => onMutationFailure(
3438
- err,
3439
3149
  optimisticId,
3440
- (error) => new EditThreadMetadataError(error, {
3150
+ {
3151
+ type: "EDIT_THREAD_METADATA_ERROR",
3441
3152
  roomId,
3442
3153
  threadId,
3443
3154
  metadata
3444
- })
3155
+ },
3156
+ err
3445
3157
  )
3446
3158
  );
3447
3159
  },
@@ -3473,20 +3185,21 @@ function useCreateRoomComment(roomId) {
3473
3185
  type: "create-comment",
3474
3186
  comment
3475
3187
  });
3476
- const attachmentIds = _optionalChain([attachments, 'optionalAccess', _20 => _20.map, 'call', _21 => _21((attachment) => attachment.id)]);
3188
+ const attachmentIds = _optionalChain([attachments, 'optionalAccess', _24 => _24.map, 'call', _25 => _25((attachment) => attachment.id)]);
3477
3189
  client[_core.kInternal].httpClient.createComment({ roomId, threadId, commentId, body, attachmentIds }).then(
3478
3190
  (newComment) => {
3479
3191
  store.createComment(newComment, optimisticId);
3480
3192
  },
3481
3193
  (err) => onMutationFailure(
3482
- err,
3483
3194
  optimisticId,
3484
- (err2) => new CreateCommentError(err2, {
3195
+ {
3196
+ type: "CREATE_COMMENT_ERROR",
3485
3197
  roomId,
3486
3198
  threadId,
3487
3199
  commentId,
3488
3200
  body
3489
- })
3201
+ },
3202
+ err
3490
3203
  )
3491
3204
  );
3492
3205
  return comment;
@@ -3503,7 +3216,7 @@ function useEditRoomComment(roomId) {
3503
3216
  ({ threadId, commentId, body, attachments }) => {
3504
3217
  const editedAt = /* @__PURE__ */ new Date();
3505
3218
  const { store, onMutationFailure } = getRoomExtrasForClient(client);
3506
- const existing = store.get1_threads().threadsDB.getEvenIfDeleted(threadId);
3219
+ const existing = store.outputs.threads.get().getEvenIfDeleted(threadId);
3507
3220
  if (existing === void 0) {
3508
3221
  _core.console.warn(
3509
3222
  `Internal unexpected behavior. Cannot edit comment in thread "${threadId}" because the thread does not exist in the cache.`
@@ -3528,20 +3241,15 @@ function useEditRoomComment(roomId) {
3528
3241
  attachments: _nullishCoalesce(attachments, () => ( []))
3529
3242
  }
3530
3243
  });
3531
- const attachmentIds = _optionalChain([attachments, 'optionalAccess', _22 => _22.map, 'call', _23 => _23((attachment) => attachment.id)]);
3244
+ const attachmentIds = _optionalChain([attachments, 'optionalAccess', _26 => _26.map, 'call', _27 => _27((attachment) => attachment.id)]);
3532
3245
  client[_core.kInternal].httpClient.editComment({ roomId, threadId, commentId, body, attachmentIds }).then(
3533
3246
  (editedComment) => {
3534
3247
  store.editComment(threadId, optimisticId, editedComment);
3535
3248
  },
3536
3249
  (err) => onMutationFailure(
3537
- err,
3538
3250
  optimisticId,
3539
- (error) => new EditCommentError(error, {
3540
- roomId,
3541
- threadId,
3542
- commentId,
3543
- body
3544
- })
3251
+ { type: "EDIT_COMMENT_ERROR", roomId, threadId, commentId, body },
3252
+ err
3545
3253
  )
3546
3254
  );
3547
3255
  },
@@ -3569,13 +3277,9 @@ function useDeleteRoomComment(roomId) {
3569
3277
  store.deleteComment(threadId, optimisticId, commentId, deletedAt);
3570
3278
  },
3571
3279
  (err) => onMutationFailure(
3572
- err,
3573
3280
  optimisticId,
3574
- (error) => new DeleteCommentError(error, {
3575
- roomId,
3576
- threadId,
3577
- commentId
3578
- })
3281
+ { type: "DELETE_COMMENT_ERROR", roomId, threadId, commentId },
3282
+ err
3579
3283
  )
3580
3284
  );
3581
3285
  },
@@ -3613,14 +3317,15 @@ function useAddRoomCommentReaction(roomId) {
3613
3317
  );
3614
3318
  },
3615
3319
  (err) => onMutationFailure(
3616
- err,
3617
3320
  optimisticId,
3618
- (error) => new AddReactionError(error, {
3321
+ {
3322
+ type: "ADD_REACTION_ERROR",
3619
3323
  roomId,
3620
3324
  threadId,
3621
3325
  commentId,
3622
3326
  emoji
3623
- })
3327
+ },
3328
+ err
3624
3329
  )
3625
3330
  );
3626
3331
  },
@@ -3657,14 +3362,15 @@ function useRemoveRoomCommentReaction(roomId) {
3657
3362
  );
3658
3363
  },
3659
3364
  (err) => onMutationFailure(
3660
- err,
3661
3365
  optimisticId,
3662
- (error) => new RemoveReactionError(error, {
3366
+ {
3367
+ type: "REMOVE_REACTION_ERROR",
3663
3368
  roomId,
3664
3369
  threadId,
3665
3370
  commentId,
3666
3371
  emoji
3667
- })
3372
+ },
3373
+ err
3668
3374
  )
3669
3375
  );
3670
3376
  },
@@ -3680,7 +3386,7 @@ function useMarkRoomThreadAsRead(roomId) {
3680
3386
  (threadId) => {
3681
3387
  const { store, onMutationFailure } = getRoomExtrasForClient(client);
3682
3388
  const inboxNotification = Object.values(
3683
- store.get1_notifications().notificationsById
3389
+ store.outputs.notifications.get().notificationsById
3684
3390
  ).find(
3685
3391
  (inboxNotification2) => inboxNotification2.kind === "thread" && inboxNotification2.threadId === threadId
3686
3392
  );
@@ -3704,11 +3410,13 @@ function useMarkRoomThreadAsRead(roomId) {
3704
3410
  },
3705
3411
  (err) => {
3706
3412
  onMutationFailure(
3707
- err,
3708
3413
  optimisticId,
3709
- (error) => new MarkInboxNotificationAsReadError(error, {
3414
+ {
3415
+ type: "MARK_INBOX_NOTIFICATION_AS_READ_ERROR",
3416
+ roomId,
3710
3417
  inboxNotificationId: inboxNotification.id
3711
- })
3418
+ },
3419
+ err
3712
3420
  );
3713
3421
  return;
3714
3422
  }
@@ -3741,12 +3449,9 @@ function useMarkRoomThreadAsResolved(roomId) {
3741
3449
  );
3742
3450
  },
3743
3451
  (err) => onMutationFailure(
3744
- err,
3745
3452
  optimisticId,
3746
- (error) => new MarkThreadAsResolvedError(error, {
3747
- roomId,
3748
- threadId
3749
- })
3453
+ { type: "MARK_THREAD_AS_RESOLVED_ERROR", roomId, threadId },
3454
+ err
3750
3455
  )
3751
3456
  );
3752
3457
  },
@@ -3777,12 +3482,9 @@ function useMarkRoomThreadAsUnresolved(roomId) {
3777
3482
  );
3778
3483
  },
3779
3484
  (err) => onMutationFailure(
3780
- err,
3781
3485
  optimisticId,
3782
- (error) => new MarkThreadAsUnresolvedError(error, {
3783
- roomId,
3784
- threadId
3785
- })
3486
+ { type: "MARK_THREAD_AS_UNRESOLVED_ERROR", roomId, threadId },
3487
+ err
3786
3488
  )
3787
3489
  );
3788
3490
  },
@@ -3818,9 +3520,7 @@ function useRoomNotificationSettings() {
3818
3520
  const { store, getOrCreateNotificationsSettingsPollerForRoomId } = getRoomExtrasForClient(client);
3819
3521
  const poller = getOrCreateNotificationsSettingsPollerForRoomId(room.id);
3820
3522
  _react.useEffect.call(void 0,
3821
- () => {
3822
- void store.waitUntilRoomNotificationSettingsLoaded(room.id);
3823
- }
3523
+ () => void store.outputs.settingsByRoomId.getOrCreate(room.id).waitUntilLoaded()
3824
3524
  // NOTE: Deliberately *not* using a dependency array here!
3825
3525
  //
3826
3526
  // It is important to call waitUntil on *every* render.
@@ -3837,16 +3537,8 @@ function useRoomNotificationSettings() {
3837
3537
  poller.dec();
3838
3538
  };
3839
3539
  }, [poller]);
3840
- const getter = _react.useCallback.call(void 0,
3841
- () => store.getNotificationSettingsLoadingState(room.id),
3842
- [store, room.id]
3843
- );
3844
- const settings = useSyncExternalStoreWithSelector(
3845
- store.subscribe2,
3846
- getter,
3847
- getter,
3848
- identity3,
3849
- shallow2
3540
+ const settings = useSignal(
3541
+ store.outputs.settingsByRoomId.getOrCreate(room.id).signal
3850
3542
  );
3851
3543
  return _react.useMemo.call(void 0, () => {
3852
3544
  return [settings, updateRoomNotificationSettings];
@@ -3856,7 +3548,7 @@ function useRoomNotificationSettingsSuspense() {
3856
3548
  const client = useClient();
3857
3549
  const store = getRoomExtrasForClient(client).store;
3858
3550
  const room = useRoom();
3859
- use(store.waitUntilRoomNotificationSettingsLoaded(room.id));
3551
+ use(store.outputs.settingsByRoomId.getOrCreate(room.id).waitUntilLoaded());
3860
3552
  const [settings, updateRoomNotificationSettings] = useRoomNotificationSettings();
3861
3553
  _core.assert.call(void 0, !settings.error, "Did not expect error");
3862
3554
  _core.assert.call(void 0, !settings.isLoading, "Did not expect loading");
@@ -3903,14 +3595,8 @@ function useHistoryVersions() {
3903
3595
  poller.pollNowIfStale();
3904
3596
  return () => poller.dec();
3905
3597
  }, [poller]);
3906
- const getter = _react.useCallback.call(void 0,
3907
- () => store.getRoomVersionsLoadingState(room.id),
3908
- [store, room.id]
3909
- );
3910
3598
  _react.useEffect.call(void 0,
3911
- () => {
3912
- void store.waitUntilRoomVersionsLoaded(room.id);
3913
- }
3599
+ () => void store.outputs.versionsByRoomId.getOrCreate(room.id).waitUntilLoaded()
3914
3600
  // NOTE: Deliberately *not* using a dependency array here!
3915
3601
  //
3916
3602
  // It is important to call waitUntil on *every* render.
@@ -3920,20 +3606,13 @@ function useHistoryVersions() {
3920
3606
  // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very
3921
3607
  // *next* render after that, a *new* fetch/promise will get created.
3922
3608
  );
3923
- const state = useSyncExternalStoreWithSelector(
3924
- store.subscribe3,
3925
- getter,
3926
- getter,
3927
- identity3,
3928
- shallow2
3929
- );
3930
- return state;
3609
+ return useSignal(store.outputs.versionsByRoomId.getOrCreate(room.id).signal);
3931
3610
  }
3932
3611
  function useHistoryVersionsSuspense() {
3933
3612
  const client = useClient();
3934
3613
  const room = useRoom();
3935
3614
  const store = getRoomExtrasForClient(client).store;
3936
- use(store.waitUntilRoomVersionsLoaded(room.id));
3615
+ use(store.outputs.versionsByRoomId.getOrCreate(room.id).waitUntilLoaded());
3937
3616
  const result = useHistoryVersions();
3938
3617
  _core.assert.call(void 0, !result.error, "Did not expect error");
3939
3618
  _core.assert.call(void 0, !result.isLoading, "Did not expect loading");
@@ -3955,11 +3634,9 @@ function useUpdateRoomNotificationSettings() {
3955
3634
  store.updateRoomNotificationSettings(room.id, optimisticId, settings2);
3956
3635
  },
3957
3636
  (err) => onMutationFailure(
3958
- err,
3959
3637
  optimisticId,
3960
- (error) => new UpdateNotificationSettingsError(error, {
3961
- roomId: room.id
3962
- })
3638
+ { type: "UPDATE_NOTIFICATION_SETTINGS_ERROR", roomId: room.id },
3639
+ err
3963
3640
  )
3964
3641
  );
3965
3642
  },
@@ -4020,20 +3697,19 @@ function useStorageStatusSuspense(options) {
4020
3697
  useSuspendUntilStorageReady();
4021
3698
  return useStorageStatus(options);
4022
3699
  }
4023
- function useThreadsSuspense(options = {
4024
- query: { metadata: {} }
4025
- }) {
3700
+ function useThreadsSuspense(options = {}) {
4026
3701
  const client = useClient();
4027
3702
  const room = useRoom();
4028
3703
  const { store } = getRoomExtrasForClient(client);
4029
- use(store.waitUntilRoomThreadsLoaded(room.id, options.query));
3704
+ const queryKey = makeRoomThreadsQueryKey(room.id, options.query);
3705
+ use(store.outputs.loadingRoomThreads.getOrCreate(queryKey).waitUntilLoaded());
4030
3706
  const result = useThreads(options);
4031
3707
  _core.assert.call(void 0, !result.error, "Did not expect error");
4032
3708
  _core.assert.call(void 0, !result.isLoading, "Did not expect loading");
4033
3709
  return result;
4034
3710
  }
4035
3711
  function selectorFor_useAttachmentUrl(state) {
4036
- if (state === void 0 || _optionalChain([state, 'optionalAccess', _24 => _24.isLoading])) {
3712
+ if (state === void 0 || _optionalChain([state, 'optionalAccess', _28 => _28.isLoading])) {
4037
3713
  return _nullishCoalesce(state, () => ( { isLoading: true }));
4038
3714
  }
4039
3715
  if (state.error) {
@@ -4053,11 +3729,11 @@ function useRoomAttachmentUrl(attachmentId, roomId) {
4053
3729
  const client = useClient();
4054
3730
  const store = client[_core.kInternal].httpClient.getOrCreateAttachmentUrlsStore(roomId);
4055
3731
  const getAttachmentUrlState = _react.useCallback.call(void 0,
4056
- () => store.getState(attachmentId),
3732
+ () => store.getItemState(attachmentId),
4057
3733
  [store, attachmentId]
4058
3734
  );
4059
3735
  _react.useEffect.call(void 0, () => {
4060
- void store.get(attachmentId);
3736
+ void store.enqueue(attachmentId);
4061
3737
  }, [store, attachmentId]);
4062
3738
  return useSyncExternalStoreWithSelector(
4063
3739
  store.subscribe,
@@ -4071,12 +3747,12 @@ function useAttachmentUrlSuspense(attachmentId) {
4071
3747
  const room = useRoom();
4072
3748
  const { attachmentUrlsStore } = room[_core.kInternal];
4073
3749
  const getAttachmentUrlState = _react.useCallback.call(void 0,
4074
- () => attachmentUrlsStore.getState(attachmentId),
3750
+ () => attachmentUrlsStore.getItemState(attachmentId),
4075
3751
  [attachmentUrlsStore, attachmentId]
4076
3752
  );
4077
3753
  const attachmentUrlState = getAttachmentUrlState();
4078
3754
  if (!attachmentUrlState || attachmentUrlState.isLoading) {
4079
- throw attachmentUrlsStore.get(attachmentId);
3755
+ throw attachmentUrlsStore.enqueue(attachmentId);
4080
3756
  }
4081
3757
  if (attachmentUrlState.error) {
4082
3758
  throw attachmentUrlState.error;
@@ -4095,12 +3771,13 @@ function useAttachmentUrlSuspense(attachmentId) {
4095
3771
  error: void 0
4096
3772
  };
4097
3773
  }
3774
+ var NO_PERMISSIONS = /* @__PURE__ */ new Set();
4098
3775
  function useRoomPermissions(roomId) {
4099
3776
  const client = useClient();
4100
3777
  const store = getRoomExtrasForClient(client).store;
4101
3778
  return useSignal(
4102
3779
  store.permissionHints.signal,
4103
- (hints) => _nullishCoalesce(hints[roomId], () => ( /* @__PURE__ */ new Set()))
3780
+ (hints) => _nullishCoalesce(hints.get(roomId), () => ( NO_PERMISSIONS))
4104
3781
  );
4105
3782
  }
4106
3783
  function createRoomContext(client) {
@@ -4247,7 +3924,5 @@ var _useUpdateMyPresence = useUpdateMyPresence;
4247
3924
 
4248
3925
 
4249
3926
 
4250
-
4251
-
4252
- exports.RoomContext = RoomContext; exports.useRoomOrNull = useRoomOrNull; exports.useSyncExternalStoreWithSelector = useSyncExternalStoreWithSelector; exports.ClientContext = ClientContext; exports.getUmbrellaStoreForClient = getUmbrellaStoreForClient; exports.useClientOrNull = useClientOrNull; 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.useSyncStatus = useSyncStatus; exports.CreateThreadError = CreateThreadError; exports.useSignal = useSignal; exports.useStatus = useStatus; exports.useReportTextEditor = useReportTextEditor; exports.useYjsProvider = useYjsProvider; exports.useCreateTextMention = useCreateTextMention; exports.useDeleteTextMention = useDeleteTextMention; exports.useResolveMentionSuggestions = useResolveMentionSuggestions; exports.useMentionSuggestionsCache = useMentionSuggestionsCache; 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.useCreateRoomThread = useCreateRoomThread; exports.useDeleteRoomThread = useDeleteRoomThread; exports.useEditRoomThreadMetadata = useEditRoomThreadMetadata; exports.useCreateComment = useCreateComment; exports.useCreateRoomComment = useCreateRoomComment; exports.useEditComment = useEditComment; exports.useEditRoomComment = useEditRoomComment; exports.useDeleteComment = useDeleteComment; exports.useDeleteRoomComment = useDeleteRoomComment; exports.useAddRoomCommentReaction = useAddRoomCommentReaction; exports.useRemoveReaction = useRemoveReaction; exports.useRemoveRoomCommentReaction = useRemoveRoomCommentReaction; exports.useMarkThreadAsRead = useMarkThreadAsRead; exports.useMarkRoomThreadAsRead = useMarkRoomThreadAsRead; exports.useMarkThreadAsResolved = useMarkThreadAsResolved; exports.useMarkRoomThreadAsResolved = useMarkRoomThreadAsResolved; exports.useMarkThreadAsUnresolved = useMarkThreadAsUnresolved; exports.useMarkRoomThreadAsUnresolved = useMarkRoomThreadAsUnresolved; exports.useThreadSubscription = useThreadSubscription; exports.useHistoryVersionData = useHistoryVersionData; exports.useUpdateRoomNotificationSettings = useUpdateRoomNotificationSettings; exports.useOthersConnectionIdsSuspense = useOthersConnectionIdsSuspense; exports.useStorageStatusSuspense = useStorageStatusSuspense; exports.useAttachmentUrl = useAttachmentUrl; exports.useRoomAttachmentUrl = useRoomAttachmentUrl; exports.useAttachmentUrlSuspense = useAttachmentUrlSuspense; exports.useRoomPermissions = useRoomPermissions; 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._useRoomNotificationSettings = _useRoomNotificationSettings; exports._useRoomNotificationSettingsSuspense = _useRoomNotificationSettingsSuspense; 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;
4253
- //# sourceMappingURL=chunk-NUDMG62P.js.map
3927
+ exports.RoomContext = RoomContext; exports.useRoomOrNull = useRoomOrNull; exports.useSyncExternalStoreWithSelector = useSyncExternalStoreWithSelector; exports.useSignal = useSignal; exports.ClientContext = ClientContext; exports.getUmbrellaStoreForClient = getUmbrellaStoreForClient; exports.useClientOrNull = useClientOrNull; 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.useSyncStatus = useSyncStatus; exports.useErrorListener = useErrorListener; exports.useStatus = useStatus; exports.useReportTextEditor = useReportTextEditor; exports.useYjsProvider = useYjsProvider; exports.useCreateTextMention = useCreateTextMention; exports.useDeleteTextMention = useDeleteTextMention; exports.useResolveMentionSuggestions = useResolveMentionSuggestions; exports.useMentionSuggestionsCache = useMentionSuggestionsCache; exports.useStorageStatus = useStorageStatus; exports.useBatch = useBatch; exports.useLostConnectionListener = useLostConnectionListener; exports.useHistory = useHistory; exports.useUndo = useUndo; exports.useRedo = useRedo; exports.useCanUndo = useCanUndo; exports.useCanRedo = useCanRedo; exports.useOthersConnectionIds = useOthersConnectionIds; exports.useCreateRoomThread = useCreateRoomThread; exports.useDeleteRoomThread = useDeleteRoomThread; exports.useEditRoomThreadMetadata = useEditRoomThreadMetadata; exports.useCreateComment = useCreateComment; exports.useCreateRoomComment = useCreateRoomComment; exports.useEditComment = useEditComment; exports.useEditRoomComment = useEditRoomComment; exports.useDeleteComment = useDeleteComment; exports.useDeleteRoomComment = useDeleteRoomComment; exports.useAddRoomCommentReaction = useAddRoomCommentReaction; exports.useRemoveReaction = useRemoveReaction; exports.useRemoveRoomCommentReaction = useRemoveRoomCommentReaction; exports.useMarkThreadAsRead = useMarkThreadAsRead; exports.useMarkRoomThreadAsRead = useMarkRoomThreadAsRead; exports.useMarkThreadAsResolved = useMarkThreadAsResolved; exports.useMarkRoomThreadAsResolved = useMarkRoomThreadAsResolved; exports.useMarkThreadAsUnresolved = useMarkThreadAsUnresolved; exports.useMarkRoomThreadAsUnresolved = useMarkRoomThreadAsUnresolved; exports.useThreadSubscription = useThreadSubscription; exports.useHistoryVersionData = useHistoryVersionData; exports.useUpdateRoomNotificationSettings = useUpdateRoomNotificationSettings; exports.useOthersConnectionIdsSuspense = useOthersConnectionIdsSuspense; exports.useStorageStatusSuspense = useStorageStatusSuspense; exports.useAttachmentUrl = useAttachmentUrl; exports.useRoomAttachmentUrl = useRoomAttachmentUrl; exports.useAttachmentUrlSuspense = useAttachmentUrlSuspense; exports.useRoomPermissions = useRoomPermissions; 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._useRoomNotificationSettings = _useRoomNotificationSettings; exports._useRoomNotificationSettingsSuspense = _useRoomNotificationSettingsSuspense; 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;
3928
+ //# sourceMappingURL=chunk-NZL5WL5O.js.map