@liveblocks/react 1.2.0-comments5 → 1.2.0-comments6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/index.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/index.ts
2
2
  var _core = require('@liveblocks/core');
3
3
 
4
4
  // src/version.ts
5
5
  var PKG_NAME = "@liveblocks/react";
6
- var PKG_VERSION = "1.2.0-comments5";
6
+ var PKG_VERSION = "1.2.0-comments6";
7
7
  var PKG_FORMAT = "cjs";
8
8
 
9
9
  // src/ClientSideSuspense.tsx
@@ -24,8 +24,485 @@ var _client = require('@liveblocks/client');
24
24
 
25
25
 
26
26
 
27
+
28
+
27
29
  var _withselectorjs = require('use-sync-external-store/shim/with-selector.js');
28
30
 
31
+ // src/comments/CommentsRoom.ts
32
+
33
+
34
+ // ../../node_modules/nanoid/index.js
35
+ var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto);
36
+
37
+ // ../../node_modules/nanoid/url-alphabet/index.js
38
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
39
+
40
+ // ../../node_modules/nanoid/index.js
41
+ var POOL_SIZE_MULTIPLIER = 128;
42
+ var pool;
43
+ var poolOffset;
44
+ var fillPool = (bytes) => {
45
+ if (!pool || pool.length < bytes) {
46
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
47
+ _crypto2.default.randomFillSync(pool);
48
+ poolOffset = 0;
49
+ } else if (poolOffset + bytes > pool.length) {
50
+ _crypto2.default.randomFillSync(pool);
51
+ poolOffset = 0;
52
+ }
53
+ poolOffset += bytes;
54
+ };
55
+ var nanoid = (size = 21) => {
56
+ fillPool(size -= 0);
57
+ let id = "";
58
+ for (let i = poolOffset - size; i < poolOffset; i++) {
59
+ id += urlAlphabet[pool[i] & 63];
60
+ }
61
+ return id;
62
+ };
63
+
64
+ // src/comments/CommentsRoom.ts
65
+ var _indexjs = require('use-sync-external-store/shim/index.js');
66
+
67
+ // src/comments/errors.ts
68
+ var CreateThreadError = class extends Error {
69
+ constructor(cause, context) {
70
+ super("Create thread failed.");
71
+ this.cause = cause;
72
+ this.context = context;
73
+ this.name = "CreateThreadError";
74
+ }
75
+ };
76
+ var EditThreadMetadataError = class extends Error {
77
+ constructor(cause, context) {
78
+ super("Edit thread metadata failed.");
79
+ this.cause = cause;
80
+ this.context = context;
81
+ this.name = "EditThreadMetadataError";
82
+ }
83
+ };
84
+ var CreateCommentError = class extends Error {
85
+ constructor(cause, context) {
86
+ super("Create comment failed.");
87
+ this.cause = cause;
88
+ this.context = context;
89
+ this.name = "CreateCommentError";
90
+ }
91
+ };
92
+ var EditCommentError = class extends Error {
93
+ constructor(cause, context) {
94
+ super("Edit comment failed.");
95
+ this.cause = cause;
96
+ this.context = context;
97
+ this.name = "EditCommentError";
98
+ }
99
+ };
100
+ var DeleteCommentError = class extends Error {
101
+ constructor(cause, context) {
102
+ super("Delete comment failed.");
103
+ this.cause = cause;
104
+ this.context = context;
105
+ this.name = "DeleteCommentError";
106
+ }
107
+ };
108
+
109
+ // src/comments/lib/store.ts
110
+
111
+ function createStore(initialState) {
112
+ let state = initialState;
113
+ const eventSource = _core.makeEventSource.call(void 0, );
114
+ return {
115
+ get() {
116
+ return state;
117
+ },
118
+ set(newState) {
119
+ state = newState;
120
+ eventSource.notify(state);
121
+ },
122
+ subscribe(callback) {
123
+ return eventSource.subscribe(callback);
124
+ },
125
+ subscribeOnce(callback) {
126
+ return eventSource.subscribeOnce(callback);
127
+ },
128
+ subscribersCount() {
129
+ return eventSource.count();
130
+ },
131
+ destroy() {
132
+ return eventSource.clear();
133
+ }
134
+ };
135
+ }
136
+
137
+ // src/comments/CommentsRoom.ts
138
+ var POLLING_INTERVAL_REALTIME = 3e4;
139
+ var POLLING_INTERVAL = 5e3;
140
+ var THREAD_ID_PREFIX = "th";
141
+ var COMMENT_ID_PREFIX = "cm";
142
+ function createOptimisticId(prefix) {
143
+ return `${prefix}_${nanoid()}`;
144
+ }
145
+ function createCommentsRoom(room, errorEventSource) {
146
+ const store = createStore({
147
+ isLoading: true
148
+ });
149
+ let numberOfMutations = 0;
150
+ function endMutation() {
151
+ numberOfMutations--;
152
+ if (numberOfMutations === 0) {
153
+ revalidateThreads();
154
+ }
155
+ }
156
+ function startMutation() {
157
+ pollingHub.threads.stop();
158
+ numberOfMutations++;
159
+ }
160
+ const pollingHub = {
161
+ // TODO: If there's an error, it will currently infinitely retry at the current polling rate → add retry logic
162
+ threads: _core.makePoller.call(void 0, revalidateThreads)
163
+ };
164
+ let unsubscribeRealtimeEvents;
165
+ let unsubscribeRealtimeConnection;
166
+ let realtimeClientConnected = false;
167
+ function getPollingInterval() {
168
+ return realtimeClientConnected ? POLLING_INTERVAL_REALTIME : POLLING_INTERVAL;
169
+ }
170
+ function ensureThreadsAreLoadedForMutations() {
171
+ const state = store.get();
172
+ if (state.isLoading || state.error) {
173
+ throw new Error(
174
+ "Cannot update threads or comments before they are loaded"
175
+ );
176
+ }
177
+ return state.threads;
178
+ }
179
+ async function revalidateThreads() {
180
+ pollingHub.threads.pause();
181
+ if (numberOfMutations === 0) {
182
+ setThreads(await room.getThreads());
183
+ }
184
+ pollingHub.threads.resume();
185
+ }
186
+ function subscribe() {
187
+ if (!unsubscribeRealtimeEvents) {
188
+ unsubscribeRealtimeEvents = room.events.comments.subscribe(() => {
189
+ pollingHub.threads.restart(getPollingInterval());
190
+ revalidateThreads();
191
+ });
192
+ }
193
+ if (!unsubscribeRealtimeConnection) {
194
+ unsubscribeRealtimeConnection = room.events.status.subscribe((status) => {
195
+ const nextRealtimeClientConnected = status === "connected";
196
+ if (nextRealtimeClientConnected !== realtimeClientConnected) {
197
+ realtimeClientConnected = nextRealtimeClientConnected;
198
+ pollingHub.threads.restart(getPollingInterval());
199
+ }
200
+ });
201
+ }
202
+ pollingHub.threads.start(getPollingInterval());
203
+ revalidateThreads();
204
+ return () => {
205
+ pollingHub.threads.stop();
206
+ _optionalChain([unsubscribeRealtimeEvents, 'optionalCall', _ => _()]);
207
+ unsubscribeRealtimeEvents = void 0;
208
+ _optionalChain([unsubscribeRealtimeConnection, 'optionalCall', _2 => _2()]);
209
+ unsubscribeRealtimeConnection = void 0;
210
+ };
211
+ }
212
+ function setThreads(newThreads) {
213
+ store.set({
214
+ threads: newThreads,
215
+ isLoading: false
216
+ });
217
+ }
218
+ function getCurrentUserId() {
219
+ const self = room.getSelf();
220
+ if (self === null || self.id === void 0) {
221
+ return "anonymous";
222
+ } else {
223
+ return self.id;
224
+ }
225
+ }
226
+ function createThread(options) {
227
+ const body = options.body;
228
+ const metadata = "metadata" in options ? options.metadata : {};
229
+ const threads = ensureThreadsAreLoadedForMutations();
230
+ const threadId = createOptimisticId(THREAD_ID_PREFIX);
231
+ const commentId = createOptimisticId(COMMENT_ID_PREFIX);
232
+ const now = (/* @__PURE__ */ new Date()).toISOString();
233
+ const newThread = {
234
+ id: threadId,
235
+ type: "thread",
236
+ createdAt: now,
237
+ roomId: room.id,
238
+ metadata,
239
+ comments: [
240
+ {
241
+ id: commentId,
242
+ createdAt: now,
243
+ type: "comment",
244
+ userId: getCurrentUserId(),
245
+ body
246
+ }
247
+ ]
248
+ };
249
+ setThreads([...threads, newThread]);
250
+ startMutation();
251
+ room.createThread({ threadId, commentId, body, metadata }).catch(
252
+ (er) => errorEventSource.notify(
253
+ new CreateThreadError(er, {
254
+ roomId: room.id,
255
+ threadId,
256
+ commentId,
257
+ body,
258
+ metadata
259
+ })
260
+ )
261
+ ).finally(endMutation);
262
+ return newThread;
263
+ }
264
+ function editThreadMetadata(options) {
265
+ const threadId = options.threadId;
266
+ const metadata = "metadata" in options ? options.metadata : {};
267
+ const threads = ensureThreadsAreLoadedForMutations();
268
+ setThreads(
269
+ threads.map(
270
+ (thread) => thread.id === threadId ? {
271
+ ...thread,
272
+ metadata: {
273
+ ...thread.metadata,
274
+ ...metadata
275
+ }
276
+ } : thread
277
+ )
278
+ );
279
+ startMutation();
280
+ room.editThreadMetadata({ metadata, threadId }).catch(
281
+ (er) => errorEventSource.notify(
282
+ new EditThreadMetadataError(er, {
283
+ roomId: room.id,
284
+ threadId,
285
+ metadata
286
+ })
287
+ )
288
+ ).finally(endMutation);
289
+ }
290
+ function createComment({
291
+ threadId,
292
+ body
293
+ }) {
294
+ const threads = ensureThreadsAreLoadedForMutations();
295
+ const commentId = createOptimisticId(COMMENT_ID_PREFIX);
296
+ const now = (/* @__PURE__ */ new Date()).toISOString();
297
+ const comment = {
298
+ id: commentId,
299
+ threadId,
300
+ roomId: room.id,
301
+ type: "comment",
302
+ createdAt: now,
303
+ userId: getCurrentUserId(),
304
+ mentionedIds: [],
305
+ body
306
+ };
307
+ setThreads(
308
+ threads.map(
309
+ (thread) => thread.id === threadId ? {
310
+ ...thread,
311
+ comments: [...thread.comments, comment]
312
+ } : thread
313
+ )
314
+ );
315
+ startMutation();
316
+ room.createComment({ threadId, commentId, body }).catch(
317
+ (er) => errorEventSource.notify(
318
+ new CreateCommentError(er, {
319
+ roomId: room.id,
320
+ threadId,
321
+ commentId,
322
+ body
323
+ })
324
+ )
325
+ ).finally(endMutation);
326
+ return comment;
327
+ }
328
+ function editComment({ threadId, commentId, body }) {
329
+ const threads = ensureThreadsAreLoadedForMutations();
330
+ const now = (/* @__PURE__ */ new Date()).toISOString();
331
+ setThreads(
332
+ threads.map(
333
+ (thread) => thread.id === threadId ? {
334
+ ...thread,
335
+ comments: thread.comments.map(
336
+ (comment) => comment.id === commentId ? {
337
+ ...comment,
338
+ editedAt: now,
339
+ body
340
+ } : comment
341
+ )
342
+ } : thread
343
+ )
344
+ );
345
+ startMutation();
346
+ room.editComment({ threadId, commentId, body }).catch(
347
+ (er) => errorEventSource.notify(
348
+ new EditCommentError(er, {
349
+ roomId: room.id,
350
+ threadId,
351
+ commentId,
352
+ body
353
+ })
354
+ )
355
+ ).finally(endMutation);
356
+ }
357
+ function deleteComment({ threadId, commentId }) {
358
+ const threads = ensureThreadsAreLoadedForMutations();
359
+ const now = (/* @__PURE__ */ new Date()).toISOString();
360
+ const newThreads = [];
361
+ for (const thread of threads) {
362
+ if (thread.id === threadId) {
363
+ const newThread = {
364
+ ...thread,
365
+ comments: thread.comments.map(
366
+ (comment) => comment.id === commentId ? {
367
+ ...comment,
368
+ deletedAt: now,
369
+ body: void 0,
370
+ mentionedIds: []
371
+ } : comment
372
+ )
373
+ };
374
+ if (newThread.comments.some((comment) => comment.deletedAt === void 0)) {
375
+ newThreads.push(newThread);
376
+ }
377
+ } else {
378
+ newThreads.push(thread);
379
+ }
380
+ }
381
+ setThreads(newThreads);
382
+ startMutation();
383
+ room.deleteComment({ threadId, commentId }).catch(
384
+ (er) => errorEventSource.notify(
385
+ new DeleteCommentError(er, {
386
+ roomId: room.id,
387
+ threadId,
388
+ commentId
389
+ })
390
+ )
391
+ ).finally(endMutation);
392
+ }
393
+ function useThreads() {
394
+ return _indexjs.useSyncExternalStore.call(void 0,
395
+ store.subscribe,
396
+ store.get,
397
+ store.get
398
+ );
399
+ }
400
+ function useThreadsSuspense() {
401
+ const result = useThreads();
402
+ if (result.isLoading) {
403
+ throw new Promise(store.subscribeOnce);
404
+ }
405
+ if (result.error) {
406
+ throw result.error;
407
+ }
408
+ return result.threads;
409
+ }
410
+ return {
411
+ useThreads,
412
+ useThreadsSuspense,
413
+ createThread,
414
+ editThreadMetadata,
415
+ createComment,
416
+ editComment,
417
+ deleteComment,
418
+ subscribe
419
+ };
420
+ }
421
+
422
+ // src/comments/lib/use-async-cache.ts
423
+
424
+
425
+
426
+ // src/comments/lib/use-initial.ts
427
+
428
+ function useInitial(value) {
429
+ return _react.useRef.call(void 0, value instanceof Function ? value() : value).current;
430
+ }
431
+
432
+ // src/comments/lib/use-async-cache.ts
433
+ var INITIAL_ASYNC_STATE = {
434
+ isLoading: false,
435
+ data: void 0,
436
+ error: void 0
437
+ };
438
+ var noop = () => {
439
+ };
440
+ function useAsyncCache(cache, key, options) {
441
+ const frozenOptions = useInitial(options);
442
+ const cacheItem = _react.useMemo.call(void 0, () => {
443
+ if (key === null || !cache) {
444
+ return null;
445
+ }
446
+ const cacheItem2 = cache.create(key, _optionalChain([frozenOptions, 'optionalAccess', _3 => _3.overrideFunction]));
447
+ void cacheItem2.get();
448
+ return cacheItem2;
449
+ }, [cache, frozenOptions, key]);
450
+ const subscribe = _react.useCallback.call(void 0,
451
+ (callback) => _nullishCoalesce(_optionalChain([cacheItem, 'optionalAccess', _4 => _4.subscribe, 'call', _5 => _5(callback)]), () => ( noop)),
452
+ [cacheItem]
453
+ );
454
+ const getState = _react.useCallback.call(void 0,
455
+ () => _nullishCoalesce(_optionalChain([cacheItem, 'optionalAccess', _6 => _6.getState, 'call', _7 => _7()]), () => ( INITIAL_ASYNC_STATE)),
456
+ [cacheItem]
457
+ );
458
+ const revalidate = _react.useCallback.call(void 0, () => _optionalChain([cacheItem, 'optionalAccess', _8 => _8.revalidate, 'call', _9 => _9()]), [cacheItem]);
459
+ const state = _indexjs.useSyncExternalStore.call(void 0, subscribe, getState, getState);
460
+ const previousData = _react.useRef.call(void 0, );
461
+ let data = state.data;
462
+ _react.useEffect.call(void 0, () => {
463
+ previousData.current = { key, data: state.data };
464
+ }, [key, state]);
465
+ if (_optionalChain([frozenOptions, 'optionalAccess', _10 => _10.suspense]) && state.isLoading && cacheItem) {
466
+ throw new Promise((resolve) => {
467
+ cacheItem.subscribeOnce(() => resolve());
468
+ });
469
+ }
470
+ if (state.isLoading && _optionalChain([frozenOptions, 'optionalAccess', _11 => _11.keepPreviousDataWhileLoading]) && typeof state.data === "undefined" && _optionalChain([previousData, 'access', _12 => _12.current, 'optionalAccess', _13 => _13.key]) !== key && typeof _optionalChain([previousData, 'access', _14 => _14.current, 'optionalAccess', _15 => _15.data]) !== "undefined") {
471
+ data = previousData.current.data;
472
+ }
473
+ return {
474
+ isLoading: state.isLoading,
475
+ data,
476
+ error: state.error,
477
+ getState,
478
+ revalidate
479
+ };
480
+ }
481
+
482
+ // src/comments/lib/use-debounce.ts
483
+
484
+ var DEFAULT_DELAY = 500;
485
+ function useDebounce(value, delay = DEFAULT_DELAY) {
486
+ const timeout = _react.useRef.call(void 0, );
487
+ const [debouncedValue, setDebouncedValue] = _react.useState.call(void 0, value);
488
+ _react.useEffect.call(void 0, () => {
489
+ if (delay === false) {
490
+ return;
491
+ }
492
+ if (timeout.current === void 0) {
493
+ setDebouncedValue(value);
494
+ }
495
+ timeout.current = window.setTimeout(() => {
496
+ setDebouncedValue(value);
497
+ timeout.current = void 0;
498
+ }, delay);
499
+ return () => {
500
+ window.clearTimeout(timeout.current);
501
+ };
502
+ }, [value, delay]);
503
+ return debouncedValue;
504
+ }
505
+
29
506
  // src/hooks.ts
