@liveblocks/react 1.2.0 → 1.2.2-comments1

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