30
507
 
31
508
  function useRerender() {
@@ -38,12 +515,12 @@ function useRerender() {
38
515
  );
39
516
  return update;
40
517
  }
41
- function useInitial(value) {
518
+ function useInitial2(value) {
42
519
  return _react.useRef.call(void 0, value).current;
43
520
  }
44
521
 
45
522
  // src/factory.tsx
46
- var noop = () => {
523
+ var noop2 = () => {
47
524
  };
48
525
  var identity = (x) => x;
49
526
  var missing_unstable_batchedUpdates = (reactVersion, roomId) => `We noticed you\u2019re using React ${reactVersion}. Please pass unstable_batchedUpdates at the RoomProvider level until you\u2019re ready to upgrade to React 18:
@@ -58,7 +535,7 @@ var missing_unstable_batchedUpdates = (reactVersion, roomId) => `We noticed you\
58
535
 
59
536
  Why? Please see https://liveblocks.io/docs/guides/troubleshooting#stale-props-zombie-child for more information`;
60
537
  var superfluous_unstable_batchedUpdates = "You don\u2019t need to pass unstable_batchedUpdates to RoomProvider anymore, since you\u2019re on React 18+ already.";
61
- function useSyncExternalStore(s, gs, gss) {
538
+ function useSyncExternalStore3(s, gs, gss) {
62
539
  return _withselectorjs.useSyncExternalStoreWithSelector.call(void 0, s, gs, gss, identity);
63
540
  }
64
541
  var EMPTY_OTHERS = (
@@ -95,7 +572,27 @@ function makeMutationContext(room) {
95
572
  setMyPresence: room.updatePresence
96
573
  };
97
574
  }
98
- function createRoomContext(client) {
575
+ var hasWarnedIfNoResolveUser = false;
576
+ var hasWarnedIfNoResolveMentionSuggestions = false;
577
+ function warnIfNoResolveUser(usersCache) {
578
+ if (!hasWarnedIfNoResolveUser && !usersCache && process.env.NODE_ENV !== "production") {
579
+ console.warn("The resolveUser option wasn't set in createRoomContext.");
580
+ hasWarnedIfNoResolveUser = true;
581
+ }
582
+ }
583
+ function warnIfNoResolveMentionSuggestions(mentionSuggestionsCache) {
584
+ if (!hasWarnedIfNoResolveMentionSuggestions && !mentionSuggestionsCache && process.env.NODE_ENV !== "production") {
585
+ console.warn(
586
+ "The resolveMentionSuggestions option wasn't set in createRoomContext."
587
+ );
588
+ hasWarnedIfNoResolveMentionSuggestions = true;
589
+ }
590
+ }
591
+ var ContextBundle = React2.createContext(null);
592
+ function useRoomContextBundle() {
593
+ return React2.useContext(ContextBundle);
594
+ }
595
+ function createRoomContext(client, options) {
99
596
  const RoomContext = React2.createContext(null);
100
597
  function RoomProvider(props) {
101
598
  const {
@@ -125,7 +622,7 @@ function createRoomContext(client) {
125
622
  superfluous_unstable_batchedUpdates
126
623
  );
127
624
  }
128
- const frozen = useInitial({
625
+ const frozen = useInitial2({
129
626
  initialPresence,
130
627
  initialStorage,
131
628
  unstable_batchedUpdates,
@@ -140,19 +637,24 @@ function createRoomContext(client) {
140
637
  })
141
638
  );
142
639
  React2.useEffect(() => {
143
- setRoom(
144
- client.enter(roomId, {
640
+ const room2 = client.enter(
641
+ roomId,
642
+ {
145
643
  initialPresence: frozen.initialPresence,
146
644
  initialStorage: frozen.initialStorage,
147
645
  shouldInitiallyConnect: frozen.shouldInitiallyConnect,
148
646
  unstable_batchedUpdates: frozen.unstable_batchedUpdates
149
- })
647
+ }
150
648
  );
649
+ setRoom(room2);
650
+ const unsubscribe = getCommentsRoom(room2).subscribe();
151
651
  return () => {
652
+ unsubscribe();
653
+ commentsRooms.delete(room2.id);
152
654
  client.leave(roomId);
153
655
  };
154
656
  }, [roomId, frozen]);
155
- return /* @__PURE__ */ React2.createElement(RoomContext.Provider, { value: room }, props.children);
657
+ return /* @__PURE__ */ React2.createElement(RoomContext.Provider, { value: room }, /* @__PURE__ */ React2.createElement(ContextBundle.Provider, { value: bundle }, props.children));
156
658
  }
157
659
  function connectionIdSelector(others) {
158
660
  return others.map((user) => user.connectionId);
@@ -168,13 +670,13 @@ function createRoomContext(client) {
168
670
  const room = useRoom();
169
671
  const subscribe = room.events.status.subscribe;
170
672
  const getSnapshot = room.getStatus;
171
- return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
673
+ return useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
172
674
  }
173
675
  function useMyPresence() {
174
676
  const room = useRoom();
175
677
  const subscribe = room.events.myPresence.subscribe;
176
678
  const getSnapshot = room.getPresence;
177
- const presence = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
679
+ const presence = useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
178
680
  const setPresence = room.updatePresence;
179
681
  return [presence, setPresence];
180
682
  }
@@ -248,8 +750,8 @@ function createRoomContext(client) {
248
750
  function useBroadcastEvent() {
249
751
  const room = useRoom();
250
752
  return React2.useCallback(
251
- (event, options = { shouldQueueEventIfNotReady: false }) => {
252
- room.broadcastEvent(event, options);
753
+ (event, options2 = { shouldQueueEventIfNotReady: false }) => {
754
+ room.broadcastEvent(event, options2);
253
755
  },
254
756
  [room]
255
757
  );
@@ -314,7 +816,7 @@ function createRoomContext(client) {
314
816
  const subscribe = room.events.storageDidLoad.subscribeOnce;
315
817
  const getSnapshot = room.getStorageSnapshot;
316
818
  const getServerSnapshot = React2.useCallback(() => null, []);
317
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
819
+ return useSyncExternalStore3(subscribe, getSnapshot, getServerSnapshot);
318
820
  }
319
821
  function useStorageRoot() {
320
822
  return [useMutableStorageRoot()];
@@ -332,13 +834,13 @@ function createRoomContext(client) {
332
834
  const room = useRoom();
333
835
  const subscribe = room.events.history.subscribe;
334
836
  const canUndo = room.history.canUndo;
335
- return useSyncExternalStore(subscribe, canUndo, canUndo);
837
+ return useSyncExternalStore3(subscribe, canUndo, canUndo);
336
838
  }
337
839
  function useCanRedo() {
338
840
  const room = useRoom();
339
841
  const subscribe = room.events.history.subscribe;
340
842
  const canRedo = room.history.canRedo;
341
- return useSyncExternalStore(subscribe, canRedo, canRedo);
843
+ return useSyncExternalStore3(subscribe, canRedo, canRedo);
342
844
  }
343
845
  function useBatch() {
344
846
  return useRoom().batch;
@@ -395,7 +897,7 @@ function createRoomContext(client) {
395
897
  [selector]
396
898
  );
397
899
  const subscribe = React2.useCallback(
398
- (onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop,
900
+ (onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop2,
399
901
  [room, rootOrNull]
400
902
  );
401
903
  const getSnapshot = React2.useCallback(() => {
@@ -501,7 +1003,106 @@ function createRoomContext(client) {
501
1003
  useSuspendUntilStorageLoaded();
502
1004
  return useLegacyKey(key);
503
1005
  }
504
- return {
1006
+ const errorEventSource = _core.makeEventSource.call(void 0, );
1007
+ const commentsRooms = /* @__PURE__ */ new Map();
1008
+ function getCommentsRoom(room) {
1009
+ let commentsRoom = commentsRooms.get(room.id);
1010
+ if (commentsRoom === void 0) {
1011
+ commentsRoom = createCommentsRoom(room, errorEventSource);
1012
+ commentsRooms.set(room.id, commentsRoom);
1013
+ }
1014
+ return commentsRoom;
1015
+ }
1016
+ function useThreads() {
1017
+ const room = useRoom();
1018
+ return getCommentsRoom(room).useThreads();
1019
+ }
1020
+ function useThreadsSuspense() {
1021
+ const room = useRoom();
1022
+ return getCommentsRoom(room).useThreadsSuspense();
1023
+ }
1024
+ function useCreateThread() {
1025
+ const room = useRoom();
1026
+ return React2.useCallback(
1027
+ (options2) => getCommentsRoom(room).createThread(options2),
1028
+ [room]
1029
+ );
1030
+ }
1031
+ function useEditThreadMetadata() {
1032
+ const room = useRoom();
1033
+ return React2.useCallback(
1034
+ (options2) => getCommentsRoom(room).editThreadMetadata(options2),
1035
+ [room]
1036
+ );
1037
+ }
1038
+ function useCreateComment() {
1039
+ const room = useRoom();
1040
+ return React2.useCallback(
1041
+ (options2) => getCommentsRoom(room).createComment(options2),
1042
+ [room]
1043
+ );
1044
+ }
1045
+ function useEditComment() {
1046
+ const room = useRoom();
1047
+ return React2.useCallback(
1048
+ (options2) => getCommentsRoom(room).editComment(options2),
1049
+ [room]
1050
+ );
1051
+ }
1052
+ function useDeleteComment() {
1053
+ const room = useRoom();
1054
+ return React2.useCallback(
1055
+ (options2) => getCommentsRoom(room).deleteComment(options2),
1056
+ [room]
1057
+ );
1058
+ }
1059
+ const { resolveUser, resolveMentionSuggestions } = _nullishCoalesce(options, () => ( {}));
1060
+ const usersCache = resolveUser ? _core.createAsyncCache.call(void 0, resolveUser) : void 0;
1061
+ function useUser(userId) {
1062
+ const state = useAsyncCache(usersCache, userId);
1063
+ React2.useEffect(() => warnIfNoResolveUser(usersCache), []);
1064
+ if (state.isLoading) {
1065
+ return {
1066
+ isLoading: true
1067
+ };
1068
+ } else {
1069
+ return {
1070
+ user: state.data,
1071
+ error: state.error,
1072
+ isLoading: false
1073
+ };
1074
+ }
1075
+ }
1076
+ function useUserSuspense(userId) {
1077
+ const state = useAsyncCache(usersCache, userId, {
1078
+ suspense: true
1079
+ });
1080
+ React2.useEffect(() => warnIfNoResolveUser(usersCache), []);
1081
+ return {
1082
+ user: state.data,
1083
+ error: state.error,
1084
+ isLoading: false
1085
+ };
1086
+ }
1087
+ const mentionSuggestionsCache = _core.createAsyncCache.call(void 0,
1088
+ _nullishCoalesce(resolveMentionSuggestions, () => ( (() => Promise.resolve([]))))
1089
+ );
1090
+ function useMentionSuggestions(search) {
1091
+ const debouncedSearch = useDebounce(search, 500);
1092
+ const { data } = useAsyncCache(
1093
+ mentionSuggestionsCache,
1094
+ _nullishCoalesce(debouncedSearch, () => ( null)),
1095
+ {
1096
+ keepPreviousDataWhileLoading: true
1097
+ }
1098
+ );
1099
+ React2.useEffect(
1100
+ () => warnIfNoResolveMentionSuggestions(mentionSuggestionsCache),
1101
+ []
1102
+ );
1103
+ return data;
1104
+ }
1105
+ const bundle = {
505
1106
  RoomContext,
506
1107
  RoomProvider,
507
1108
  useRoom,
@@ -530,6 +1131,14 @@ function createRoomContext(client) {
530
1131
  useOthersConnectionIds,
531
1132
  useOther,
532
1133
  useMutation,
1134
+ useThreads,
1135
+ useUser,
1136
+ useCreateThread,
1137
+ useEditThreadMetadata,
1138
+ useCreateComment,
1139
+ useEditComment,
1140
+ useDeleteComment,
1141
+ useMentionSuggestions,
533
1142
  suspense: {
534
1143
  RoomContext,
535
1144
  RoomProvider,
@@ -558,9 +1167,17 @@ function createRoomContext(client) {
558
1167
  useOthersMapped: useOthersMappedSuspense,
559
1168
  useOthersConnectionIds: useOthersConnectionIdsSuspense,
560
1169
  useOther: useOtherSuspense,
561
- useMutation
1170
+ useMutation,
1171
+ useThreads: useThreadsSuspense,
1172
+ useUser: useUserSuspense,
1173
+ useCreateThread,
1174
+ useEditThreadMetadata,
1175
+ useCreateComment,
1176
+ useEditComment,
1177
+ useDeleteComment
562
1178
  }
563
1179
  };
1180
+ return bundle;
564
1181
  }
565
1182
 
566
1183
  // src/index.ts
@@ -570,5 +1187,6 @@ _core.detectDupes.call(void 0, PKG_NAME, PKG_VERSION, PKG_FORMAT);
570
1187
 
571
1188
 
572
1189
 
573
- exports.ClientSideSuspense = ClientSideSuspense; exports.createRoomContext = createRoomContext; exports.shallow = _client.shallow;
1190
+
1191
+ exports.ClientSideSuspense = ClientSideSuspense; exports.createRoomContext = createRoomContext; exports.shallow = _client.shallow; exports.useRoomContextBundle = useRoomContextBundle;
574
1192
  //# sourceMappingURL=index.js.map