@liveblocks/react 1.11.2 → 1.12.0-lexical2
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.d.mts +229 -106
- package/dist/index.d.ts +229 -106
- package/dist/index.js +1979 -1844
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1986 -1851
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { detectDupes } from "@liveblocks/core";
|
|
|
5
5
|
|
|
6
6
|
// src/version.ts
|
|
7
7
|
var PKG_NAME = "@liveblocks/react";
|
|
8
|
-
var PKG_VERSION = "1.
|
|
8
|
+
var PKG_VERSION = "1.12.0-lexical2";
|
|
9
9
|
var PKG_FORMAT = "esm";
|
|
10
10
|
|
|
11
11
|
// src/ClientSideSuspense.tsx
|
|
@@ -18,68 +18,6 @@ function ClientSideSuspense(props) {
|
|
|
18
18
|
return /* @__PURE__ */ React.createElement(React.Suspense, { fallback: props.fallback }, mounted ? props.children() : props.fallback);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
// src/liveblocks.tsx
|
|
22
|
-
import { kInternal as kInternal3, makePoller as makePoller2 } from "@liveblocks/core";
|
|
23
|
-
import { nanoid as nanoid3 } from "nanoid";
|
|
24
|
-
import React3, {
|
|
25
|
-
createContext as createContext2,
|
|
26
|
-
useCallback as useCallback3,
|
|
27
|
-
useContext as useContext3,
|
|
28
|
-
useEffect as useEffect5
|
|
29
|
-
} from "react";
|
|
30
|
-
import { useSyncExternalStore as useSyncExternalStore3 } from "use-sync-external-store/shim/index.js";
|
|
31
|
-
import { useSyncExternalStoreWithSelector as useSyncExternalStoreWithSelector2 } from "use-sync-external-store/shim/with-selector.js";
|
|
32
|
-
|
|
33
|
-
// src/comments/lib/selected-inbox-notifications.ts
|
|
34
|
-
import { applyOptimisticUpdates } from "@liveblocks/core";
|
|
35
|
-
function selectedInboxNotifications(state) {
|
|
36
|
-
const result = applyOptimisticUpdates(state);
|
|
37
|
-
return Object.values(result.inboxNotifications).sort(
|
|
38
|
-
// Sort so that the most recent notifications are first
|
|
39
|
-
(a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime()
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// src/lib/retry-error.ts
|
|
44
|
-
var MAX_ERROR_RETRY_COUNT = 5;
|
|
45
|
-
var ERROR_RETRY_INTERVAL = 5e3;
|
|
46
|
-
function retryError(action, retryCount) {
|
|
47
|
-
if (retryCount >= MAX_ERROR_RETRY_COUNT)
|
|
48
|
-
return;
|
|
49
|
-
const timeout = Math.pow(2, retryCount) * ERROR_RETRY_INTERVAL;
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
void action();
|
|
52
|
-
}, timeout);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/shared.ts
|
|
56
|
-
import { kInternal as kInternal2 } from "@liveblocks/core";
|
|
57
|
-
import { useCallback as useCallback2, useContext as useContext2, useEffect as useEffect4 } from "react";
|
|
58
|
-
import { useSyncExternalStore as useSyncExternalStore2 } from "use-sync-external-store/shim/index.js";
|
|
59
|
-
|
|
60
|
-
// src/room.tsx
|
|
61
|
-
import { shallow } from "@liveblocks/client";
|
|
62
|
-
import {
|
|
63
|
-
addReaction,
|
|
64
|
-
CommentsApiError,
|
|
65
|
-
console as console2,
|
|
66
|
-
deleteComment,
|
|
67
|
-
deprecateIf,
|
|
68
|
-
errorIf,
|
|
69
|
-
isLiveNode,
|
|
70
|
-
kInternal,
|
|
71
|
-
makeEventSource,
|
|
72
|
-
makePoller,
|
|
73
|
-
NotificationsApiError,
|
|
74
|
-
removeReaction,
|
|
75
|
-
ServerMsgCode,
|
|
76
|
-
stringify,
|
|
77
|
-
upsertComment
|
|
78
|
-
} from "@liveblocks/core";
|
|
79
|
-
import { nanoid as nanoid2 } from "nanoid";
|
|
80
|
-
import * as React2 from "react";
|
|
81
|
-
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
|
|
82
|
-
|
|
83
21
|
// src/comments/errors.ts
|
|
84
22
|
var CreateThreadError = class extends Error {
|
|
85
23
|
constructor(cause, context) {
|
|
@@ -154,53 +92,28 @@ var UpdateNotificationSettingsError = class extends Error {
|
|
|
154
92
|
}
|
|
155
93
|
};
|
|
156
94
|
|
|
157
|
-
// src/
|
|
158
|
-
import {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return createOptimisticId(COMMENT_ID_PREFIX);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// src/comments/lib/select-notification-settings.ts
|
|
172
|
-
import {
|
|
173
|
-
applyOptimisticUpdates as applyOptimisticUpdates2,
|
|
174
|
-
nn
|
|
175
|
-
} from "@liveblocks/core";
|
|
176
|
-
function selectNotificationSettings(roomId, state) {
|
|
177
|
-
const { notificationSettings } = applyOptimisticUpdates2(state);
|
|
178
|
-
return nn(notificationSettings[roomId]);
|
|
179
|
-
}
|
|
95
|
+
// src/liveblocks.tsx
|
|
96
|
+
import { kInternal as kInternal3, makePoller as makePoller2, raise as raise2 } from "@liveblocks/core";
|
|
97
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
98
|
+
import React4, {
|
|
99
|
+
createContext as createContext2,
|
|
100
|
+
useCallback as useCallback3,
|
|
101
|
+
useContext as useContext2,
|
|
102
|
+
useEffect as useEffect6
|
|
103
|
+
} from "react";
|
|
104
|
+
import { useSyncExternalStore as useSyncExternalStore3 } from "use-sync-external-store/shim/index.js";
|
|
105
|
+
import { useSyncExternalStoreWithSelector as useSyncExternalStoreWithSelector2 } from "use-sync-external-store/shim/with-selector.js";
|
|
180
106
|
|
|
181
|
-
// src/
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
const query = options.query;
|
|
194
|
-
if (!query)
|
|
195
|
-
return true;
|
|
196
|
-
for (const key in query.metadata) {
|
|
197
|
-
if (thread.metadata[key] !== query.metadata[key]) {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return true;
|
|
202
|
-
});
|
|
203
|
-
return threads.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
107
|
+
// src/lib/retry-error.ts
|
|
108
|
+
var MAX_ERROR_RETRY_COUNT = 5;
|
|
109
|
+
var ERROR_RETRY_INTERVAL = 5e3;
|
|
110
|
+
function retryError(action, retryCount) {
|
|
111
|
+
if (retryCount >= MAX_ERROR_RETRY_COUNT)
|
|
112
|
+
return;
|
|
113
|
+
const timeout = Math.pow(2, retryCount) * ERROR_RETRY_INTERVAL;
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
void action();
|
|
116
|
+
}, timeout);
|
|
204
117
|
}
|
|
205
118
|
|
|
206
119
|
// src/lib/use-initial.ts
|
|
@@ -209,6 +122,34 @@ function useInitial(value) {
|
|
|
209
122
|
return useState2(value)[0];
|
|
210
123
|
}
|
|
211
124
|
|
|
125
|
+
// src/shared.ts
|
|
126
|
+
import { kInternal as kInternal2, raise } from "@liveblocks/core";
|
|
127
|
+
import { useCallback as useCallback2, useEffect as useEffect5 } from "react";
|
|
128
|
+
import { useSyncExternalStore as useSyncExternalStore2 } from "use-sync-external-store/shim/index.js";
|
|
129
|
+
|
|
130
|
+
// src/room.tsx
|
|
131
|
+
import { shallow } from "@liveblocks/client";
|
|
132
|
+
import {
|
|
133
|
+
addReaction,
|
|
134
|
+
CommentsApiError,
|
|
135
|
+
console as console2,
|
|
136
|
+
deleteComment,
|
|
137
|
+
deprecateIf,
|
|
138
|
+
errorIf,
|
|
139
|
+
isLiveNode,
|
|
140
|
+
kInternal,
|
|
141
|
+
makeEventSource,
|
|
142
|
+
makePoller,
|
|
143
|
+
NotificationsApiError,
|
|
144
|
+
removeReaction,
|
|
145
|
+
ServerMsgCode,
|
|
146
|
+
stringify,
|
|
147
|
+
upsertComment
|
|
148
|
+
} from "@liveblocks/core";
|
|
149
|
+
import { nanoid } from "nanoid";
|
|
150
|
+
import * as React3 from "react";
|
|
151
|
+
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
|
|
152
|
+
|
|
212
153
|
// src/lib/use-latest.ts
|
|
213
154
|
import { useEffect as useEffect2, useRef } from "react";
|
|
214
155
|
function useLatest(value) {
|
|
@@ -232,7 +173,46 @@ function useRerender() {
|
|
|
232
173
|
return update;
|
|
233
174
|
}
|
|
234
175
|
|
|
176
|
+
// src/use-scroll-to-comment-on-load-effect.ts
|
|
177
|
+
import * as React2 from "react";
|
|
178
|
+
function handleScrollToCommentOnLoad(shouldScrollOnLoad, state) {
|
|
179
|
+
if (shouldScrollOnLoad === false)
|
|
180
|
+
return;
|
|
181
|
+
if (state.isLoading)
|
|
182
|
+
return;
|
|
183
|
+
const isWindowDefined = typeof window !== "undefined";
|
|
184
|
+
if (!isWindowDefined)
|
|
185
|
+
return;
|
|
186
|
+
const hash = window.location.hash;
|
|
187
|
+
const commentId = hash.slice(1);
|
|
188
|
+
if (!commentId.startsWith("cm_"))
|
|
189
|
+
return;
|
|
190
|
+
const comment = document.getElementById(commentId);
|
|
191
|
+
if (comment === null)
|
|
192
|
+
return;
|
|
193
|
+
const comments = state.threads.flatMap((thread) => thread.comments);
|
|
194
|
+
const isCommentInThreads = comments.some(
|
|
195
|
+
(comment2) => comment2.id === commentId
|
|
196
|
+
);
|
|
197
|
+
if (!isCommentInThreads)
|
|
198
|
+
return;
|
|
199
|
+
comment.scrollIntoView();
|
|
200
|
+
}
|
|
201
|
+
function useScrollToCommentOnLoadEffect(shouldScrollOnLoad, state) {
|
|
202
|
+
React2.useEffect(
|
|
203
|
+
() => {
|
|
204
|
+
handleScrollToCommentOnLoad(shouldScrollOnLoad, state);
|
|
205
|
+
},
|
|
206
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this effect once
|
|
207
|
+
[state.isLoading]
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
235
211
|
// src/room.tsx
|
|
212
|
+
var ThreadCreateCallbackContext = React3.createContext(null);
|
|
213
|
+
var ThreadDeleteCallbackContext = React3.createContext(null);
|
|
214
|
+
var ComposerFocusCallbackContext = React3.createContext(null);
|
|
215
|
+
var IsThreadActiveCallbackContext = React3.createContext(null);
|
|
236
216
|
var noop = () => {
|
|
237
217
|
};
|
|
238
218
|
var identity = (x) => x;
|
|
@@ -254,236 +234,662 @@ function useSyncExternalStore(s, gs, gss) {
|
|
|
254
234
|
var STABLE_EMPTY_LIST = Object.freeze([]);
|
|
255
235
|
var POLLING_INTERVAL = 5 * 60 * 1e3;
|
|
256
236
|
var MENTION_SUGGESTIONS_DEBOUNCE = 500;
|
|
237
|
+
function makeNotificationSettingsQueryKey(roomId) {
|
|
238
|
+
return `${roomId}:NOTIFICATION_SETTINGS`;
|
|
239
|
+
}
|
|
257
240
|
function alwaysEmptyList() {
|
|
258
241
|
return STABLE_EMPTY_LIST;
|
|
259
242
|
}
|
|
260
243
|
function alwaysNull() {
|
|
261
244
|
return null;
|
|
262
245
|
}
|
|
246
|
+
function selectorFor_useOthersConnectionIds(others) {
|
|
247
|
+
return others.map((user) => user.connectionId);
|
|
248
|
+
}
|
|
263
249
|
function makeMutationContext(room) {
|
|
264
|
-
const
|
|
250
|
+
const cannotUseUntil = "This mutation cannot be used until";
|
|
251
|
+
const needsPresence = `${cannotUseUntil} connected to the Liveblocks room`;
|
|
252
|
+
const needsStorage = `${cannotUseUntil} storage has been loaded`;
|
|
265
253
|
return {
|
|
266
254
|
get storage() {
|
|
267
255
|
const mutableRoot = room.getStorageSnapshot();
|
|
268
256
|
if (mutableRoot === null) {
|
|
269
|
-
throw new Error(
|
|
257
|
+
throw new Error(needsStorage);
|
|
270
258
|
}
|
|
271
259
|
return mutableRoot;
|
|
272
260
|
},
|
|
273
261
|
get self() {
|
|
274
262
|
const self = room.getSelf();
|
|
275
263
|
if (self === null) {
|
|
276
|
-
throw new Error(
|
|
264
|
+
throw new Error(needsPresence);
|
|
277
265
|
}
|
|
278
266
|
return self;
|
|
279
267
|
},
|
|
280
268
|
get others() {
|
|
281
269
|
const others = room.getOthers();
|
|
282
270
|
if (room.getSelf() === null) {
|
|
283
|
-
throw new Error(
|
|
271
|
+
throw new Error(needsPresence);
|
|
284
272
|
}
|
|
285
273
|
return others;
|
|
286
274
|
},
|
|
287
275
|
setMyPresence: room.updatePresence
|
|
288
276
|
};
|
|
289
277
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
278
|
+
function getCurrentUserId(room) {
|
|
279
|
+
const self = room.getSelf();
|
|
280
|
+
if (self === null || self.id === void 0) {
|
|
281
|
+
return "anonymous";
|
|
282
|
+
} else {
|
|
283
|
+
return self.id;
|
|
295
284
|
}
|
|
296
|
-
return bundle;
|
|
297
285
|
}
|
|
298
|
-
function
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
);
|
|
286
|
+
function handleApiError(err) {
|
|
287
|
+
const message = `Request failed with status ${err.status}: ${err.message}`;
|
|
288
|
+
if (err.details?.error === "FORBIDDEN") {
|
|
289
|
+
const detailedMessage = [message, err.details.suggestion, err.details.docs].filter(Boolean).join("\n");
|
|
290
|
+
console2.error(detailedMessage);
|
|
303
291
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
292
|
+
return new Error(message);
|
|
293
|
+
}
|
|
294
|
+
var _extras = /* @__PURE__ */ new WeakMap();
|
|
295
|
+
var _bundles = /* @__PURE__ */ new WeakMap();
|
|
296
|
+
function getOrCreateRoomContextBundle(client) {
|
|
297
|
+
let bundle = _bundles.get(client);
|
|
298
|
+
if (!bundle) {
|
|
299
|
+
bundle = makeRoomContextBundle(client);
|
|
300
|
+
_bundles.set(client, bundle);
|
|
308
301
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
302
|
+
return bundle;
|
|
303
|
+
}
|
|
304
|
+
function getExtrasForClient(client) {
|
|
305
|
+
let extras = _extras.get(client);
|
|
306
|
+
if (!extras) {
|
|
307
|
+
extras = makeExtrasForClient(client);
|
|
308
|
+
_extras.set(client, extras);
|
|
309
|
+
}
|
|
310
|
+
return extras;
|
|
311
|
+
}
|
|
312
|
+
function makeExtrasForClient(client) {
|
|
313
|
+
const store = client[kInternal].cacheStore;
|
|
314
|
+
const DEFAULT_DEDUPING_INTERVAL = 2e3;
|
|
315
|
+
const lastRequestedAtByRoom = /* @__PURE__ */ new Map();
|
|
316
|
+
const requestsByQuery = /* @__PURE__ */ new Map();
|
|
317
|
+
const requestStatusByRoom = /* @__PURE__ */ new Map();
|
|
318
|
+
const subscribersByQuery = /* @__PURE__ */ new Map();
|
|
319
|
+
const mentionSuggestionsCache = /* @__PURE__ */ new Map();
|
|
320
|
+
const poller = makePoller(refreshThreadsAndNotifications);
|
|
321
|
+
async function refreshThreadsAndNotifications() {
|
|
322
|
+
const requests = [];
|
|
323
|
+
client[kInternal].getRoomIds().map((roomId) => {
|
|
324
|
+
const room = client.getRoom(roomId);
|
|
325
|
+
if (room === null)
|
|
326
|
+
return;
|
|
327
|
+
requests.push(getThreadsUpdates(room.id));
|
|
328
|
+
});
|
|
329
|
+
await Promise.allSettled(requests);
|
|
336
330
|
}
|
|
337
|
-
function
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
331
|
+
function incrementQuerySubscribers(queryKey) {
|
|
332
|
+
const subscribers = subscribersByQuery.get(queryKey) ?? 0;
|
|
333
|
+
subscribersByQuery.set(queryKey, subscribers + 1);
|
|
334
|
+
poller.start(POLLING_INTERVAL);
|
|
335
|
+
return () => {
|
|
336
|
+
const subscribers2 = subscribersByQuery.get(queryKey);
|
|
337
|
+
if (subscribers2 === void 0 || subscribers2 <= 0) {
|
|
338
|
+
console2.warn(
|
|
339
|
+
`Internal unexpected behavior. Cannot decrease subscriber count for query "${queryKey}"`
|
|
343
340
|
);
|
|
341
|
+
return;
|
|
344
342
|
}
|
|
345
|
-
|
|
346
|
-
|
|
343
|
+
subscribersByQuery.set(queryKey, subscribers2 - 1);
|
|
344
|
+
let totalSubscribers = 0;
|
|
345
|
+
for (const subscribers3 of subscribersByQuery.values()) {
|
|
346
|
+
totalSubscribers += subscribers3;
|
|
347
347
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
348
|
+
if (totalSubscribers <= 0) {
|
|
349
|
+
poller.stop();
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
async function getThreadsUpdates(roomId) {
|
|
354
|
+
const room = client.getRoom(roomId);
|
|
355
|
+
if (room === null)
|
|
356
|
+
return;
|
|
357
|
+
const since = lastRequestedAtByRoom.get(room.id);
|
|
358
|
+
if (since === void 0)
|
|
359
|
+
return;
|
|
360
|
+
const isFetchingThreadsUpdates = requestStatusByRoom.get(room.id) ?? false;
|
|
361
|
+
if (isFetchingThreadsUpdates === true)
|
|
362
|
+
return;
|
|
363
|
+
try {
|
|
364
|
+
requestStatusByRoom.set(room.id, true);
|
|
365
|
+
const updates = await room[kInternal].comments.getThreads({ since });
|
|
366
|
+
setTimeout(() => {
|
|
367
|
+
requestStatusByRoom.set(room.id, false);
|
|
368
|
+
}, DEFAULT_DEDUPING_INTERVAL);
|
|
369
|
+
store.updateThreadsAndNotifications(
|
|
370
|
+
updates.threads,
|
|
371
|
+
updates.inboxNotifications,
|
|
372
|
+
updates.deletedThreads,
|
|
373
|
+
updates.deletedInboxNotifications
|
|
357
374
|
);
|
|
375
|
+
lastRequestedAtByRoom.set(room.id, updates.meta.requestedAt);
|
|
376
|
+
} catch (err) {
|
|
377
|
+
requestStatusByRoom.set(room.id, false);
|
|
378
|
+
return;
|
|
358
379
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
380
|
+
}
|
|
381
|
+
async function getThreadsAndInboxNotifications(room, queryKey, options, { retryCount } = { retryCount: 0 }) {
|
|
382
|
+
const existingRequest = requestsByQuery.get(queryKey);
|
|
383
|
+
if (existingRequest !== void 0)
|
|
384
|
+
return existingRequest;
|
|
385
|
+
const commentsAPI = room[kInternal].comments;
|
|
386
|
+
const request = commentsAPI.getThreads(options);
|
|
387
|
+
requestsByQuery.set(queryKey, request);
|
|
388
|
+
store.setQueryState(queryKey, {
|
|
389
|
+
isLoading: true
|
|
364
390
|
});
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
async function handleCommentEvent(message) {
|
|
374
|
-
const info = await room[kInternal].comments.getThread({
|
|
375
|
-
threadId: message.threadId
|
|
376
|
-
});
|
|
377
|
-
if (!info) {
|
|
378
|
-
store.deleteThread(message.threadId);
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
const { thread, inboxNotification } = info;
|
|
382
|
-
const existingThread = store.get().threads[message.threadId];
|
|
383
|
-
switch (message.type) {
|
|
384
|
-
case ServerMsgCode.COMMENT_EDITED:
|
|
385
|
-
case ServerMsgCode.THREAD_METADATA_UPDATED:
|
|
386
|
-
case ServerMsgCode.COMMENT_REACTION_ADDED:
|
|
387
|
-
case ServerMsgCode.COMMENT_REACTION_REMOVED:
|
|
388
|
-
case ServerMsgCode.COMMENT_DELETED:
|
|
389
|
-
if (!existingThread)
|
|
390
|
-
break;
|
|
391
|
-
store.updateThreadAndNotification(thread, inboxNotification);
|
|
392
|
-
break;
|
|
393
|
-
case ServerMsgCode.COMMENT_CREATED:
|
|
394
|
-
store.updateThreadAndNotification(thread, inboxNotification);
|
|
395
|
-
break;
|
|
396
|
-
default:
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return room.events.comments.subscribe(
|
|
401
|
-
(message) => void handleCommentEvent(message)
|
|
391
|
+
try {
|
|
392
|
+
const result = await request;
|
|
393
|
+
store.updateThreadsAndNotifications(
|
|
394
|
+
result.threads,
|
|
395
|
+
result.inboxNotifications,
|
|
396
|
+
result.deletedThreads,
|
|
397
|
+
result.deletedInboxNotifications,
|
|
398
|
+
queryKey
|
|
402
399
|
);
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}, [room.id]);
|
|
407
|
-
React2.useEffect(() => {
|
|
408
|
-
function handleIsOnline() {
|
|
409
|
-
void getThreadsUpdates(room.id);
|
|
410
|
-
}
|
|
411
|
-
window.addEventListener("online", handleIsOnline);
|
|
412
|
-
return () => {
|
|
413
|
-
window.removeEventListener("online", handleIsOnline);
|
|
414
|
-
};
|
|
415
|
-
}, [room.id]);
|
|
416
|
-
React2.useEffect(() => {
|
|
417
|
-
const pair = stableEnterRoom(roomId, frozenProps);
|
|
418
|
-
setRoomLeavePair(pair);
|
|
419
|
-
const { room: room2, leave } = pair;
|
|
420
|
-
if (frozenProps.autoConnect) {
|
|
421
|
-
room2.connect();
|
|
400
|
+
const lastRequestedAt = lastRequestedAtByRoom.get(room.id);
|
|
401
|
+
if (lastRequestedAt === void 0 || lastRequestedAt > result.meta.requestedAt) {
|
|
402
|
+
lastRequestedAtByRoom.set(room.id, result.meta.requestedAt);
|
|
422
403
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
function connectionIdSelector(others) {
|
|
436
|
-
return others.map((user) => user.connectionId);
|
|
437
|
-
}
|
|
438
|
-
function useRoom() {
|
|
439
|
-
const room = React2.useContext(RoomContext);
|
|
440
|
-
if (room === null) {
|
|
441
|
-
throw new Error("RoomProvider is missing from the React tree.");
|
|
404
|
+
poller.start(POLLING_INTERVAL);
|
|
405
|
+
} catch (err) {
|
|
406
|
+
requestsByQuery.delete(queryKey);
|
|
407
|
+
retryError(() => {
|
|
408
|
+
void getThreadsAndInboxNotifications(room, queryKey, options, {
|
|
409
|
+
retryCount: retryCount + 1
|
|
410
|
+
});
|
|
411
|
+
}, retryCount);
|
|
412
|
+
store.setQueryState(queryKey, {
|
|
413
|
+
isLoading: false,
|
|
414
|
+
error: err
|
|
415
|
+
});
|
|
442
416
|
}
|
|
443
|
-
return
|
|
444
|
-
}
|
|
445
|
-
function useStatus() {
|
|
446
|
-
const room = useRoom();
|
|
447
|
-
const subscribe = room.events.status.subscribe;
|
|
448
|
-
const getSnapshot = room.getStatus;
|
|
449
|
-
const getServerSnapshot = room.getStatus;
|
|
450
|
-
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
417
|
+
return;
|
|
451
418
|
}
|
|
452
|
-
function
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
419
|
+
async function getInboxNotificationSettings(room, queryKey, { retryCount } = { retryCount: 0 }) {
|
|
420
|
+
const existingRequest = requestsByQuery.get(queryKey);
|
|
421
|
+
if (existingRequest !== void 0)
|
|
422
|
+
return existingRequest;
|
|
423
|
+
try {
|
|
424
|
+
const request = room[kInternal].notifications.getRoomNotificationSettings();
|
|
425
|
+
requestsByQuery.set(queryKey, request);
|
|
426
|
+
store.setQueryState(queryKey, {
|
|
427
|
+
isLoading: true
|
|
428
|
+
});
|
|
429
|
+
const settings = await request;
|
|
430
|
+
store.updateRoomInboxNotificationSettings(room.id, settings, queryKey);
|
|
431
|
+
} catch (err) {
|
|
432
|
+
requestsByQuery.delete(queryKey);
|
|
433
|
+
retryError(() => {
|
|
434
|
+
void getInboxNotificationSettings(room, queryKey, {
|
|
435
|
+
retryCount: retryCount + 1
|
|
436
|
+
});
|
|
437
|
+
}, retryCount);
|
|
438
|
+
store.setQueryState(queryKey, {
|
|
439
|
+
isLoading: false,
|
|
440
|
+
error: err
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return;
|
|
459
444
|
}
|
|
460
|
-
|
|
461
|
-
|
|
445
|
+
const commentsErrorEventSource = makeEventSource();
|
|
446
|
+
function onMutationFailure(innerError, optimisticUpdateId, createPublicError) {
|
|
447
|
+
store.set((state) => ({
|
|
448
|
+
...state,
|
|
449
|
+
optimisticUpdates: state.optimisticUpdates.filter(
|
|
450
|
+
(update) => update.id !== optimisticUpdateId
|
|
451
|
+
)
|
|
452
|
+
}));
|
|
453
|
+
if (innerError instanceof CommentsApiError) {
|
|
454
|
+
const error = handleApiError(innerError);
|
|
455
|
+
commentsErrorEventSource.notify(createPublicError(error));
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (innerError instanceof NotificationsApiError) {
|
|
459
|
+
handleApiError(innerError);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
throw innerError;
|
|
462
463
|
}
|
|
463
|
-
function
|
|
464
|
+
function useMentionSuggestions(search) {
|
|
464
465
|
const room = useRoom();
|
|
465
|
-
const
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
466
|
+
const [mentionSuggestions, setMentionSuggestions] = React3.useState();
|
|
467
|
+
const lastInvokedAt = React3.useRef();
|
|
468
|
+
React3.useEffect(() => {
|
|
469
|
+
const resolveMentionSuggestions = client[kInternal].resolveMentionSuggestions;
|
|
470
|
+
if (search === void 0 || !resolveMentionSuggestions) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const resolveMentionSuggestionsArgs = { text: search, roomId: room.id };
|
|
474
|
+
const mentionSuggestionsCacheKey = stringify(
|
|
475
|
+
resolveMentionSuggestionsArgs
|
|
476
|
+
);
|
|
477
|
+
let debounceTimeout;
|
|
478
|
+
let isCanceled = false;
|
|
479
|
+
const getMentionSuggestions = async () => {
|
|
480
|
+
try {
|
|
481
|
+
lastInvokedAt.current = performance.now();
|
|
482
|
+
const mentionSuggestions2 = await resolveMentionSuggestions(
|
|
483
|
+
resolveMentionSuggestionsArgs
|
|
484
|
+
);
|
|
485
|
+
if (!isCanceled) {
|
|
486
|
+
setMentionSuggestions(mentionSuggestions2);
|
|
487
|
+
mentionSuggestionsCache.set(
|
|
488
|
+
mentionSuggestionsCacheKey,
|
|
489
|
+
mentionSuggestions2
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console2.error(error?.message);
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
if (mentionSuggestionsCache.has(mentionSuggestionsCacheKey)) {
|
|
497
|
+
setMentionSuggestions(
|
|
498
|
+
mentionSuggestionsCache.get(mentionSuggestionsCacheKey)
|
|
499
|
+
);
|
|
500
|
+
} else if (!lastInvokedAt.current || Math.abs(performance.now() - lastInvokedAt.current) > MENTION_SUGGESTIONS_DEBOUNCE) {
|
|
501
|
+
void getMentionSuggestions();
|
|
502
|
+
} else {
|
|
503
|
+
debounceTimeout = window.setTimeout(() => {
|
|
504
|
+
void getMentionSuggestions();
|
|
505
|
+
}, MENTION_SUGGESTIONS_DEBOUNCE);
|
|
506
|
+
}
|
|
507
|
+
return () => {
|
|
508
|
+
isCanceled = true;
|
|
509
|
+
window.clearTimeout(debounceTimeout);
|
|
510
|
+
};
|
|
511
|
+
}, [room.id, search]);
|
|
512
|
+
return mentionSuggestions;
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
store,
|
|
516
|
+
incrementQuerySubscribers,
|
|
517
|
+
commentsErrorEventSource,
|
|
518
|
+
getThreadsUpdates,
|
|
519
|
+
getThreadsAndInboxNotifications,
|
|
520
|
+
getInboxNotificationSettings,
|
|
521
|
+
useMentionSuggestions,
|
|
522
|
+
onMutationFailure
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
var RoomContext = React3.createContext(null);
|
|
526
|
+
function makeRoomContextBundle(client) {
|
|
527
|
+
function RoomProvider_withImplicitLiveblocksProvider(props) {
|
|
528
|
+
return /* @__PURE__ */ React3.createElement(LiveblocksProvider, { client }, /* @__PURE__ */ React3.createElement(RoomProvider, { ...props }));
|
|
475
529
|
}
|
|
476
|
-
|
|
477
|
-
|
|
530
|
+
const { useMentionSuggestions } = getExtrasForClient(client);
|
|
531
|
+
const shared = createSharedContext(client);
|
|
532
|
+
const bundle = {
|
|
533
|
+
RoomContext,
|
|
534
|
+
RoomProvider: RoomProvider_withImplicitLiveblocksProvider,
|
|
535
|
+
useRoom,
|
|
536
|
+
useStatus,
|
|
537
|
+
useBatch,
|
|
538
|
+
useBroadcastEvent,
|
|
539
|
+
useOthersListener,
|
|
540
|
+
useLostConnectionListener,
|
|
541
|
+
useErrorListener,
|
|
542
|
+
useEventListener,
|
|
543
|
+
useHistory,
|
|
544
|
+
useUndo,
|
|
545
|
+
useRedo,
|
|
546
|
+
useCanRedo,
|
|
547
|
+
useCanUndo,
|
|
548
|
+
// These are just aliases. The passed-in key will define their return values.
|
|
549
|
+
useList: useLegacyKey,
|
|
550
|
+
useMap: useLegacyKey,
|
|
551
|
+
useObject: useLegacyKey,
|
|
552
|
+
useStorageRoot,
|
|
553
|
+
useStorage: make_useStorage(),
|
|
554
|
+
useSelf,
|
|
555
|
+
useMyPresence,
|
|
556
|
+
useUpdateMyPresence,
|
|
557
|
+
useOthers,
|
|
558
|
+
useOthersMapped: make_useOthersMapped(),
|
|
559
|
+
useOthersConnectionIds,
|
|
560
|
+
useOther: make_useOther(),
|
|
561
|
+
useMutation: make_useMutation(),
|
|
562
|
+
useThreads,
|
|
563
|
+
useCreateThread,
|
|
564
|
+
useEditThreadMetadata,
|
|
565
|
+
useCreateComment,
|
|
566
|
+
useEditComment,
|
|
567
|
+
useDeleteComment,
|
|
568
|
+
useAddReaction,
|
|
569
|
+
useRemoveReaction,
|
|
570
|
+
useMarkThreadAsRead,
|
|
571
|
+
useThreadSubscription,
|
|
572
|
+
useRoomNotificationSettings,
|
|
573
|
+
useUpdateRoomNotificationSettings,
|
|
574
|
+
...shared.classic,
|
|
575
|
+
suspense: {
|
|
576
|
+
RoomContext,
|
|
577
|
+
RoomProvider: RoomProvider_withImplicitLiveblocksProvider,
|
|
578
|
+
useRoom,
|
|
579
|
+
useStatus,
|
|
580
|
+
useBatch,
|
|
581
|
+
useBroadcastEvent,
|
|
582
|
+
useOthersListener,
|
|
583
|
+
useLostConnectionListener,
|
|
584
|
+
useErrorListener,
|
|
585
|
+
useEventListener,
|
|
586
|
+
useHistory,
|
|
587
|
+
useUndo,
|
|
588
|
+
useRedo,
|
|
589
|
+
useCanRedo,
|
|
590
|
+
useCanUndo,
|
|
591
|
+
// Legacy hooks
|
|
592
|
+
useList: useLegacyKeySuspense,
|
|
593
|
+
useMap: useLegacyKeySuspense,
|
|
594
|
+
useObject: useLegacyKeySuspense,
|
|
595
|
+
useStorageRoot,
|
|
596
|
+
useStorage: make_useStorageSuspense(),
|
|
597
|
+
useSelf: useSelfSuspense,
|
|
598
|
+
useMyPresence,
|
|
599
|
+
useUpdateMyPresence,
|
|
600
|
+
useOthers: make_useOthersSuspense(),
|
|
601
|
+
useOthersMapped: make_useOthersMappedSuspense(),
|
|
602
|
+
useOthersConnectionIds: useOthersConnectionIdsSuspense,
|
|
603
|
+
useOther: make_useOtherSuspense(),
|
|
604
|
+
useMutation: make_useMutation(),
|
|
605
|
+
useThreads: useThreadsSuspense,
|
|
606
|
+
useCreateThread,
|
|
607
|
+
useEditThreadMetadata,
|
|
608
|
+
useCreateComment,
|
|
609
|
+
useEditComment,
|
|
610
|
+
useDeleteComment,
|
|
611
|
+
useAddReaction,
|
|
612
|
+
useRemoveReaction,
|
|
613
|
+
useMarkThreadAsRead,
|
|
614
|
+
useThreadSubscription,
|
|
615
|
+
useRoomNotificationSettings: useRoomNotificationSettingsSuspense,
|
|
616
|
+
useUpdateRoomNotificationSettings,
|
|
617
|
+
...shared.suspense
|
|
618
|
+
},
|
|
619
|
+
[kInternal]: {
|
|
620
|
+
useCurrentUserId,
|
|
621
|
+
useMentionSuggestions,
|
|
622
|
+
useCommentsErrorListener,
|
|
623
|
+
ThreadCreateCallbackProvider: ThreadCreateCallbackContext.Provider,
|
|
624
|
+
useThreadCreateCallback,
|
|
625
|
+
ThreadDeleteCallbackProvider: ThreadDeleteCallbackContext.Provider,
|
|
626
|
+
useThreadDeleteCallback,
|
|
627
|
+
ComposerFocusCallbackProvider: ComposerFocusCallbackContext.Provider,
|
|
628
|
+
useComposerFocusCallback,
|
|
629
|
+
IsThreadActiveCallbackProvider: IsThreadActiveCallbackContext.Provider,
|
|
630
|
+
useIsThreadActiveCallback
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
return Object.defineProperty(bundle, kInternal, {
|
|
634
|
+
enumerable: false
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
function RoomProvider(props) {
|
|
638
|
+
const client = useClient();
|
|
639
|
+
const [cache] = React3.useState(
|
|
640
|
+
() => /* @__PURE__ */ new Map()
|
|
641
|
+
);
|
|
642
|
+
const stableEnterRoom = React3.useCallback(
|
|
643
|
+
(roomId, options) => {
|
|
644
|
+
const cached = cache.get(roomId);
|
|
645
|
+
if (cached)
|
|
646
|
+
return cached;
|
|
647
|
+
const rv = client.enterRoom(roomId, options);
|
|
648
|
+
const origLeave = rv.leave;
|
|
649
|
+
rv.leave = () => {
|
|
650
|
+
origLeave();
|
|
651
|
+
cache.delete(roomId);
|
|
652
|
+
};
|
|
653
|
+
cache.set(roomId, rv);
|
|
654
|
+
return rv;
|
|
655
|
+
},
|
|
656
|
+
[client, cache]
|
|
657
|
+
);
|
|
658
|
+
return /* @__PURE__ */ React3.createElement(RoomProviderInner, { ...props, stableEnterRoom });
|
|
659
|
+
}
|
|
660
|
+
function RoomProviderInner(props) {
|
|
661
|
+
const client = useClient();
|
|
662
|
+
const { id: roomId, stableEnterRoom } = props;
|
|
663
|
+
if (process.env.NODE_ENV !== "production") {
|
|
664
|
+
if (!roomId) {
|
|
665
|
+
throw new Error(
|
|
666
|
+
"RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required"
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
if (typeof roomId !== "string") {
|
|
670
|
+
throw new Error("RoomProvider id property should be a string.");
|
|
671
|
+
}
|
|
672
|
+
const majorReactVersion = parseInt(React3.version) || 1;
|
|
673
|
+
const oldReactVersion = majorReactVersion < 18;
|
|
674
|
+
errorIf(
|
|
675
|
+
oldReactVersion && props.unstable_batchedUpdates === void 0,
|
|
676
|
+
missing_unstable_batchedUpdates(majorReactVersion, roomId)
|
|
677
|
+
);
|
|
678
|
+
deprecateIf(
|
|
679
|
+
!oldReactVersion && props.unstable_batchedUpdates !== void 0,
|
|
680
|
+
superfluous_unstable_batchedUpdates
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
const frozenProps = useInitial({
|
|
684
|
+
initialPresence: props.initialPresence,
|
|
685
|
+
initialStorage: props.initialStorage,
|
|
686
|
+
unstable_batchedUpdates: props.unstable_batchedUpdates,
|
|
687
|
+
autoConnect: props.autoConnect ?? props.shouldInitiallyConnect ?? typeof window !== "undefined"
|
|
688
|
+
});
|
|
689
|
+
const [{ room }, setRoomLeavePair] = React3.useState(
|
|
690
|
+
() => stableEnterRoom(roomId, {
|
|
691
|
+
...frozenProps,
|
|
692
|
+
autoConnect: false
|
|
693
|
+
// Deliberately using false here on the first render, see below
|
|
694
|
+
})
|
|
695
|
+
);
|
|
696
|
+
React3.useEffect(() => {
|
|
697
|
+
const { store } = getExtrasForClient(client);
|
|
698
|
+
async function handleCommentEvent(message) {
|
|
699
|
+
const info = await room[kInternal].comments.getThread({
|
|
700
|
+
threadId: message.threadId
|
|
701
|
+
});
|
|
702
|
+
if (!info) {
|
|
703
|
+
store.deleteThread(message.threadId);
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const { thread, inboxNotification } = info;
|
|
707
|
+
const existingThread = store.get().threads[message.threadId];
|
|
708
|
+
switch (message.type) {
|
|
709
|
+
case ServerMsgCode.COMMENT_EDITED:
|
|
710
|
+
case ServerMsgCode.THREAD_METADATA_UPDATED:
|
|
711
|
+
case ServerMsgCode.COMMENT_REACTION_ADDED:
|
|
712
|
+
case ServerMsgCode.COMMENT_REACTION_REMOVED:
|
|
713
|
+
case ServerMsgCode.COMMENT_DELETED:
|
|
714
|
+
if (!existingThread)
|
|
715
|
+
break;
|
|
716
|
+
store.updateThreadAndNotification(thread, inboxNotification);
|
|
717
|
+
break;
|
|
718
|
+
case ServerMsgCode.COMMENT_CREATED:
|
|
719
|
+
store.updateThreadAndNotification(thread, inboxNotification);
|
|
720
|
+
break;
|
|
721
|
+
default:
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return room.events.comments.subscribe(
|
|
726
|
+
(message) => void handleCommentEvent(message)
|
|
727
|
+
);
|
|
728
|
+
}, [client, room]);
|
|
729
|
+
React3.useEffect(() => {
|
|
730
|
+
const { getThreadsUpdates } = getExtrasForClient(client);
|
|
731
|
+
void getThreadsUpdates(room.id);
|
|
732
|
+
}, [client, room.id]);
|
|
733
|
+
React3.useEffect(() => {
|
|
734
|
+
function handleIsOnline() {
|
|
735
|
+
const { getThreadsUpdates } = getExtrasForClient(client);
|
|
736
|
+
void getThreadsUpdates(room.id);
|
|
737
|
+
}
|
|
738
|
+
window.addEventListener("online", handleIsOnline);
|
|
739
|
+
return () => {
|
|
740
|
+
window.removeEventListener("online", handleIsOnline);
|
|
741
|
+
};
|
|
742
|
+
}, [client, room.id]);
|
|
743
|
+
React3.useEffect(() => {
|
|
744
|
+
const pair = stableEnterRoom(roomId, frozenProps);
|
|
745
|
+
setRoomLeavePair(pair);
|
|
746
|
+
const { room: room2, leave } = pair;
|
|
747
|
+
if (frozenProps.autoConnect) {
|
|
748
|
+
room2.connect();
|
|
749
|
+
}
|
|
750
|
+
return () => {
|
|
751
|
+
leave();
|
|
752
|
+
};
|
|
753
|
+
}, [roomId, frozenProps, stableEnterRoom]);
|
|
754
|
+
return /* @__PURE__ */ React3.createElement(RoomContext.Provider, { value: room }, props.children);
|
|
755
|
+
}
|
|
756
|
+
function useRoom() {
|
|
757
|
+
const room = React3.useContext(RoomContext);
|
|
758
|
+
if (room === null) {
|
|
759
|
+
throw new Error("RoomProvider is missing from the React tree.");
|
|
478
760
|
}
|
|
479
|
-
|
|
480
|
-
|
|
761
|
+
return room;
|
|
762
|
+
}
|
|
763
|
+
function useStatus() {
|
|
764
|
+
const room = useRoom();
|
|
765
|
+
const subscribe = room.events.status.subscribe;
|
|
766
|
+
const getSnapshot = room.getStatus;
|
|
767
|
+
const getServerSnapshot = room.getStatus;
|
|
768
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
769
|
+
}
|
|
770
|
+
function useBatch() {
|
|
771
|
+
return useRoom().batch;
|
|
772
|
+
}
|
|
773
|
+
function useBroadcastEvent() {
|
|
774
|
+
const room = useRoom();
|
|
775
|
+
return React3.useCallback(
|
|
776
|
+
(event, options = { shouldQueueEventIfNotReady: false }) => {
|
|
777
|
+
room.broadcastEvent(event, options);
|
|
778
|
+
},
|
|
779
|
+
[room]
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
function useOthersListener(callback) {
|
|
783
|
+
const room = useRoom();
|
|
784
|
+
const savedCallback = useLatest(callback);
|
|
785
|
+
React3.useEffect(
|
|
786
|
+
() => room.events.others.subscribe((event) => savedCallback.current(event)),
|
|
787
|
+
[room, savedCallback]
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
function useLostConnectionListener(callback) {
|
|
791
|
+
const room = useRoom();
|
|
792
|
+
const savedCallback = useLatest(callback);
|
|
793
|
+
React3.useEffect(
|
|
794
|
+
() => room.events.lostConnection.subscribe(
|
|
795
|
+
(event) => savedCallback.current(event)
|
|
796
|
+
),
|
|
797
|
+
[room, savedCallback]
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
function useErrorListener(callback) {
|
|
801
|
+
const room = useRoom();
|
|
802
|
+
const savedCallback = useLatest(callback);
|
|
803
|
+
React3.useEffect(
|
|
804
|
+
() => room.events.error.subscribe((e) => savedCallback.current(e)),
|
|
805
|
+
[room, savedCallback]
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
function useEventListener(callback) {
|
|
809
|
+
const room = useRoom();
|
|
810
|
+
const savedCallback = useLatest(callback);
|
|
811
|
+
React3.useEffect(() => {
|
|
812
|
+
const listener = (eventData) => {
|
|
813
|
+
savedCallback.current(eventData);
|
|
814
|
+
};
|
|
815
|
+
return room.events.customEvent.subscribe(listener);
|
|
816
|
+
}, [room, savedCallback]);
|
|
817
|
+
}
|
|
818
|
+
function useHistory() {
|
|
819
|
+
return useRoom().history;
|
|
820
|
+
}
|
|
821
|
+
function useUndo() {
|
|
822
|
+
return useHistory().undo;
|
|
823
|
+
}
|
|
824
|
+
function useRedo() {
|
|
825
|
+
return useHistory().redo;
|
|
826
|
+
}
|
|
827
|
+
function useCanUndo() {
|
|
828
|
+
const room = useRoom();
|
|
829
|
+
const subscribe = room.events.history.subscribe;
|
|
830
|
+
const canUndo = room.history.canUndo;
|
|
831
|
+
return useSyncExternalStore(subscribe, canUndo, canUndo);
|
|
832
|
+
}
|
|
833
|
+
function useCanRedo() {
|
|
834
|
+
const room = useRoom();
|
|
835
|
+
const subscribe = room.events.history.subscribe;
|
|
836
|
+
const canRedo = room.history.canRedo;
|
|
837
|
+
return useSyncExternalStore(subscribe, canRedo, canRedo);
|
|
838
|
+
}
|
|
839
|
+
function useSelf(maybeSelector, isEqual) {
|
|
840
|
+
const room = useRoom();
|
|
841
|
+
const subscribe = room.events.self.subscribe;
|
|
842
|
+
const getSnapshot = room.getSelf;
|
|
843
|
+
const selector = maybeSelector ?? identity;
|
|
844
|
+
const wrappedSelector = React3.useCallback(
|
|
845
|
+
(me) => me !== null ? selector(me) : null,
|
|
846
|
+
[selector]
|
|
847
|
+
);
|
|
848
|
+
const getServerSnapshot = alwaysNull;
|
|
849
|
+
return useSyncExternalStoreWithSelector(
|
|
850
|
+
subscribe,
|
|
851
|
+
getSnapshot,
|
|
852
|
+
getServerSnapshot,
|
|
853
|
+
wrappedSelector,
|
|
854
|
+
isEqual
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
function useCurrentUserId() {
|
|
858
|
+
return useSelf((user) => typeof user.id === "string" ? user.id : null);
|
|
859
|
+
}
|
|
860
|
+
function useMyPresence() {
|
|
861
|
+
const room = useRoom();
|
|
862
|
+
const subscribe = room.events.myPresence.subscribe;
|
|
863
|
+
const getSnapshot = room.getPresence;
|
|
864
|
+
const presence = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
865
|
+
const setPresence = room.updatePresence;
|
|
866
|
+
return [presence, setPresence];
|
|
867
|
+
}
|
|
868
|
+
function useUpdateMyPresence() {
|
|
869
|
+
return useRoom().updatePresence;
|
|
870
|
+
}
|
|
871
|
+
function useOthers(selector, isEqual) {
|
|
872
|
+
const room = useRoom();
|
|
873
|
+
const subscribe = room.events.others.subscribe;
|
|
874
|
+
const getSnapshot = room.getOthers;
|
|
875
|
+
const getServerSnapshot = alwaysEmptyList;
|
|
876
|
+
return useSyncExternalStoreWithSelector(
|
|
877
|
+
subscribe,
|
|
878
|
+
getSnapshot,
|
|
879
|
+
getServerSnapshot,
|
|
880
|
+
selector ?? identity,
|
|
881
|
+
isEqual
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
function make_useOthersMapped() {
|
|
885
|
+
return function useOthersMapped(itemSelector, itemIsEqual) {
|
|
886
|
+
const wrappedSelector = React3.useCallback(
|
|
481
887
|
(others) => others.map(
|
|
482
888
|
(other) => [other.connectionId, itemSelector(other)]
|
|
483
889
|
),
|
|
484
890
|
[itemSelector]
|
|
485
891
|
);
|
|
486
|
-
const wrappedIsEqual =
|
|
892
|
+
const wrappedIsEqual = React3.useCallback(
|
|
487
893
|
(a, b) => {
|
|
488
894
|
const eq = itemIsEqual ?? Object.is;
|
|
489
895
|
return a.length === b.length && a.every((atuple, index) => {
|
|
@@ -494,10 +900,15 @@ function createRoomContext(client, options) {
|
|
|
494
900
|
[itemIsEqual]
|
|
495
901
|
);
|
|
496
902
|
return useOthers(wrappedSelector, wrappedIsEqual);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
function useOthersConnectionIds() {
|
|
906
|
+
return useOthers(selectorFor_useOthersConnectionIds, shallow);
|
|
907
|
+
}
|
|
908
|
+
var NOT_FOUND = Symbol();
|
|
909
|
+
function make_useOther() {
|
|
910
|
+
return function useOther(connectionId, selector, isEqual) {
|
|
911
|
+
const wrappedSelector = React3.useCallback(
|
|
501
912
|
(others) => {
|
|
502
913
|
const other2 = others.find(
|
|
503
914
|
(other3) => other3.connectionId === connectionId
|
|
@@ -506,7 +917,7 @@ function createRoomContext(client, options) {
|
|
|
506
917
|
},
|
|
507
918
|
[connectionId, selector]
|
|
508
919
|
);
|
|
509
|
-
const wrappedIsEqual =
|
|
920
|
+
const wrappedIsEqual = React3.useCallback(
|
|
510
921
|
(prev, curr) => {
|
|
511
922
|
if (prev === NOT_FOUND || curr === NOT_FOUND) {
|
|
512
923
|
return prev === curr;
|
|
@@ -523,153 +934,31 @@ function createRoomContext(client, options) {
|
|
|
523
934
|
);
|
|
524
935
|
}
|
|
525
936
|
return other;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
function useMutableStorageRoot() {
|
|
940
|
+
const room = useRoom();
|
|
941
|
+
const subscribe = room.events.storageDidLoad.subscribeOnce;
|
|
942
|
+
const getSnapshot = room.getStorageSnapshot;
|
|
943
|
+
const getServerSnapshot = alwaysNull;
|
|
944
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
945
|
+
}
|
|
946
|
+
function useStorageRoot() {
|
|
947
|
+
return [useMutableStorageRoot()];
|
|
948
|
+
}
|
|
949
|
+
function make_useStorage() {
|
|
950
|
+
return function useStorage(selector, isEqual) {
|
|
537
951
|
const room = useRoom();
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
() =>
|
|
541
|
-
[
|
|
952
|
+
const rootOrNull = useMutableStorageRoot();
|
|
953
|
+
const wrappedSelector = React3.useCallback(
|
|
954
|
+
(rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
|
|
955
|
+
[selector]
|
|
542
956
|
);
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
const savedCallback = useLatest(callback);
|
|
547
|
-
React2.useEffect(
|
|
548
|
-
() => room.events.lostConnection.subscribe(
|
|
549
|
-
(event) => savedCallback.current(event)
|
|
550
|
-
),
|
|
551
|
-
[room, savedCallback]
|
|
957
|
+
const subscribe = React3.useCallback(
|
|
958
|
+
(onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop,
|
|
959
|
+
[room, rootOrNull]
|
|
552
960
|
);
|
|
553
|
-
|
|
554
|
-
function useErrorListener(callback) {
|
|
555
|
-
const room = useRoom();
|
|
556
|
-
const savedCallback = useLatest(callback);
|
|
557
|
-
React2.useEffect(
|
|
558
|
-
() => room.events.error.subscribe((e) => savedCallback.current(e)),
|
|
559
|
-
[room, savedCallback]
|
|
560
|
-
);
|
|
561
|
-
}
|
|
562
|
-
function useEventListener(callback) {
|
|
563
|
-
const room = useRoom();
|
|
564
|
-
const savedCallback = useLatest(callback);
|
|
565
|
-
React2.useEffect(() => {
|
|
566
|
-
const listener = (eventData) => {
|
|
567
|
-
savedCallback.current(eventData);
|
|
568
|
-
};
|
|
569
|
-
return room.events.customEvent.subscribe(listener);
|
|
570
|
-
}, [room, savedCallback]);
|
|
571
|
-
}
|
|
572
|
-
function useSelf(maybeSelector, isEqual) {
|
|
573
|
-
const room = useRoom();
|
|
574
|
-
const subscribe = room.events.self.subscribe;
|
|
575
|
-
const getSnapshot = room.getSelf;
|
|
576
|
-
const selector = maybeSelector ?? identity;
|
|
577
|
-
const wrappedSelector = React2.useCallback(
|
|
578
|
-
(me) => me !== null ? selector(me) : null,
|
|
579
|
-
[selector]
|
|
580
|
-
);
|
|
581
|
-
const getServerSnapshot = alwaysNull;
|
|
582
|
-
return useSyncExternalStoreWithSelector(
|
|
583
|
-
subscribe,
|
|
584
|
-
getSnapshot,
|
|
585
|
-
getServerSnapshot,
|
|
586
|
-
wrappedSelector,
|
|
587
|
-
isEqual
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
function useMutableStorageRoot() {
|
|
591
|
-
const room = useRoom();
|
|
592
|
-
const subscribe = room.events.storageDidLoad.subscribeOnce;
|
|
593
|
-
const getSnapshot = room.getStorageSnapshot;
|
|
594
|
-
const getServerSnapshot = alwaysNull;
|
|
595
|
-
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
596
|
-
}
|
|
597
|
-
function useStorageRoot() {
|
|
598
|
-
return [useMutableStorageRoot()];
|
|
599
|
-
}
|
|
600
|
-
function useHistory() {
|
|
601
|
-
return useRoom().history;
|
|
602
|
-
}
|
|
603
|
-
function useUndo() {
|
|
604
|
-
return useHistory().undo;
|
|
605
|
-
}
|
|
606
|
-
function useRedo() {
|
|
607
|
-
return useHistory().redo;
|
|
608
|
-
}
|
|
609
|
-
function useCanUndo() {
|
|
610
|
-
const room = useRoom();
|
|
611
|
-
const subscribe = room.events.history.subscribe;
|
|
612
|
-
const canUndo = room.history.canUndo;
|
|
613
|
-
return useSyncExternalStore(subscribe, canUndo, canUndo);
|
|
614
|
-
}
|
|
615
|
-
function useCanRedo() {
|
|
616
|
-
const room = useRoom();
|
|
617
|
-
const subscribe = room.events.history.subscribe;
|
|
618
|
-
const canRedo = room.history.canRedo;
|
|
619
|
-
return useSyncExternalStore(subscribe, canRedo, canRedo);
|
|
620
|
-
}
|
|
621
|
-
function useBatch() {
|
|
622
|
-
return useRoom().batch;
|
|
623
|
-
}
|
|
624
|
-
function useLegacyKey(key) {
|
|
625
|
-
const room = useRoom();
|
|
626
|
-
const rootOrNull = useMutableStorageRoot();
|
|
627
|
-
const rerender = useRerender();
|
|
628
|
-
React2.useEffect(() => {
|
|
629
|
-
if (rootOrNull === null) {
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
const root = rootOrNull;
|
|
633
|
-
let unsubCurr;
|
|
634
|
-
let curr = root.get(key);
|
|
635
|
-
function subscribeToCurr() {
|
|
636
|
-
unsubCurr = isLiveNode(curr) ? room.subscribe(curr, rerender) : void 0;
|
|
637
|
-
}
|
|
638
|
-
function onRootChange() {
|
|
639
|
-
const newValue = root.get(key);
|
|
640
|
-
if (newValue !== curr) {
|
|
641
|
-
unsubCurr?.();
|
|
642
|
-
curr = newValue;
|
|
643
|
-
subscribeToCurr();
|
|
644
|
-
rerender();
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
subscribeToCurr();
|
|
648
|
-
rerender();
|
|
649
|
-
const unsubscribeRoot = room.subscribe(root, onRootChange);
|
|
650
|
-
return () => {
|
|
651
|
-
unsubscribeRoot();
|
|
652
|
-
unsubCurr?.();
|
|
653
|
-
};
|
|
654
|
-
}, [rootOrNull, room, key, rerender]);
|
|
655
|
-
if (rootOrNull === null) {
|
|
656
|
-
return null;
|
|
657
|
-
} else {
|
|
658
|
-
return rootOrNull.get(key);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
function useStorage(selector, isEqual) {
|
|
662
|
-
const room = useRoom();
|
|
663
|
-
const rootOrNull = useMutableStorageRoot();
|
|
664
|
-
const wrappedSelector = React2.useCallback(
|
|
665
|
-
(rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
|
|
666
|
-
[selector]
|
|
667
|
-
);
|
|
668
|
-
const subscribe = React2.useCallback(
|
|
669
|
-
(onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop,
|
|
670
|
-
[room, rootOrNull]
|
|
671
|
-
);
|
|
672
|
-
const getSnapshot = React2.useCallback(() => {
|
|
961
|
+
const getSnapshot = React3.useCallback(() => {
|
|
673
962
|
if (rootOrNull === null) {
|
|
674
963
|
return null;
|
|
675
964
|
} else {
|
|
@@ -686,38 +975,49 @@ function createRoomContext(client, options) {
|
|
|
686
975
|
wrappedSelector,
|
|
687
976
|
isEqual
|
|
688
977
|
);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
function useSuspendUntilStorageLoaded() {
|
|
698
|
-
const room = useRoom();
|
|
699
|
-
if (room.getStorageSnapshot() !== null) {
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function useLegacyKey(key) {
|
|
981
|
+
const room = useRoom();
|
|
982
|
+
const rootOrNull = useMutableStorageRoot();
|
|
983
|
+
const rerender = useRerender();
|
|
984
|
+
React3.useEffect(() => {
|
|
985
|
+
if (rootOrNull === null) {
|
|
700
986
|
return;
|
|
701
987
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
function useSuspendUntilPresenceLoaded() {
|
|
708
|
-
const room = useRoom();
|
|
709
|
-
if (room.getSelf() !== null) {
|
|
710
|
-
return;
|
|
988
|
+
const root = rootOrNull;
|
|
989
|
+
let unsubCurr;
|
|
990
|
+
let curr = root.get(key);
|
|
991
|
+
function subscribeToCurr() {
|
|
992
|
+
unsubCurr = isLiveNode(curr) ? room.subscribe(curr, rerender) : void 0;
|
|
711
993
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
994
|
+
function onRootChange() {
|
|
995
|
+
const newValue = root.get(key);
|
|
996
|
+
if (newValue !== curr) {
|
|
997
|
+
unsubCurr?.();
|
|
998
|
+
curr = newValue;
|
|
999
|
+
subscribeToCurr();
|
|
1000
|
+
rerender();
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
subscribeToCurr();
|
|
1004
|
+
rerender();
|
|
1005
|
+
const unsubscribeRoot = room.subscribe(root, onRootChange);
|
|
1006
|
+
return () => {
|
|
1007
|
+
unsubscribeRoot();
|
|
1008
|
+
unsubCurr?.();
|
|
1009
|
+
};
|
|
1010
|
+
}, [rootOrNull, room, key, rerender]);
|
|
1011
|
+
if (rootOrNull === null) {
|
|
1012
|
+
return null;
|
|
1013
|
+
} else {
|
|
1014
|
+
return rootOrNull.get(key);
|
|
717
1015
|
}
|
|
718
|
-
|
|
1016
|
+
}
|
|
1017
|
+
function make_useMutation() {
|
|
1018
|
+
return function useMutation(callback, deps) {
|
|
719
1019
|
const room = useRoom();
|
|
720
|
-
return
|
|
1020
|
+
return React3.useMemo(
|
|
721
1021
|
() => {
|
|
722
1022
|
return (...args) => (
|
|
723
1023
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
@@ -735,1103 +1035,887 @@ function createRoomContext(client, options) {
|
|
|
735
1035
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
736
1036
|
[room, ...deps]
|
|
737
1037
|
);
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
return useOthersConnectionIds();
|
|
763
|
-
}
|
|
764
|
-
function useOthersMappedSuspense(itemSelector, itemIsEqual) {
|
|
765
|
-
useSuspendUntilPresenceLoaded();
|
|
766
|
-
return useOthersMapped(itemSelector, itemIsEqual);
|
|
767
|
-
}
|
|
768
|
-
function useOtherSuspense(connectionId, selector, isEqual) {
|
|
769
|
-
useSuspendUntilPresenceLoaded();
|
|
770
|
-
return useOther(connectionId, selector, isEqual);
|
|
771
|
-
}
|
|
772
|
-
function useLegacyKeySuspense(key) {
|
|
773
|
-
useSuspendUntilStorageLoaded();
|
|
774
|
-
return useLegacyKey(key);
|
|
775
|
-
}
|
|
776
|
-
const store = client[kInternal].cacheStore;
|
|
777
|
-
function onMutationFailure(innerError, optimisticUpdateId, createPublicError) {
|
|
778
|
-
store.set((state) => ({
|
|
779
|
-
...state,
|
|
780
|
-
optimisticUpdates: state.optimisticUpdates.filter(
|
|
781
|
-
(update) => update.id !== optimisticUpdateId
|
|
782
|
-
)
|
|
783
|
-
}));
|
|
784
|
-
if (innerError instanceof CommentsApiError) {
|
|
785
|
-
const error = handleApiError(innerError);
|
|
786
|
-
commentsErrorEventSource.notify(createPublicError(error));
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
if (innerError instanceof NotificationsApiError) {
|
|
790
|
-
handleApiError(innerError);
|
|
791
|
-
return;
|
|
792
|
-
}
|
|
793
|
-
throw innerError;
|
|
794
|
-
}
|
|
795
|
-
const subscribersByQuery = /* @__PURE__ */ new Map();
|
|
796
|
-
const requestsByQuery = /* @__PURE__ */ new Map();
|
|
797
|
-
const poller = makePoller(refreshThreadsAndNotifications);
|
|
798
|
-
async function refreshThreadsAndNotifications() {
|
|
799
|
-
const requests = [];
|
|
800
|
-
client[kInternal].getRoomIds().map((roomId) => {
|
|
801
|
-
const room = client.getRoom(roomId);
|
|
802
|
-
if (room === null)
|
|
803
|
-
return;
|
|
804
|
-
requests.push(getThreadsUpdates(room.id));
|
|
805
|
-
});
|
|
806
|
-
await Promise.allSettled(requests);
|
|
807
|
-
}
|
|
808
|
-
function incrementQuerySubscribers(queryKey) {
|
|
809
|
-
const subscribers = subscribersByQuery.get(queryKey) ?? 0;
|
|
810
|
-
subscribersByQuery.set(queryKey, subscribers + 1);
|
|
811
|
-
poller.start(POLLING_INTERVAL);
|
|
812
|
-
}
|
|
813
|
-
function decrementQuerySubscribers(queryKey) {
|
|
814
|
-
const subscribers = subscribersByQuery.get(queryKey);
|
|
815
|
-
if (subscribers === void 0 || subscribers <= 0) {
|
|
816
|
-
console2.warn(
|
|
817
|
-
`Internal unexpected behavior. Cannot decrease subscriber count for query "${queryKey}"`
|
|
818
|
-
);
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
subscribersByQuery.set(queryKey, subscribers - 1);
|
|
822
|
-
let totalSubscribers = 0;
|
|
823
|
-
for (const subscribers2 of subscribersByQuery.values()) {
|
|
824
|
-
totalSubscribers += subscribers2;
|
|
825
|
-
}
|
|
826
|
-
if (totalSubscribers <= 0) {
|
|
827
|
-
poller.stop();
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
async function getThreadsAndInboxNotifications(room, queryKey, options2, { retryCount } = { retryCount: 0 }) {
|
|
831
|
-
const existingRequest = requestsByQuery.get(queryKey);
|
|
832
|
-
if (existingRequest !== void 0)
|
|
833
|
-
return existingRequest;
|
|
834
|
-
const request = room[kInternal].comments.getThreads(options2);
|
|
835
|
-
requestsByQuery.set(queryKey, request);
|
|
836
|
-
store.setQueryState(queryKey, {
|
|
837
|
-
isLoading: true
|
|
838
|
-
});
|
|
839
|
-
try {
|
|
840
|
-
const result = await request;
|
|
841
|
-
store.updateThreadsAndNotifications(
|
|
842
|
-
result.threads,
|
|
843
|
-
result.inboxNotifications,
|
|
844
|
-
result.deletedThreads,
|
|
845
|
-
result.deletedInboxNotifications,
|
|
846
|
-
queryKey
|
|
847
|
-
);
|
|
848
|
-
const lastRequestedAt = lastRequestedAtByRoom.get(room.id);
|
|
849
|
-
if (lastRequestedAt === void 0 || lastRequestedAt > result.meta.requestedAt) {
|
|
850
|
-
lastRequestedAtByRoom.set(room.id, result.meta.requestedAt);
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
function useThreads(options = {
|
|
1041
|
+
query: { metadata: {} }
|
|
1042
|
+
}) {
|
|
1043
|
+
const { scrollOnLoad = true } = options;
|
|
1044
|
+
const client = useClient();
|
|
1045
|
+
const room = useRoom();
|
|
1046
|
+
const queryKey = React3.useMemo(
|
|
1047
|
+
() => generateQueryKey(room.id, options.query),
|
|
1048
|
+
[room, options]
|
|
1049
|
+
);
|
|
1050
|
+
const { store, getThreadsAndInboxNotifications, incrementQuerySubscribers } = getExtrasForClient(client);
|
|
1051
|
+
React3.useEffect(() => {
|
|
1052
|
+
void getThreadsAndInboxNotifications(room, queryKey, options);
|
|
1053
|
+
return incrementQuerySubscribers(queryKey);
|
|
1054
|
+
}, [room, queryKey]);
|
|
1055
|
+
const selector = React3.useCallback(
|
|
1056
|
+
(state2) => {
|
|
1057
|
+
const query = state2.queries[queryKey];
|
|
1058
|
+
if (query === void 0 || query.isLoading) {
|
|
1059
|
+
return {
|
|
1060
|
+
isLoading: true
|
|
1061
|
+
};
|
|
851
1062
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
});
|
|
859
|
-
}, retryCount);
|
|
860
|
-
store.setQueryState(queryKey, {
|
|
1063
|
+
return {
|
|
1064
|
+
threads: client[kInternal].comments.selectedThreads(
|
|
1065
|
+
room.id,
|
|
1066
|
+
state2,
|
|
1067
|
+
options
|
|
1068
|
+
),
|
|
861
1069
|
isLoading: false,
|
|
862
|
-
error:
|
|
1070
|
+
error: query.error
|
|
1071
|
+
};
|
|
1072
|
+
},
|
|
1073
|
+
[room, queryKey]
|
|
1074
|
+
// eslint-disable-line react-hooks/exhaustive-deps
|
|
1075
|
+
);
|
|
1076
|
+
const state = useSyncExternalStoreWithSelector(
|
|
1077
|
+
store.subscribe,
|
|
1078
|
+
store.get,
|
|
1079
|
+
store.get,
|
|
1080
|
+
selector
|
|
1081
|
+
);
|
|
1082
|
+
useScrollToCommentOnLoadEffect(scrollOnLoad, state);
|
|
1083
|
+
return state;
|
|
1084
|
+
}
|
|
1085
|
+
function useCommentsErrorListener(callback) {
|
|
1086
|
+
const client = useClient();
|
|
1087
|
+
const savedCallback = useLatest(callback);
|
|
1088
|
+
const { commentsErrorEventSource } = getExtrasForClient(client);
|
|
1089
|
+
React3.useEffect(() => {
|
|
1090
|
+
return commentsErrorEventSource.subscribe(savedCallback.current);
|
|
1091
|
+
}, [savedCallback, commentsErrorEventSource]);
|
|
1092
|
+
}
|
|
1093
|
+
function useThreadCreateCallback() {
|
|
1094
|
+
return React3.useContext(ThreadCreateCallbackContext);
|
|
1095
|
+
}
|
|
1096
|
+
function useThreadDeleteCallback() {
|
|
1097
|
+
return React3.useContext(ThreadDeleteCallbackContext);
|
|
1098
|
+
}
|
|
1099
|
+
function useComposerFocusCallback() {
|
|
1100
|
+
return React3.useContext(ComposerFocusCallbackContext);
|
|
1101
|
+
}
|
|
1102
|
+
function useIsThreadActiveCallback() {
|
|
1103
|
+
return React3.useContext(IsThreadActiveCallbackContext);
|
|
1104
|
+
}
|
|
1105
|
+
function useCreateThread() {
|
|
1106
|
+
const client = useClient();
|
|
1107
|
+
const room = useRoom();
|
|
1108
|
+
const onCreateThread = useThreadCreateCallback();
|
|
1109
|
+
return React3.useCallback(
|
|
1110
|
+
(options) => {
|
|
1111
|
+
const body = options.body;
|
|
1112
|
+
const metadata = "metadata" in options ? options.metadata : {};
|
|
1113
|
+
const threadId = client[kInternal].comments.createThreadId();
|
|
1114
|
+
const commentId = client[kInternal].comments.createCommentId();
|
|
1115
|
+
const createdAt = /* @__PURE__ */ new Date();
|
|
1116
|
+
const newComment = {
|
|
1117
|
+
id: commentId,
|
|
1118
|
+
threadId,
|
|
1119
|
+
roomId: room.id,
|
|
1120
|
+
createdAt,
|
|
1121
|
+
type: "comment",
|
|
1122
|
+
userId: getCurrentUserId(room),
|
|
1123
|
+
body,
|
|
1124
|
+
reactions: []
|
|
1125
|
+
};
|
|
1126
|
+
const newThread = {
|
|
1127
|
+
id: threadId,
|
|
1128
|
+
type: "thread",
|
|
1129
|
+
createdAt,
|
|
1130
|
+
updatedAt: createdAt,
|
|
1131
|
+
roomId: room.id,
|
|
1132
|
+
metadata,
|
|
1133
|
+
comments: [newComment]
|
|
1134
|
+
};
|
|
1135
|
+
const optimisticUpdateId = nanoid();
|
|
1136
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1137
|
+
store.pushOptimisticUpdate({
|
|
1138
|
+
type: "create-thread",
|
|
1139
|
+
thread: newThread,
|
|
1140
|
+
id: optimisticUpdateId,
|
|
1141
|
+
roomId: room.id
|
|
863
1142
|
});
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
updates.deletedInboxNotifications
|
|
1143
|
+
onCreateThread?.(newThread.id);
|
|
1144
|
+
const commentsAPI = room[kInternal].comments;
|
|
1145
|
+
commentsAPI.createThread({ threadId, commentId, body, metadata }).then(
|
|
1146
|
+
(thread) => {
|
|
1147
|
+
store.set((state) => ({
|
|
1148
|
+
...state,
|
|
1149
|
+
threads: {
|
|
1150
|
+
...state.threads,
|
|
1151
|
+
[threadId]: thread
|
|
1152
|
+
},
|
|
1153
|
+
optimisticUpdates: state.optimisticUpdates.filter(
|
|
1154
|
+
(update) => update.id !== optimisticUpdateId
|
|
1155
|
+
)
|
|
1156
|
+
}));
|
|
1157
|
+
},
|
|
1158
|
+
(err) => onMutationFailure(
|
|
1159
|
+
err,
|
|
1160
|
+
optimisticUpdateId,
|
|
1161
|
+
(err2) => new CreateThreadError(err2, {
|
|
1162
|
+
roomId: room.id,
|
|
1163
|
+
threadId,
|
|
1164
|
+
commentId,
|
|
1165
|
+
body,
|
|
1166
|
+
metadata
|
|
1167
|
+
})
|
|
1168
|
+
)
|
|
891
1169
|
);
|
|
892
|
-
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
(state2) => {
|
|
987
|
-
return {
|
|
988
|
-
threads: selectedThreads(room.id, state2, options2),
|
|
989
|
-
isLoading: false
|
|
990
|
-
};
|
|
991
|
-
},
|
|
992
|
-
[room, queryKey]
|
|
993
|
-
// eslint-disable-line react-hooks/exhaustive-deps
|
|
994
|
-
);
|
|
995
|
-
React2.useEffect(() => {
|
|
996
|
-
incrementQuerySubscribers(queryKey);
|
|
997
|
-
return () => {
|
|
998
|
-
decrementQuerySubscribers(queryKey);
|
|
1170
|
+
return newThread;
|
|
1171
|
+
},
|
|
1172
|
+
[client, room, onCreateThread]
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
function useEditThreadMetadata() {
|
|
1176
|
+
const client = useClient();
|
|
1177
|
+
const room = useRoom();
|
|
1178
|
+
return React3.useCallback(
|
|
1179
|
+
(options) => {
|
|
1180
|
+
if (!("metadata" in options)) {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
const threadId = options.threadId;
|
|
1184
|
+
const metadata = options.metadata;
|
|
1185
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
1186
|
+
const optimisticUpdateId = nanoid();
|
|
1187
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1188
|
+
store.pushOptimisticUpdate({
|
|
1189
|
+
type: "edit-thread-metadata",
|
|
1190
|
+
metadata,
|
|
1191
|
+
id: optimisticUpdateId,
|
|
1192
|
+
threadId,
|
|
1193
|
+
updatedAt
|
|
1194
|
+
});
|
|
1195
|
+
const commentsAPI = room[kInternal].comments;
|
|
1196
|
+
commentsAPI.editThreadMetadata({ metadata, threadId }).then(
|
|
1197
|
+
(metadata2) => {
|
|
1198
|
+
store.set((state) => {
|
|
1199
|
+
const existingThread = state.threads[threadId];
|
|
1200
|
+
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1201
|
+
(update) => update.id !== optimisticUpdateId
|
|
1202
|
+
);
|
|
1203
|
+
if (existingThread === void 0) {
|
|
1204
|
+
return {
|
|
1205
|
+
...state,
|
|
1206
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
if (existingThread.deletedAt !== void 0) {
|
|
1210
|
+
return {
|
|
1211
|
+
...state,
|
|
1212
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
if (existingThread.updatedAt && existingThread.updatedAt > updatedAt) {
|
|
1216
|
+
return {
|
|
1217
|
+
...state,
|
|
1218
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
...state,
|
|
1223
|
+
threads: {
|
|
1224
|
+
...state.threads,
|
|
1225
|
+
[threadId]: {
|
|
1226
|
+
...existingThread,
|
|
1227
|
+
metadata: metadata2
|
|
1228
|
+
}
|
|
1229
|
+
},
|
|
1230
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1231
|
+
};
|
|
1232
|
+
});
|
|
1233
|
+
},
|
|
1234
|
+
(err) => onMutationFailure(
|
|
1235
|
+
err,
|
|
1236
|
+
optimisticUpdateId,
|
|
1237
|
+
(error) => new EditThreadMetadataError(error, {
|
|
1238
|
+
roomId: room.id,
|
|
1239
|
+
threadId,
|
|
1240
|
+
metadata
|
|
1241
|
+
})
|
|
1242
|
+
)
|
|
1243
|
+
);
|
|
1244
|
+
},
|
|
1245
|
+
[client, room]
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1248
|
+
function useCreateComment() {
|
|
1249
|
+
const client = useClient();
|
|
1250
|
+
const room = useRoom();
|
|
1251
|
+
return React3.useCallback(
|
|
1252
|
+
({ threadId, body }) => {
|
|
1253
|
+
const commentId = client[kInternal].comments.createCommentId();
|
|
1254
|
+
const createdAt = /* @__PURE__ */ new Date();
|
|
1255
|
+
const comment = {
|
|
1256
|
+
id: commentId,
|
|
1257
|
+
threadId,
|
|
1258
|
+
roomId: room.id,
|
|
1259
|
+
type: "comment",
|
|
1260
|
+
createdAt,
|
|
1261
|
+
userId: getCurrentUserId(room),
|
|
1262
|
+
body,
|
|
1263
|
+
reactions: []
|
|
999
1264
|
};
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
store.
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
};
|
|
1035
|
-
const newThread = {
|
|
1036
|
-
id: threadId,
|
|
1037
|
-
type: "thread",
|
|
1038
|
-
createdAt,
|
|
1039
|
-
updatedAt: createdAt,
|
|
1040
|
-
roomId: room.id,
|
|
1041
|
-
metadata,
|
|
1042
|
-
comments: [newComment]
|
|
1043
|
-
};
|
|
1044
|
-
const optimisticUpdateId = nanoid2();
|
|
1045
|
-
store.pushOptimisticUpdate({
|
|
1046
|
-
type: "create-thread",
|
|
1047
|
-
thread: newThread,
|
|
1048
|
-
id: optimisticUpdateId
|
|
1049
|
-
});
|
|
1050
|
-
room[kInternal].comments.createThread({ threadId, commentId, body, metadata }).then(
|
|
1051
|
-
(thread) => {
|
|
1052
|
-
store.set((state) => ({
|
|
1265
|
+
const optimisticUpdateId = nanoid();
|
|
1266
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1267
|
+
store.pushOptimisticUpdate({
|
|
1268
|
+
type: "create-comment",
|
|
1269
|
+
comment,
|
|
1270
|
+
id: optimisticUpdateId
|
|
1271
|
+
});
|
|
1272
|
+
room[kInternal].comments.createComment({ threadId, commentId, body }).then(
|
|
1273
|
+
(newComment) => {
|
|
1274
|
+
store.set((state) => {
|
|
1275
|
+
const existingThread = state.threads[threadId];
|
|
1276
|
+
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1277
|
+
(update) => update.id !== optimisticUpdateId
|
|
1278
|
+
);
|
|
1279
|
+
if (existingThread === void 0) {
|
|
1280
|
+
return {
|
|
1281
|
+
...state,
|
|
1282
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
const inboxNotification = Object.values(
|
|
1286
|
+
state.inboxNotifications
|
|
1287
|
+
).find(
|
|
1288
|
+
(notification) => notification.kind === "thread" && notification.threadId === threadId
|
|
1289
|
+
);
|
|
1290
|
+
const updatedInboxNotifications = inboxNotification !== void 0 ? {
|
|
1291
|
+
...state.inboxNotifications,
|
|
1292
|
+
[inboxNotification.id]: {
|
|
1293
|
+
...inboxNotification,
|
|
1294
|
+
notifiedAt: newComment.createdAt,
|
|
1295
|
+
readAt: newComment.createdAt
|
|
1296
|
+
}
|
|
1297
|
+
} : state.inboxNotifications;
|
|
1298
|
+
return {
|
|
1053
1299
|
...state,
|
|
1054
1300
|
threads: {
|
|
1055
1301
|
...state.threads,
|
|
1056
|
-
[threadId]:
|
|
1302
|
+
[threadId]: upsertComment(existingThread, newComment)
|
|
1303
|
+
// Upsert the new comment into the thread comments list (if applicable)
|
|
1057
1304
|
},
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1305
|
+
inboxNotifications: updatedInboxNotifications,
|
|
1306
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1307
|
+
};
|
|
1308
|
+
});
|
|
1309
|
+
},
|
|
1310
|
+
(err) => onMutationFailure(
|
|
1311
|
+
err,
|
|
1312
|
+
optimisticUpdateId,
|
|
1313
|
+
(err2) => new CreateCommentError(err2, {
|
|
1314
|
+
roomId: room.id,
|
|
1315
|
+
threadId,
|
|
1316
|
+
commentId,
|
|
1317
|
+
body
|
|
1318
|
+
})
|
|
1319
|
+
)
|
|
1320
|
+
);
|
|
1321
|
+
return comment;
|
|
1322
|
+
},
|
|
1323
|
+
[client, room]
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
function useEditComment() {
|
|
1327
|
+
const client = useClient();
|
|
1328
|
+
const room = useRoom();
|
|
1329
|
+
return React3.useCallback(
|
|
1330
|
+
({ threadId, commentId, body }) => {
|
|
1331
|
+
const editedAt = /* @__PURE__ */ new Date();
|
|
1332
|
+
const optimisticUpdateId = nanoid();
|
|
1333
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1334
|
+
const thread = store.get().threads[threadId];
|
|
1335
|
+
if (thread === void 0) {
|
|
1336
|
+
console2.warn(
|
|
1337
|
+
`Internal unexpected behavior. Cannot edit comment in thread "${threadId}" because the thread does not exist in the cache.`
|
|
1074
1338
|
);
|
|
1075
|
-
return
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
(update) => update.id !== optimisticUpdateId
|
|
1104
|
-
);
|
|
1105
|
-
if (existingThread === void 0) {
|
|
1106
|
-
return {
|
|
1107
|
-
...state,
|
|
1108
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1109
|
-
};
|
|
1110
|
-
}
|
|
1111
|
-
if (existingThread.deletedAt !== void 0) {
|
|
1112
|
-
return {
|
|
1113
|
-
...state,
|
|
1114
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1115
|
-
};
|
|
1116
|
-
}
|
|
1117
|
-
if (existingThread.updatedAt && existingThread.updatedAt > updatedAt) {
|
|
1118
|
-
return {
|
|
1119
|
-
...state,
|
|
1120
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
const comment = thread.comments.find(
|
|
1342
|
+
(comment2) => comment2.id === commentId
|
|
1343
|
+
);
|
|
1344
|
+
if (comment === void 0 || comment.deletedAt !== void 0) {
|
|
1345
|
+
console2.warn(
|
|
1346
|
+
`Internal unexpected behavior. Cannot edit comment "${commentId}" in thread "${threadId}" because the comment does not exist in the cache.`
|
|
1347
|
+
);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
store.pushOptimisticUpdate({
|
|
1351
|
+
type: "edit-comment",
|
|
1352
|
+
comment: {
|
|
1353
|
+
...comment,
|
|
1354
|
+
editedAt,
|
|
1355
|
+
body
|
|
1356
|
+
},
|
|
1357
|
+
id: optimisticUpdateId
|
|
1358
|
+
});
|
|
1359
|
+
room[kInternal].comments.editComment({ threadId, commentId, body }).then(
|
|
1360
|
+
(editedComment) => {
|
|
1361
|
+
store.set((state) => {
|
|
1362
|
+
const existingThread = state.threads[threadId];
|
|
1363
|
+
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1364
|
+
(update) => update.id !== optimisticUpdateId
|
|
1365
|
+
);
|
|
1366
|
+
if (existingThread === void 0) {
|
|
1123
1367
|
return {
|
|
1124
1368
|
...state,
|
|
1125
|
-
threads: {
|
|
1126
|
-
...state.threads,
|
|
1127
|
-
[threadId]: {
|
|
1128
|
-
...existingThread,
|
|
1129
|
-
metadata: metadata2
|
|
1130
|
-
}
|
|
1131
|
-
},
|
|
1132
1369
|
optimisticUpdates: updatedOptimisticUpdates
|
|
1133
1370
|
};
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
}
|
|
1144
|
-
)
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1371
|
+
}
|
|
1372
|
+
return {
|
|
1373
|
+
...state,
|
|
1374
|
+
threads: {
|
|
1375
|
+
...state.threads,
|
|
1376
|
+
[threadId]: upsertComment(existingThread, editedComment)
|
|
1377
|
+
// Upsert the edited comment into the thread comments list (if applicable)
|
|
1378
|
+
},
|
|
1379
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1380
|
+
};
|
|
1381
|
+
});
|
|
1382
|
+
},
|
|
1383
|
+
(err) => onMutationFailure(
|
|
1384
|
+
err,
|
|
1385
|
+
optimisticUpdateId,
|
|
1386
|
+
(error) => new EditCommentError(error, {
|
|
1387
|
+
roomId: room.id,
|
|
1388
|
+
threadId,
|
|
1389
|
+
commentId,
|
|
1390
|
+
body
|
|
1391
|
+
})
|
|
1392
|
+
)
|
|
1393
|
+
);
|
|
1394
|
+
},
|
|
1395
|
+
[client, room]
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
function useDeleteComment() {
|
|
1399
|
+
const client = useClient();
|
|
1400
|
+
const room = useRoom();
|
|
1401
|
+
const onDeleteThread = useThreadDeleteCallback();
|
|
1402
|
+
return React3.useCallback(
|
|
1403
|
+
({ threadId, commentId }) => {
|
|
1404
|
+
const deletedAt = /* @__PURE__ */ new Date();
|
|
1405
|
+
const optimisticUpdateId = nanoid();
|
|
1406
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1407
|
+
store.pushOptimisticUpdate({
|
|
1408
|
+
type: "delete-comment",
|
|
1409
|
+
threadId,
|
|
1410
|
+
commentId,
|
|
1411
|
+
deletedAt,
|
|
1412
|
+
id: optimisticUpdateId,
|
|
1413
|
+
roomId: room.id
|
|
1414
|
+
});
|
|
1415
|
+
const thread = store.get().threads[threadId];
|
|
1416
|
+
if (thread !== void 0 && thread.deletedAt === void 0) {
|
|
1417
|
+
const newThread = deleteComment(thread, commentId, deletedAt);
|
|
1418
|
+
if (newThread.deletedAt !== void 0) {
|
|
1419
|
+
onDeleteThread?.(threadId);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
room[kInternal].comments.deleteComment({ threadId, commentId }).then(
|
|
1423
|
+
() => {
|
|
1424
|
+
store.set((state) => {
|
|
1425
|
+
const existingThread = state.threads[threadId];
|
|
1426
|
+
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1427
|
+
(update) => update.id !== optimisticUpdateId
|
|
1428
|
+
);
|
|
1429
|
+
if (existingThread === void 0) {
|
|
1181
1430
|
return {
|
|
1182
1431
|
...state,
|
|
1183
|
-
threads: {
|
|
1184
|
-
...state.threads,
|
|
1185
|
-
[threadId]: addReaction(
|
|
1186
|
-
existingThread,
|
|
1187
|
-
commentId,
|
|
1188
|
-
addedReaction
|
|
1189
|
-
)
|
|
1190
|
-
},
|
|
1191
1432
|
optimisticUpdates: updatedOptimisticUpdates
|
|
1192
1433
|
};
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1434
|
+
}
|
|
1435
|
+
return {
|
|
1436
|
+
...state,
|
|
1437
|
+
threads: {
|
|
1438
|
+
...state.threads,
|
|
1439
|
+
[threadId]: deleteComment(existingThread, commentId, deletedAt)
|
|
1440
|
+
},
|
|
1441
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1442
|
+
};
|
|
1443
|
+
});
|
|
1444
|
+
},
|
|
1445
|
+
(err) => onMutationFailure(
|
|
1446
|
+
err,
|
|
1447
|
+
optimisticUpdateId,
|
|
1448
|
+
(error) => new DeleteCommentError(error, {
|
|
1449
|
+
roomId: room.id,
|
|
1450
|
+
threadId,
|
|
1451
|
+
commentId
|
|
1452
|
+
})
|
|
1453
|
+
)
|
|
1454
|
+
);
|
|
1455
|
+
},
|
|
1456
|
+
[client, room, onDeleteThread]
|
|
1457
|
+
);
|
|
1458
|
+
}
|
|
1459
|
+
function useAddReaction() {
|
|
1460
|
+
const client = useClient();
|
|
1461
|
+
const room = useRoom();
|
|
1462
|
+
return React3.useCallback(
|
|
1463
|
+
({ threadId, commentId, emoji }) => {
|
|
1464
|
+
const createdAt = /* @__PURE__ */ new Date();
|
|
1465
|
+
const userId = getCurrentUserId(room);
|
|
1466
|
+
const optimisticUpdateId = nanoid();
|
|
1467
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1468
|
+
store.pushOptimisticUpdate({
|
|
1469
|
+
type: "add-reaction",
|
|
1470
|
+
threadId,
|
|
1471
|
+
commentId,
|
|
1472
|
+
reaction: {
|
|
1221
1473
|
emoji,
|
|
1222
1474
|
userId,
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
)
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
...state,
|
|
1236
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1237
|
-
};
|
|
1238
|
-
}
|
|
1475
|
+
createdAt
|
|
1476
|
+
},
|
|
1477
|
+
id: optimisticUpdateId
|
|
1478
|
+
});
|
|
1479
|
+
room[kInternal].comments.addReaction({ threadId, commentId, emoji }).then(
|
|
1480
|
+
(addedReaction) => {
|
|
1481
|
+
store.set((state) => {
|
|
1482
|
+
const existingThread = state.threads[threadId];
|
|
1483
|
+
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1484
|
+
(update) => update.id !== optimisticUpdateId
|
|
1485
|
+
);
|
|
1486
|
+
if (existingThread === void 0) {
|
|
1239
1487
|
return {
|
|
1240
1488
|
...state,
|
|
1241
|
-
threads: {
|
|
1242
|
-
...state.threads,
|
|
1243
|
-
[threadId]: removeReaction(
|
|
1244
|
-
existingThread,
|
|
1245
|
-
commentId,
|
|
1246
|
-
emoji,
|
|
1247
|
-
userId,
|
|
1248
|
-
removedAt
|
|
1249
|
-
)
|
|
1250
|
-
},
|
|
1251
1489
|
optimisticUpdates: updatedOptimisticUpdates
|
|
1252
1490
|
};
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
...state.inboxNotifications,
|
|
1310
|
-
[inboxNotification.id]: {
|
|
1311
|
-
...inboxNotification,
|
|
1312
|
-
notifiedAt: newComment.createdAt,
|
|
1313
|
-
readAt: newComment.createdAt
|
|
1314
|
-
}
|
|
1315
|
-
} : state.inboxNotifications;
|
|
1491
|
+
}
|
|
1492
|
+
return {
|
|
1493
|
+
...state,
|
|
1494
|
+
threads: {
|
|
1495
|
+
...state.threads,
|
|
1496
|
+
[threadId]: addReaction(
|
|
1497
|
+
existingThread,
|
|
1498
|
+
commentId,
|
|
1499
|
+
addedReaction
|
|
1500
|
+
)
|
|
1501
|
+
},
|
|
1502
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1503
|
+
};
|
|
1504
|
+
});
|
|
1505
|
+
},
|
|
1506
|
+
(err) => onMutationFailure(
|
|
1507
|
+
err,
|
|
1508
|
+
optimisticUpdateId,
|
|
1509
|
+
(error) => new AddReactionError(error, {
|
|
1510
|
+
roomId: room.id,
|
|
1511
|
+
threadId,
|
|
1512
|
+
commentId,
|
|
1513
|
+
emoji
|
|
1514
|
+
})
|
|
1515
|
+
)
|
|
1516
|
+
);
|
|
1517
|
+
},
|
|
1518
|
+
[client, room]
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
function useRemoveReaction() {
|
|
1522
|
+
const client = useClient();
|
|
1523
|
+
const room = useRoom();
|
|
1524
|
+
return React3.useCallback(
|
|
1525
|
+
({ threadId, commentId, emoji }) => {
|
|
1526
|
+
const userId = getCurrentUserId(room);
|
|
1527
|
+
const removedAt = /* @__PURE__ */ new Date();
|
|
1528
|
+
const optimisticUpdateId = nanoid();
|
|
1529
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1530
|
+
store.pushOptimisticUpdate({
|
|
1531
|
+
type: "remove-reaction",
|
|
1532
|
+
threadId,
|
|
1533
|
+
commentId,
|
|
1534
|
+
emoji,
|
|
1535
|
+
userId,
|
|
1536
|
+
removedAt,
|
|
1537
|
+
id: optimisticUpdateId
|
|
1538
|
+
});
|
|
1539
|
+
room[kInternal].comments.removeReaction({ threadId, commentId, emoji }).then(
|
|
1540
|
+
() => {
|
|
1541
|
+
store.set((state) => {
|
|
1542
|
+
const existingThread = state.threads[threadId];
|
|
1543
|
+
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1544
|
+
(update) => update.id !== optimisticUpdateId
|
|
1545
|
+
);
|
|
1546
|
+
if (existingThread === void 0) {
|
|
1316
1547
|
return {
|
|
1317
1548
|
...state,
|
|
1318
|
-
threads: {
|
|
1319
|
-
...state.threads,
|
|
1320
|
-
[threadId]: upsertComment(existingThread, newComment)
|
|
1321
|
-
// Upsert the new comment into the thread comments list (if applicable)
|
|
1322
|
-
},
|
|
1323
|
-
inboxNotifications: updatedInboxNotifications,
|
|
1324
1549
|
optimisticUpdates: updatedOptimisticUpdates
|
|
1325
1550
|
};
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1551
|
+
}
|
|
1552
|
+
return {
|
|
1553
|
+
...state,
|
|
1554
|
+
threads: {
|
|
1555
|
+
...state.threads,
|
|
1556
|
+
[threadId]: removeReaction(
|
|
1557
|
+
existingThread,
|
|
1558
|
+
commentId,
|
|
1559
|
+
emoji,
|
|
1560
|
+
userId,
|
|
1561
|
+
removedAt
|
|
1562
|
+
)
|
|
1563
|
+
},
|
|
1564
|
+
optimisticUpdates: updatedOptimisticUpdates
|
|
1565
|
+
};
|
|
1566
|
+
});
|
|
1567
|
+
},
|
|
1568
|
+
(err) => onMutationFailure(
|
|
1569
|
+
err,
|
|
1570
|
+
optimisticUpdateId,
|
|
1571
|
+
(error) => new RemoveReactionError(error, {
|
|
1572
|
+
roomId: room.id,
|
|
1573
|
+
threadId,
|
|
1574
|
+
commentId,
|
|
1575
|
+
emoji
|
|
1576
|
+
})
|
|
1577
|
+
)
|
|
1578
|
+
);
|
|
1579
|
+
},
|
|
1580
|
+
[client, room]
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
function useMarkThreadAsRead() {
|
|
1584
|
+
const client = useClient();
|
|
1585
|
+
const room = useRoom();
|
|
1586
|
+
return React3.useCallback(
|
|
1587
|
+
(threadId) => {
|
|
1588
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1589
|
+
const inboxNotification = Object.values(
|
|
1590
|
+
store.get().inboxNotifications
|
|
1591
|
+
).find(
|
|
1592
|
+
(inboxNotification2) => inboxNotification2.kind === "thread" && inboxNotification2.threadId === threadId
|
|
1593
|
+
);
|
|
1594
|
+
if (!inboxNotification)
|
|
1595
|
+
return;
|
|
1596
|
+
const optimisticUpdateId = nanoid();
|
|
1597
|
+
const now = /* @__PURE__ */ new Date();
|
|
1598
|
+
store.pushOptimisticUpdate({
|
|
1599
|
+
type: "mark-inbox-notification-as-read",
|
|
1600
|
+
id: optimisticUpdateId,
|
|
1601
|
+
inboxNotificationId: inboxNotification.id,
|
|
1602
|
+
readAt: now
|
|
1603
|
+
});
|
|
1604
|
+
room[kInternal].notifications.markInboxNotificationAsRead(inboxNotification.id).then(
|
|
1605
|
+
() => {
|
|
1606
|
+
store.set((state) => ({
|
|
1607
|
+
...state,
|
|
1608
|
+
inboxNotifications: {
|
|
1609
|
+
...state.inboxNotifications,
|
|
1610
|
+
[inboxNotification.id]: {
|
|
1611
|
+
...inboxNotification,
|
|
1612
|
+
readAt: now
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
optimisticUpdates: state.optimisticUpdates.filter(
|
|
1616
|
+
(update) => update.id !== optimisticUpdateId
|
|
1617
|
+
)
|
|
1618
|
+
}));
|
|
1619
|
+
},
|
|
1620
|
+
(err) => {
|
|
1621
|
+
onMutationFailure(
|
|
1329
1622
|
err,
|
|
1330
1623
|
optimisticUpdateId,
|
|
1331
|
-
(
|
|
1332
|
-
|
|
1333
|
-
threadId,
|
|
1334
|
-
commentId,
|
|
1335
|
-
body
|
|
1624
|
+
(error) => new MarkInboxNotificationAsReadError(error, {
|
|
1625
|
+
inboxNotificationId: inboxNotification.id
|
|
1336
1626
|
})
|
|
1337
|
-
)
|
|
1338
|
-
);
|
|
1339
|
-
return comment;
|
|
1340
|
-
},
|
|
1341
|
-
[room]
|
|
1342
|
-
);
|
|
1343
|
-
}
|
|
1344
|
-
function useEditComment() {
|
|
1345
|
-
const room = useRoom();
|
|
1346
|
-
return React2.useCallback(
|
|
1347
|
-
({ threadId, commentId, body }) => {
|
|
1348
|
-
const editedAt = /* @__PURE__ */ new Date();
|
|
1349
|
-
const optimisticUpdateId = nanoid2();
|
|
1350
|
-
const thread = store.get().threads[threadId];
|
|
1351
|
-
if (thread === void 0) {
|
|
1352
|
-
console2.warn(
|
|
1353
|
-
`Internal unexpected behavior. Cannot edit comment in thread "${threadId}" because the thread does not exist in the cache.`
|
|
1354
1627
|
);
|
|
1355
1628
|
return;
|
|
1356
1629
|
}
|
|
1357
|
-
const comment = thread.comments.find(
|
|
1358
|
-
(comment2) => comment2.id === commentId
|
|
1359
|
-
);
|
|
1360
|
-
if (comment === void 0 || comment.deletedAt !== void 0) {
|
|
1361
|
-
console2.warn(
|
|
1362
|
-
`Internal unexpected behavior. Cannot edit comment "${commentId}" in thread "${threadId}" because the comment does not exist in the cache.`
|
|
1363
|
-
);
|
|
1364
|
-
return;
|
|
1365
|
-
}
|
|
1366
|
-
store.pushOptimisticUpdate({
|
|
1367
|
-
type: "edit-comment",
|
|
1368
|
-
comment: {
|
|
1369
|
-
...comment,
|
|
1370
|
-
editedAt,
|
|
1371
|
-
body
|
|
1372
|
-
},
|
|
1373
|
-
id: optimisticUpdateId
|
|
1374
|
-
});
|
|
1375
|
-
room[kInternal].comments.editComment({ threadId, commentId, body }).then(
|
|
1376
|
-
(editedComment) => {
|
|
1377
|
-
store.set((state) => {
|
|
1378
|
-
const existingThread = state.threads[threadId];
|
|
1379
|
-
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1380
|
-
(update) => update.id !== optimisticUpdateId
|
|
1381
|
-
);
|
|
1382
|
-
if (existingThread === void 0) {
|
|
1383
|
-
return {
|
|
1384
|
-
...state,
|
|
1385
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1386
|
-
};
|
|
1387
|
-
}
|
|
1388
|
-
return {
|
|
1389
|
-
...state,
|
|
1390
|
-
threads: {
|
|
1391
|
-
...state.threads,
|
|
1392
|
-
[threadId]: upsertComment(existingThread, editedComment)
|
|
1393
|
-
// Upsert the edited comment into the thread comments list (if applicable)
|
|
1394
|
-
},
|
|
1395
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1396
|
-
};
|
|
1397
|
-
});
|
|
1398
|
-
},
|
|
1399
|
-
(err) => onMutationFailure(
|
|
1400
|
-
err,
|
|
1401
|
-
optimisticUpdateId,
|
|
1402
|
-
(error) => new EditCommentError(error, {
|
|
1403
|
-
roomId: room.id,
|
|
1404
|
-
threadId,
|
|
1405
|
-
commentId,
|
|
1406
|
-
body
|
|
1407
|
-
})
|
|
1408
|
-
)
|
|
1409
|
-
);
|
|
1410
|
-
},
|
|
1411
|
-
[room]
|
|
1412
|
-
);
|
|
1413
|
-
}
|
|
1414
|
-
function useDeleteComment() {
|
|
1415
|
-
const room = useRoom();
|
|
1416
|
-
return React2.useCallback(
|
|
1417
|
-
({ threadId, commentId }) => {
|
|
1418
|
-
const deletedAt = /* @__PURE__ */ new Date();
|
|
1419
|
-
const optimisticUpdateId = nanoid2();
|
|
1420
|
-
store.pushOptimisticUpdate({
|
|
1421
|
-
type: "delete-comment",
|
|
1422
|
-
threadId,
|
|
1423
|
-
commentId,
|
|
1424
|
-
deletedAt,
|
|
1425
|
-
id: optimisticUpdateId
|
|
1426
|
-
});
|
|
1427
|
-
room[kInternal].comments.deleteComment({ threadId, commentId }).then(
|
|
1428
|
-
() => {
|
|
1429
|
-
store.set((state) => {
|
|
1430
|
-
const existingThread = state.threads[threadId];
|
|
1431
|
-
const updatedOptimisticUpdates = state.optimisticUpdates.filter(
|
|
1432
|
-
(update) => update.id !== optimisticUpdateId
|
|
1433
|
-
);
|
|
1434
|
-
if (existingThread === void 0) {
|
|
1435
|
-
return {
|
|
1436
|
-
...state,
|
|
1437
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1438
|
-
};
|
|
1439
|
-
}
|
|
1440
|
-
return {
|
|
1441
|
-
...state,
|
|
1442
|
-
threads: {
|
|
1443
|
-
...state.threads,
|
|
1444
|
-
[threadId]: deleteComment(
|
|
1445
|
-
existingThread,
|
|
1446
|
-
commentId,
|
|
1447
|
-
deletedAt
|
|
1448
|
-
)
|
|
1449
|
-
},
|
|
1450
|
-
optimisticUpdates: updatedOptimisticUpdates
|
|
1451
|
-
};
|
|
1452
|
-
});
|
|
1453
|
-
},
|
|
1454
|
-
(err) => onMutationFailure(
|
|
1455
|
-
err,
|
|
1456
|
-
optimisticUpdateId,
|
|
1457
|
-
(error) => new DeleteCommentError(error, {
|
|
1458
|
-
roomId: room.id,
|
|
1459
|
-
threadId,
|
|
1460
|
-
commentId
|
|
1461
|
-
})
|
|
1462
|
-
)
|
|
1463
|
-
);
|
|
1464
|
-
},
|
|
1465
|
-
[room]
|
|
1466
|
-
);
|
|
1467
|
-
}
|
|
1468
|
-
const resolveMentionSuggestions = client[kInternal].resolveMentionSuggestions;
|
|
1469
|
-
const mentionSuggestionsCache = /* @__PURE__ */ new Map();
|
|
1470
|
-
function useMentionSuggestions(search) {
|
|
1471
|
-
const room = useRoom();
|
|
1472
|
-
const [mentionSuggestions, setMentionSuggestions] = React2.useState();
|
|
1473
|
-
const lastInvokedAt = React2.useRef();
|
|
1474
|
-
React2.useEffect(() => {
|
|
1475
|
-
if (search === void 0 || !resolveMentionSuggestions) {
|
|
1476
|
-
return;
|
|
1477
|
-
}
|
|
1478
|
-
const resolveMentionSuggestionsArgs = { text: search, roomId: room.id };
|
|
1479
|
-
const mentionSuggestionsCacheKey = stringify(
|
|
1480
|
-
resolveMentionSuggestionsArgs
|
|
1481
1630
|
);
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
}
|
|
1497
|
-
} catch (error) {
|
|
1498
|
-
console2.error(error?.message);
|
|
1499
|
-
}
|
|
1500
|
-
};
|
|
1501
|
-
if (mentionSuggestionsCache.has(mentionSuggestionsCacheKey)) {
|
|
1502
|
-
setMentionSuggestions(
|
|
1503
|
-
mentionSuggestionsCache.get(mentionSuggestionsCacheKey)
|
|
1504
|
-
);
|
|
1505
|
-
} else if (!lastInvokedAt.current || Math.abs(performance.now() - lastInvokedAt.current) > MENTION_SUGGESTIONS_DEBOUNCE) {
|
|
1506
|
-
void getMentionSuggestions();
|
|
1507
|
-
} else {
|
|
1508
|
-
debounceTimeout = window.setTimeout(() => {
|
|
1509
|
-
void getMentionSuggestions();
|
|
1510
|
-
}, MENTION_SUGGESTIONS_DEBOUNCE);
|
|
1511
|
-
}
|
|
1512
|
-
return () => {
|
|
1513
|
-
isCanceled = true;
|
|
1514
|
-
window.clearTimeout(debounceTimeout);
|
|
1515
|
-
};
|
|
1516
|
-
}, [room.id, search]);
|
|
1517
|
-
return mentionSuggestions;
|
|
1518
|
-
}
|
|
1519
|
-
function useThreadSubscription(threadId) {
|
|
1520
|
-
const selector = React2.useCallback(
|
|
1521
|
-
(state) => {
|
|
1522
|
-
const inboxNotification = selectedInboxNotifications(state).find(
|
|
1523
|
-
(inboxNotification2) => inboxNotification2.threadId === threadId
|
|
1524
|
-
);
|
|
1525
|
-
const thread = state.threads[threadId];
|
|
1526
|
-
if (inboxNotification === void 0 || thread === void 0) {
|
|
1527
|
-
return {
|
|
1528
|
-
status: "not-subscribed"
|
|
1529
|
-
};
|
|
1530
|
-
}
|
|
1631
|
+
},
|
|
1632
|
+
[client, room]
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
function useThreadSubscription(threadId) {
|
|
1636
|
+
const client = useClient();
|
|
1637
|
+
const { store } = getExtrasForClient(client);
|
|
1638
|
+
const selector = React3.useCallback(
|
|
1639
|
+
(state) => {
|
|
1640
|
+
const inboxNotification = client[kInternal].comments.selectedInboxNotifications(state).find(
|
|
1641
|
+
(inboxNotification2) => inboxNotification2.kind === "thread" && inboxNotification2.threadId === threadId
|
|
1642
|
+
);
|
|
1643
|
+
const thread = state.threads[threadId];
|
|
1644
|
+
if (inboxNotification === void 0 || thread === void 0) {
|
|
1531
1645
|
return {
|
|
1532
|
-
status: "subscribed"
|
|
1533
|
-
unreadSince: inboxNotification.readAt
|
|
1646
|
+
status: "not-subscribed"
|
|
1534
1647
|
};
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
readAt: now
|
|
1571
|
-
}
|
|
1572
|
-
},
|
|
1573
|
-
optimisticUpdates: state.optimisticUpdates.filter(
|
|
1574
|
-
(update) => update.id !== optimisticUpdateId
|
|
1575
|
-
)
|
|
1576
|
-
}));
|
|
1577
|
-
},
|
|
1578
|
-
(err) => {
|
|
1579
|
-
onMutationFailure(
|
|
1580
|
-
err,
|
|
1581
|
-
optimisticUpdateId,
|
|
1582
|
-
(error) => new MarkInboxNotificationAsReadError(error, {
|
|
1583
|
-
inboxNotificationId: inboxNotification.id
|
|
1584
|
-
})
|
|
1585
|
-
);
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
);
|
|
1589
|
-
},
|
|
1590
|
-
[room]
|
|
1591
|
-
);
|
|
1592
|
-
}
|
|
1593
|
-
function makeNotificationSettingsQueryKey(roomId) {
|
|
1594
|
-
return `${roomId}:NOTIFICATION_SETTINGS`;
|
|
1595
|
-
}
|
|
1596
|
-
async function getInboxNotificationSettings(room, queryKey, { retryCount } = { retryCount: 0 }) {
|
|
1597
|
-
const existingRequest = requestsByQuery.get(queryKey);
|
|
1598
|
-
if (existingRequest !== void 0)
|
|
1599
|
-
return existingRequest;
|
|
1600
|
-
try {
|
|
1601
|
-
const request = room[kInternal].notifications.getRoomNotificationSettings();
|
|
1602
|
-
requestsByQuery.set(queryKey, request);
|
|
1603
|
-
store.setQueryState(queryKey, {
|
|
1604
|
-
isLoading: true
|
|
1605
|
-
});
|
|
1606
|
-
const settings = await request;
|
|
1607
|
-
store.updateRoomInboxNotificationSettings(room.id, settings, queryKey);
|
|
1608
|
-
} catch (err) {
|
|
1609
|
-
requestsByQuery.delete(queryKey);
|
|
1610
|
-
retryError(() => {
|
|
1611
|
-
void getInboxNotificationSettings(room, queryKey, {
|
|
1612
|
-
retryCount: retryCount + 1
|
|
1613
|
-
});
|
|
1614
|
-
}, retryCount);
|
|
1615
|
-
store.setQueryState(queryKey, {
|
|
1648
|
+
}
|
|
1649
|
+
return {
|
|
1650
|
+
status: "subscribed",
|
|
1651
|
+
unreadSince: inboxNotification.readAt
|
|
1652
|
+
};
|
|
1653
|
+
},
|
|
1654
|
+
[threadId]
|
|
1655
|
+
);
|
|
1656
|
+
return useSyncExternalStoreWithSelector(
|
|
1657
|
+
store.subscribe,
|
|
1658
|
+
store.get,
|
|
1659
|
+
store.get,
|
|
1660
|
+
selector
|
|
1661
|
+
);
|
|
1662
|
+
}
|
|
1663
|
+
function useRoomNotificationSettings() {
|
|
1664
|
+
const client = useClient();
|
|
1665
|
+
const room = useRoom();
|
|
1666
|
+
const { store } = getExtrasForClient(client);
|
|
1667
|
+
React3.useEffect(() => {
|
|
1668
|
+
const { getInboxNotificationSettings } = getExtrasForClient(client);
|
|
1669
|
+
const queryKey = makeNotificationSettingsQueryKey(room.id);
|
|
1670
|
+
void getInboxNotificationSettings(room, queryKey);
|
|
1671
|
+
}, [client, room]);
|
|
1672
|
+
const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
|
|
1673
|
+
const selector = React3.useCallback(
|
|
1674
|
+
(state) => {
|
|
1675
|
+
const query = state.queries[makeNotificationSettingsQueryKey(room.id)];
|
|
1676
|
+
if (query === void 0 || query.isLoading) {
|
|
1677
|
+
return { isLoading: true };
|
|
1678
|
+
}
|
|
1679
|
+
if (query.error !== void 0) {
|
|
1680
|
+
return { isLoading: false, error: query.error };
|
|
1681
|
+
}
|
|
1682
|
+
return {
|
|
1616
1683
|
isLoading: false,
|
|
1617
|
-
|
|
1684
|
+
settings: client[kInternal].comments.selectNotificationSettings(
|
|
1685
|
+
room.id,
|
|
1686
|
+
state
|
|
1687
|
+
)
|
|
1688
|
+
};
|
|
1689
|
+
},
|
|
1690
|
+
[room]
|
|
1691
|
+
);
|
|
1692
|
+
const settings = useSyncExternalStoreWithSelector(
|
|
1693
|
+
store.subscribe,
|
|
1694
|
+
store.get,
|
|
1695
|
+
store.get,
|
|
1696
|
+
selector
|
|
1697
|
+
);
|
|
1698
|
+
return React3.useMemo(() => {
|
|
1699
|
+
return [settings, updateRoomNotificationSettings];
|
|
1700
|
+
}, [settings, updateRoomNotificationSettings]);
|
|
1701
|
+
}
|
|
1702
|
+
function useUpdateRoomNotificationSettings() {
|
|
1703
|
+
const client = useClient();
|
|
1704
|
+
const room = useRoom();
|
|
1705
|
+
return React3.useCallback(
|
|
1706
|
+
(settings) => {
|
|
1707
|
+
const optimisticUpdateId = nanoid();
|
|
1708
|
+
const { store, onMutationFailure } = getExtrasForClient(client);
|
|
1709
|
+
store.pushOptimisticUpdate({
|
|
1710
|
+
id: optimisticUpdateId,
|
|
1711
|
+
type: "update-notification-settings",
|
|
1712
|
+
roomId: room.id,
|
|
1713
|
+
settings
|
|
1618
1714
|
});
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
store.get,
|
|
1648
|
-
store.get,
|
|
1649
|
-
selector
|
|
1715
|
+
room[kInternal].notifications.updateRoomNotificationSettings(settings).then(
|
|
1716
|
+
(settings2) => {
|
|
1717
|
+
store.set((state) => ({
|
|
1718
|
+
...state,
|
|
1719
|
+
notificationSettings: {
|
|
1720
|
+
[room.id]: settings2
|
|
1721
|
+
},
|
|
1722
|
+
optimisticUpdates: state.optimisticUpdates.filter(
|
|
1723
|
+
(update) => update.id !== optimisticUpdateId
|
|
1724
|
+
)
|
|
1725
|
+
}));
|
|
1726
|
+
},
|
|
1727
|
+
(err) => onMutationFailure(
|
|
1728
|
+
err,
|
|
1729
|
+
optimisticUpdateId,
|
|
1730
|
+
(error) => new UpdateNotificationSettingsError(error, {
|
|
1731
|
+
roomId: room.id
|
|
1732
|
+
})
|
|
1733
|
+
)
|
|
1734
|
+
);
|
|
1735
|
+
},
|
|
1736
|
+
[client, room]
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
function ensureNotServerSide() {
|
|
1740
|
+
if (typeof window === "undefined") {
|
|
1741
|
+
throw new Error(
|
|
1742
|
+
"You cannot use the Suspense version of this hook on the server side. Make sure to only call them on the client side.\nFor tips, see https://liveblocks.io/docs/api-reference/liveblocks-react#suspense-avoid-ssr"
|
|
1650
1743
|
);
|
|
1651
|
-
return React2.useMemo(() => {
|
|
1652
|
-
return [settings, updateRoomNotificationSettings];
|
|
1653
|
-
}, [settings, updateRoomNotificationSettings]);
|
|
1654
1744
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1745
|
+
}
|
|
1746
|
+
function useSuspendUntilPresenceLoaded() {
|
|
1747
|
+
const room = useRoom();
|
|
1748
|
+
if (room.getSelf() !== null) {
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
ensureNotServerSide();
|
|
1752
|
+
throw new Promise((res) => {
|
|
1753
|
+
room.events.self.subscribeOnce(() => res());
|
|
1754
|
+
room.events.status.subscribeOnce(() => res());
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
function useSelfSuspense(selector, isEqual) {
|
|
1758
|
+
useSuspendUntilPresenceLoaded();
|
|
1759
|
+
return useSelf(
|
|
1760
|
+
selector,
|
|
1761
|
+
isEqual
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
function make_useOthersSuspense() {
|
|
1765
|
+
return function useOthersSuspense(selector, isEqual) {
|
|
1766
|
+
useSuspendUntilPresenceLoaded();
|
|
1767
|
+
return useOthers(
|
|
1768
|
+
selector,
|
|
1769
|
+
isEqual
|
|
1680
1770
|
);
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function useOthersConnectionIdsSuspense() {
|
|
1774
|
+
useSuspendUntilPresenceLoaded();
|
|
1775
|
+
return useOthersConnectionIds();
|
|
1776
|
+
}
|
|
1777
|
+
function make_useOthersMappedSuspense() {
|
|
1778
|
+
const useOthersMapped = make_useOthersMapped();
|
|
1779
|
+
return function(itemSelector, itemIsEqual) {
|
|
1780
|
+
useSuspendUntilPresenceLoaded();
|
|
1781
|
+
return useOthersMapped(itemSelector, itemIsEqual);
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
function make_useOtherSuspense() {
|
|
1785
|
+
const useOther = make_useOther();
|
|
1786
|
+
return function useOtherSuspense(connectionId, selector, isEqual) {
|
|
1787
|
+
useSuspendUntilPresenceLoaded();
|
|
1788
|
+
return useOther(connectionId, selector, isEqual);
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
function useSuspendUntilStorageLoaded() {
|
|
1792
|
+
const room = useRoom();
|
|
1793
|
+
if (room.getStorageSnapshot() !== null) {
|
|
1794
|
+
return;
|
|
1684
1795
|
}
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
(settings2) => {
|
|
1698
|
-
store.set((state) => ({
|
|
1699
|
-
...state,
|
|
1700
|
-
notificationSettings: {
|
|
1701
|
-
[room.id]: settings2
|
|
1702
|
-
},
|
|
1703
|
-
optimisticUpdates: state.optimisticUpdates.filter(
|
|
1704
|
-
(update) => update.id !== optimisticUpdateId
|
|
1705
|
-
)
|
|
1706
|
-
}));
|
|
1707
|
-
},
|
|
1708
|
-
(err) => onMutationFailure(
|
|
1709
|
-
err,
|
|
1710
|
-
optimisticUpdateId,
|
|
1711
|
-
(error) => new UpdateNotificationSettingsError(error, {
|
|
1712
|
-
roomId: room.id
|
|
1713
|
-
})
|
|
1714
|
-
)
|
|
1715
|
-
);
|
|
1716
|
-
},
|
|
1717
|
-
[room]
|
|
1796
|
+
ensureNotServerSide();
|
|
1797
|
+
throw new Promise((res) => {
|
|
1798
|
+
room.events.storageDidLoad.subscribeOnce(() => res());
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
function make_useStorageSuspense() {
|
|
1802
|
+
const useStorage = make_useStorage();
|
|
1803
|
+
return function useStorageSuspense(selector, isEqual) {
|
|
1804
|
+
useSuspendUntilStorageLoaded();
|
|
1805
|
+
return useStorage(
|
|
1806
|
+
selector,
|
|
1807
|
+
isEqual
|
|
1718
1808
|
);
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
function useLegacyKeySuspense(key) {
|
|
1812
|
+
useSuspendUntilStorageLoaded();
|
|
1813
|
+
return useLegacyKey(key);
|
|
1814
|
+
}
|
|
1815
|
+
function useThreadsSuspense(options = {
|
|
1816
|
+
query: { metadata: {} }
|
|
1817
|
+
}) {
|
|
1818
|
+
const { scrollOnLoad = true } = options;
|
|
1819
|
+
const client = useClient();
|
|
1820
|
+
const room = useRoom();
|
|
1821
|
+
const queryKey = React3.useMemo(
|
|
1822
|
+
() => generateQueryKey(room.id, options.query),
|
|
1823
|
+
[room, options]
|
|
1824
|
+
);
|
|
1825
|
+
const { store, getThreadsAndInboxNotifications } = getExtrasForClient(client);
|
|
1826
|
+
const query = store.get().queries[queryKey];
|
|
1827
|
+
if (query === void 0 || query.isLoading) {
|
|
1828
|
+
throw getThreadsAndInboxNotifications(room, queryKey, options);
|
|
1719
1829
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1830
|
+
if (query.error) {
|
|
1831
|
+
throw query.error;
|
|
1722
1832
|
}
|
|
1723
|
-
const
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
useEventListener,
|
|
1734
|
-
useHistory,
|
|
1735
|
-
useUndo,
|
|
1736
|
-
useRedo,
|
|
1737
|
-
useCanRedo,
|
|
1738
|
-
useCanUndo,
|
|
1739
|
-
// These are just aliases. The passed-in key will define their return values.
|
|
1740
|
-
useList: useLegacyKey,
|
|
1741
|
-
useMap: useLegacyKey,
|
|
1742
|
-
useObject: useLegacyKey,
|
|
1743
|
-
useStorageRoot,
|
|
1744
|
-
useStorage,
|
|
1745
|
-
useSelf,
|
|
1746
|
-
useMyPresence,
|
|
1747
|
-
useUpdateMyPresence,
|
|
1748
|
-
useOthers,
|
|
1749
|
-
useOthersMapped,
|
|
1750
|
-
useOthersConnectionIds,
|
|
1751
|
-
useOther,
|
|
1752
|
-
useMutation,
|
|
1753
|
-
useThreads,
|
|
1754
|
-
useCreateThread,
|
|
1755
|
-
useEditThreadMetadata,
|
|
1756
|
-
useCreateComment,
|
|
1757
|
-
useEditComment,
|
|
1758
|
-
useDeleteComment,
|
|
1759
|
-
useAddReaction,
|
|
1760
|
-
useRemoveReaction,
|
|
1761
|
-
useMarkThreadAsRead,
|
|
1762
|
-
useThreadSubscription,
|
|
1763
|
-
useRoomNotificationSettings,
|
|
1764
|
-
useUpdateRoomNotificationSettings,
|
|
1765
|
-
...shared,
|
|
1766
|
-
suspense: {
|
|
1767
|
-
RoomContext,
|
|
1768
|
-
RoomProvider: RoomProviderOuter,
|
|
1769
|
-
useRoom,
|
|
1770
|
-
useStatus,
|
|
1771
|
-
useBatch,
|
|
1772
|
-
useBroadcastEvent,
|
|
1773
|
-
useOthersListener,
|
|
1774
|
-
useLostConnectionListener,
|
|
1775
|
-
useErrorListener,
|
|
1776
|
-
useEventListener,
|
|
1777
|
-
useHistory,
|
|
1778
|
-
useUndo,
|
|
1779
|
-
useRedo,
|
|
1780
|
-
useCanRedo,
|
|
1781
|
-
useCanUndo,
|
|
1782
|
-
// Legacy hooks
|
|
1783
|
-
useList: useLegacyKeySuspense,
|
|
1784
|
-
useMap: useLegacyKeySuspense,
|
|
1785
|
-
useObject: useLegacyKeySuspense,
|
|
1786
|
-
useStorageRoot,
|
|
1787
|
-
useStorage: useStorageSuspense,
|
|
1788
|
-
useSelf: useSelfSuspense,
|
|
1789
|
-
useMyPresence,
|
|
1790
|
-
useUpdateMyPresence,
|
|
1791
|
-
useOthers: useOthersSuspense,
|
|
1792
|
-
useOthersMapped: useOthersMappedSuspense,
|
|
1793
|
-
useOthersConnectionIds: useOthersConnectionIdsSuspense,
|
|
1794
|
-
useOther: useOtherSuspense,
|
|
1795
|
-
useMutation,
|
|
1796
|
-
useThreads: useThreadsSuspense,
|
|
1797
|
-
useCreateThread,
|
|
1798
|
-
useEditThreadMetadata,
|
|
1799
|
-
useCreateComment,
|
|
1800
|
-
useEditComment,
|
|
1801
|
-
useDeleteComment,
|
|
1802
|
-
useAddReaction,
|
|
1803
|
-
useRemoveReaction,
|
|
1804
|
-
useMarkThreadAsRead,
|
|
1805
|
-
useThreadSubscription,
|
|
1806
|
-
useRoomNotificationSettings: useRoomNotificationSettingsSuspense,
|
|
1807
|
-
useUpdateRoomNotificationSettings,
|
|
1808
|
-
...shared.suspense
|
|
1833
|
+
const selector = React3.useCallback(
|
|
1834
|
+
(state2) => {
|
|
1835
|
+
return {
|
|
1836
|
+
threads: client[kInternal].comments.selectedThreads(
|
|
1837
|
+
room.id,
|
|
1838
|
+
state2,
|
|
1839
|
+
options
|
|
1840
|
+
),
|
|
1841
|
+
isLoading: false
|
|
1842
|
+
};
|
|
1809
1843
|
},
|
|
1810
|
-
[
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1844
|
+
[room, queryKey]
|
|
1845
|
+
// eslint-disable-line react-hooks/exhaustive-deps
|
|
1846
|
+
);
|
|
1847
|
+
React3.useEffect(() => {
|
|
1848
|
+
const { incrementQuerySubscribers } = getExtrasForClient(client);
|
|
1849
|
+
return incrementQuerySubscribers(queryKey);
|
|
1850
|
+
}, [client, queryKey]);
|
|
1851
|
+
const state = useSyncExternalStoreWithSelector(
|
|
1852
|
+
store.subscribe,
|
|
1853
|
+
store.get,
|
|
1854
|
+
store.get,
|
|
1855
|
+
selector
|
|
1856
|
+
);
|
|
1857
|
+
useScrollToCommentOnLoadEffect(scrollOnLoad, state);
|
|
1858
|
+
return state;
|
|
1819
1859
|
}
|
|
1820
|
-
function
|
|
1821
|
-
const
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1860
|
+
function useRoomNotificationSettingsSuspense() {
|
|
1861
|
+
const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
|
|
1862
|
+
const client = useClient();
|
|
1863
|
+
const room = useRoom();
|
|
1864
|
+
const queryKey = makeNotificationSettingsQueryKey(room.id);
|
|
1865
|
+
const { store, getInboxNotificationSettings } = getExtrasForClient(client);
|
|
1866
|
+
const query = store.get().queries[queryKey];
|
|
1867
|
+
if (query === void 0 || query.isLoading) {
|
|
1868
|
+
throw getInboxNotificationSettings(room, queryKey);
|
|
1869
|
+
}
|
|
1870
|
+
if (query.error) {
|
|
1871
|
+
throw query.error;
|
|
1872
|
+
}
|
|
1873
|
+
const selector = React3.useCallback(
|
|
1874
|
+
(state) => {
|
|
1875
|
+
return {
|
|
1876
|
+
isLoading: false,
|
|
1877
|
+
settings: client[kInternal].comments.selectNotificationSettings(
|
|
1878
|
+
room.id,
|
|
1879
|
+
state
|
|
1880
|
+
)
|
|
1881
|
+
};
|
|
1882
|
+
},
|
|
1883
|
+
[room]
|
|
1884
|
+
);
|
|
1885
|
+
const settings = useSyncExternalStoreWithSelector(
|
|
1886
|
+
store.subscribe,
|
|
1887
|
+
store.get,
|
|
1888
|
+
store.get,
|
|
1889
|
+
selector
|
|
1890
|
+
);
|
|
1891
|
+
return React3.useMemo(() => {
|
|
1892
|
+
return [settings, updateRoomNotificationSettings];
|
|
1893
|
+
}, [settings, updateRoomNotificationSettings]);
|
|
1894
|
+
}
|
|
1895
|
+
function useRoomOrNull() {
|
|
1896
|
+
return React3.useContext(RoomContext);
|
|
1897
|
+
}
|
|
1898
|
+
function useRoomContextBundleOrNull() {
|
|
1899
|
+
const client = useClientOrNull();
|
|
1900
|
+
const room = useRoomOrNull();
|
|
1901
|
+
return client && room ? getOrCreateRoomContextBundle(client) : null;
|
|
1902
|
+
}
|
|
1903
|
+
function useRoomContextBundle() {
|
|
1904
|
+
const client = useClient();
|
|
1905
|
+
return getOrCreateRoomContextBundle(client);
|
|
1827
1906
|
}
|
|
1828
|
-
function
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1907
|
+
function createRoomContext(client, options) {
|
|
1908
|
+
if (options?.resolveUsers) {
|
|
1909
|
+
throw new Error(
|
|
1910
|
+
"The 'resolveUsers' option has moved to 'createClient' from '@liveblocks/client'. Please refer to our Upgrade Guide to learn more, see https://liveblocks.io/docs/platform/upgrading/1.10."
|
|
1911
|
+
);
|
|
1833
1912
|
}
|
|
1834
|
-
|
|
1913
|
+
if (options?.resolveMentionSuggestions) {
|
|
1914
|
+
throw new Error(
|
|
1915
|
+
"The 'resolveMentionSuggestions' option has moved to 'createClient' from '@liveblocks/client'. Please refer to our Upgrade Guide to learn more, see https://liveblocks.io/docs/platform/upgrading/1.10."
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
return getOrCreateRoomContextBundle(client);
|
|
1835
1919
|
}
|
|
1836
1920
|
function generateQueryKey(roomId, options) {
|
|
1837
1921
|
return `${roomId}-${stringify(options ?? {})}`;
|
|
@@ -1839,14 +1923,14 @@ function generateQueryKey(roomId, options) {
|
|
|
1839
1923
|
|
|
1840
1924
|
// src/shared.ts
|
|
1841
1925
|
function useSharedContextBundle() {
|
|
1842
|
-
const roomContextBundle =
|
|
1843
|
-
const liveblocksContextBundle =
|
|
1926
|
+
const roomContextBundle = useRoomContextBundleOrNull();
|
|
1927
|
+
const liveblocksContextBundle = useLiveblocksContextBundleOrNull();
|
|
1844
1928
|
if (roomContextBundle !== null) {
|
|
1845
1929
|
return roomContextBundle;
|
|
1846
1930
|
} else if (liveblocksContextBundle !== null) {
|
|
1847
1931
|
return liveblocksContextBundle;
|
|
1848
1932
|
} else {
|
|
1849
|
-
|
|
1933
|
+
raise(
|
|
1850
1934
|
"LiveblocksProvider or RoomProvider are missing from the React tree."
|
|
1851
1935
|
);
|
|
1852
1936
|
}
|
|
@@ -1857,142 +1941,201 @@ var missingUserError = new Error(
|
|
|
1857
1941
|
var missingRoomInfoError = new Error(
|
|
1858
1942
|
"resolveRoomsInfo didn't return anything for this room ID."
|
|
1859
1943
|
);
|
|
1860
|
-
function
|
|
1944
|
+
function useUser_withClient(client, userId) {
|
|
1945
|
+
const usersStore = client[kInternal2].usersStore;
|
|
1946
|
+
const getUserState = useCallback2(
|
|
1947
|
+
() => usersStore.getState(userId),
|
|
1948
|
+
[usersStore, userId]
|
|
1949
|
+
);
|
|
1950
|
+
useEffect5(() => {
|
|
1951
|
+
void usersStore.get(userId);
|
|
1952
|
+
}, [usersStore, userId]);
|
|
1953
|
+
const state = useSyncExternalStore2(
|
|
1954
|
+
usersStore.subscribe,
|
|
1955
|
+
getUserState,
|
|
1956
|
+
getUserState
|
|
1957
|
+
);
|
|
1958
|
+
return state ? {
|
|
1959
|
+
isLoading: state.isLoading,
|
|
1960
|
+
user: state.data,
|
|
1961
|
+
// Return an error if `undefined` was returned by `resolveUsers` for this user ID
|
|
1962
|
+
error: !state.isLoading && !state.data && !state.error ? missingUserError : state.error
|
|
1963
|
+
} : { isLoading: true };
|
|
1964
|
+
}
|
|
1965
|
+
function useUserSuspense_withClient(client, userId) {
|
|
1861
1966
|
const usersStore = client[kInternal2].usersStore;
|
|
1967
|
+
const getUserState = useCallback2(
|
|
1968
|
+
() => usersStore.getState(userId),
|
|
1969
|
+
[usersStore, userId]
|
|
1970
|
+
);
|
|
1971
|
+
const userState = getUserState();
|
|
1972
|
+
if (!userState || userState.isLoading) {
|
|
1973
|
+
throw usersStore.get(userId);
|
|
1974
|
+
}
|
|
1975
|
+
if (userState.error) {
|
|
1976
|
+
throw userState.error;
|
|
1977
|
+
}
|
|
1978
|
+
if (!userState.data) {
|
|
1979
|
+
throw missingUserError;
|
|
1980
|
+
}
|
|
1981
|
+
const state = useSyncExternalStore2(
|
|
1982
|
+
usersStore.subscribe,
|
|
1983
|
+
getUserState,
|
|
1984
|
+
getUserState
|
|
1985
|
+
);
|
|
1986
|
+
return {
|
|
1987
|
+
isLoading: false,
|
|
1988
|
+
user: state?.data,
|
|
1989
|
+
error: state?.error
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
function useRoomInfo_withClient(client, roomId) {
|
|
1862
1993
|
const roomsInfoStore = client[kInternal2].roomsInfoStore;
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1994
|
+
const getRoomInfoState = useCallback2(
|
|
1995
|
+
() => roomsInfoStore.getState(roomId),
|
|
1996
|
+
[roomsInfoStore, roomId]
|
|
1997
|
+
);
|
|
1998
|
+
useEffect5(() => {
|
|
1999
|
+
void roomsInfoStore.get(roomId);
|
|
2000
|
+
}, [roomsInfoStore, roomId]);
|
|
2001
|
+
const state = useSyncExternalStore2(
|
|
2002
|
+
roomsInfoStore.subscribe,
|
|
2003
|
+
getRoomInfoState,
|
|
2004
|
+
getRoomInfoState
|
|
2005
|
+
);
|
|
2006
|
+
return state ? {
|
|
2007
|
+
isLoading: state.isLoading,
|
|
2008
|
+
info: state.data,
|
|
2009
|
+
// Return an error if `undefined` was returned by `resolveRoomsInfo` for this room ID
|
|
2010
|
+
error: !state.isLoading && !state.data && !state.error ? missingRoomInfoError : state.error
|
|
2011
|
+
} : { isLoading: true };
|
|
2012
|
+
}
|
|
2013
|
+
function useRoomInfoSuspense_withClient(client, roomId) {
|
|
2014
|
+
const roomsInfoStore = client[kInternal2].roomsInfoStore;
|
|
2015
|
+
const getRoomInfoState = useCallback2(
|
|
2016
|
+
() => roomsInfoStore.getState(roomId),
|
|
2017
|
+
[roomsInfoStore, roomId]
|
|
2018
|
+
);
|
|
2019
|
+
const roomInfoState = getRoomInfoState();
|
|
2020
|
+
if (!roomInfoState || roomInfoState.isLoading) {
|
|
2021
|
+
throw roomsInfoStore.get(roomId);
|
|
1882
2022
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
2023
|
+
if (roomInfoState.error) {
|
|
2024
|
+
throw roomInfoState.error;
|
|
2025
|
+
}
|
|
2026
|
+
if (!roomInfoState.data) {
|
|
2027
|
+
throw missingRoomInfoError;
|
|
2028
|
+
}
|
|
2029
|
+
const state = useSyncExternalStore2(
|
|
2030
|
+
roomsInfoStore.subscribe,
|
|
2031
|
+
getRoomInfoState,
|
|
2032
|
+
getRoomInfoState
|
|
2033
|
+
);
|
|
2034
|
+
return {
|
|
2035
|
+
isLoading: false,
|
|
2036
|
+
info: state?.data,
|
|
2037
|
+
error: state?.error
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
function createSharedContext(client) {
|
|
2041
|
+
return {
|
|
2042
|
+
classic: {
|
|
2043
|
+
useUser: (userId) => useUser_withClient(client, userId),
|
|
2044
|
+
useRoomInfo: (roomId) => useRoomInfo_withClient(client, roomId)
|
|
2045
|
+
},
|
|
2046
|
+
suspense: {
|
|
2047
|
+
useUser: (userId) => useUserSuspense_withClient(client, userId),
|
|
2048
|
+
useRoomInfo: (roomId) => useRoomInfoSuspense_withClient(client, roomId)
|
|
1897
2049
|
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
// src/liveblocks.tsx
|
|
2054
|
+
var ClientContext = createContext2(null);
|
|
2055
|
+
var _extras2 = /* @__PURE__ */ new WeakMap();
|
|
2056
|
+
var _bundles2 = /* @__PURE__ */ new WeakMap();
|
|
2057
|
+
var POLLING_INTERVAL2 = 5 * 1e3;
|
|
2058
|
+
var INBOX_NOTIFICATIONS_QUERY = "INBOX_NOTIFICATIONS";
|
|
2059
|
+
function selectorFor_useInboxNotifications(client, state) {
|
|
2060
|
+
const query = state.queries[INBOX_NOTIFICATIONS_QUERY];
|
|
2061
|
+
if (query === void 0 || query.isLoading) {
|
|
1903
2062
|
return {
|
|
1904
|
-
isLoading:
|
|
1905
|
-
user: state?.data,
|
|
1906
|
-
error: state?.error
|
|
2063
|
+
isLoading: true
|
|
1907
2064
|
};
|
|
1908
2065
|
}
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
useEffect4(() => {
|
|
1915
|
-
void roomsInfoStore.get(roomId);
|
|
1916
|
-
}, [roomId]);
|
|
1917
|
-
const state = useSyncExternalStore2(
|
|
1918
|
-
roomsInfoStore.subscribe,
|
|
1919
|
-
getRoomInfoState,
|
|
1920
|
-
getRoomInfoState
|
|
1921
|
-
);
|
|
1922
|
-
return state ? {
|
|
1923
|
-
isLoading: state.isLoading,
|
|
1924
|
-
info: state.data,
|
|
1925
|
-
// Return an error if `undefined` was returned by `resolveRoomsInfo` for this room ID
|
|
1926
|
-
error: !state.isLoading && !state.data && !state.error ? missingRoomInfoError : state.error
|
|
1927
|
-
} : { isLoading: true };
|
|
2066
|
+
if (query.error !== void 0) {
|
|
2067
|
+
return {
|
|
2068
|
+
error: query.error,
|
|
2069
|
+
isLoading: false
|
|
2070
|
+
};
|
|
1928
2071
|
}
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
2072
|
+
return {
|
|
2073
|
+
inboxNotifications: client[kInternal3].comments.selectedInboxNotifications(state),
|
|
2074
|
+
isLoading: false
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
function selectorFor_useInboxNotificationsSuspense(client, state) {
|
|
2078
|
+
return {
|
|
2079
|
+
inboxNotifications: client[kInternal3].comments.selectedInboxNotifications(state),
|
|
2080
|
+
isLoading: false
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
function selectUnreadInboxNotificationsCount(client, state) {
|
|
2084
|
+
let count = 0;
|
|
2085
|
+
for (const notification of client[kInternal3].comments.selectedInboxNotifications(state)) {
|
|
2086
|
+
if (notification.readAt === null || notification.readAt < notification.notifiedAt) {
|
|
2087
|
+
count++;
|
|
1943
2088
|
}
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
2089
|
+
}
|
|
2090
|
+
return count;
|
|
2091
|
+
}
|
|
2092
|
+
function selectorFor_useUnreadInboxNotificationsCount(client, state) {
|
|
2093
|
+
const query = state.queries[INBOX_NOTIFICATIONS_QUERY];
|
|
2094
|
+
if (query === void 0 || query.isLoading) {
|
|
1949
2095
|
return {
|
|
1950
|
-
isLoading:
|
|
1951
|
-
info: state?.data,
|
|
1952
|
-
error: state?.error
|
|
2096
|
+
isLoading: true
|
|
1953
2097
|
};
|
|
1954
2098
|
}
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2099
|
+
if (query.error !== void 0) {
|
|
2100
|
+
return {
|
|
2101
|
+
error: query.error,
|
|
2102
|
+
isLoading: false
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
return {
|
|
2106
|
+
isLoading: false,
|
|
2107
|
+
count: selectUnreadInboxNotificationsCount(client, state)
|
|
1962
2108
|
};
|
|
1963
|
-
return bundle;
|
|
1964
2109
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2110
|
+
function selectorFor_useUnreadInboxNotificationsCountSuspense(client, state) {
|
|
2111
|
+
return {
|
|
2112
|
+
isLoading: false,
|
|
2113
|
+
count: selectUnreadInboxNotificationsCount(client, state)
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
function getOrCreateContextBundle(client) {
|
|
2117
|
+
let bundle = _bundles2.get(client);
|
|
2118
|
+
if (!bundle) {
|
|
2119
|
+
bundle = makeLiveblocksContextBundle(client);
|
|
2120
|
+
_bundles2.set(client, bundle);
|
|
1972
2121
|
}
|
|
1973
2122
|
return bundle;
|
|
1974
2123
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2124
|
+
function getExtrasForClient2(client) {
|
|
2125
|
+
let extras = _extras2.get(client);
|
|
2126
|
+
if (!extras) {
|
|
2127
|
+
extras = makeExtrasForClient2(client);
|
|
2128
|
+
_extras2.set(client, extras);
|
|
2129
|
+
}
|
|
2130
|
+
return extras;
|
|
2131
|
+
}
|
|
2132
|
+
function makeExtrasForClient2(client) {
|
|
1979
2133
|
const store = client[kInternal3].cacheStore;
|
|
1980
2134
|
const notifications = client[kInternal3].notifications;
|
|
1981
|
-
function LiveblocksProvider(props) {
|
|
1982
|
-
return /* @__PURE__ */ React3.createElement(
|
|
1983
|
-
ContextBundle2.Provider,
|
|
1984
|
-
{
|
|
1985
|
-
value: bundle
|
|
1986
|
-
},
|
|
1987
|
-
props.children
|
|
1988
|
-
);
|
|
1989
|
-
}
|
|
1990
2135
|
let fetchInboxNotificationsRequest = null;
|
|
1991
|
-
let inboxNotificationsSubscribers = 0;
|
|
1992
2136
|
let lastRequestedAt;
|
|
1993
|
-
const poller = makePoller2(
|
|
1994
|
-
|
|
1995
|
-
return notifications.getInboxNotifications({ since: lastRequestedAt }).then(
|
|
2137
|
+
const poller = makePoller2(
|
|
2138
|
+
() => notifications.getInboxNotifications({ since: lastRequestedAt }).then(
|
|
1996
2139
|
(result) => {
|
|
1997
2140
|
lastRequestedAt = result.meta.requestedAt;
|
|
1998
2141
|
store.updateThreadsAndNotifications(
|
|
@@ -2005,24 +2148,8 @@ function createLiveblocksContext(client) {
|
|
|
2005
2148
|
},
|
|
2006
2149
|
() => {
|
|
2007
2150
|
}
|
|
2008
|
-
)
|
|
2009
|
-
|
|
2010
|
-
function incrementInboxNotificationsSubscribers() {
|
|
2011
|
-
inboxNotificationsSubscribers++;
|
|
2012
|
-
poller.start(POLLING_INTERVAL2);
|
|
2013
|
-
}
|
|
2014
|
-
function decrementInboxNotificationsSubscribers() {
|
|
2015
|
-
if (inboxNotificationsSubscribers <= 0) {
|
|
2016
|
-
console.warn(
|
|
2017
|
-
`Internal unexpected behavior. Cannot decrease subscriber count for query "${INBOX_NOTIFICATIONS_QUERY}"`
|
|
2018
|
-
);
|
|
2019
|
-
return;
|
|
2020
|
-
}
|
|
2021
|
-
inboxNotificationsSubscribers--;
|
|
2022
|
-
if (inboxNotificationsSubscribers <= 0) {
|
|
2023
|
-
poller.stop();
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2151
|
+
)
|
|
2152
|
+
);
|
|
2026
2153
|
async function fetchInboxNotifications({ retryCount } = { retryCount: 0 }) {
|
|
2027
2154
|
if (fetchInboxNotificationsRequest !== null) {
|
|
2028
2155
|
return fetchInboxNotificationsRequest;
|
|
@@ -2058,132 +2185,133 @@ function createLiveblocksContext(client) {
|
|
|
2058
2185
|
}
|
|
2059
2186
|
return;
|
|
2060
2187
|
}
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
}
|
|
2068
|
-
if (query.error !== void 0) {
|
|
2069
|
-
return {
|
|
2070
|
-
error: query.error,
|
|
2071
|
-
isLoading: false
|
|
2072
|
-
};
|
|
2073
|
-
}
|
|
2074
|
-
return {
|
|
2075
|
-
inboxNotifications: selectedInboxNotifications(state),
|
|
2076
|
-
isLoading: false
|
|
2077
|
-
};
|
|
2078
|
-
}
|
|
2079
|
-
function useInboxNotifications() {
|
|
2080
|
-
useEffect5(() => {
|
|
2081
|
-
void fetchInboxNotifications();
|
|
2082
|
-
incrementInboxNotificationsSubscribers();
|
|
2083
|
-
return () => decrementInboxNotificationsSubscribers();
|
|
2084
|
-
}, []);
|
|
2085
|
-
const result = useSyncExternalStoreWithSelector2(
|
|
2086
|
-
store.subscribe,
|
|
2087
|
-
store.get,
|
|
2088
|
-
store.get,
|
|
2089
|
-
useInboxNotificationsSelectorCallback
|
|
2090
|
-
);
|
|
2091
|
-
return result;
|
|
2092
|
-
}
|
|
2093
|
-
function useInboxNotificationsSuspenseSelector(state) {
|
|
2094
|
-
return {
|
|
2095
|
-
inboxNotifications: selectedInboxNotifications(state),
|
|
2096
|
-
isLoading: false
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
|
-
function useInboxNotificationsSuspense() {
|
|
2100
|
-
const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
|
|
2101
|
-
if (query === void 0 || query.isLoading) {
|
|
2102
|
-
throw fetchInboxNotifications();
|
|
2103
|
-
}
|
|
2104
|
-
if (query.error !== void 0) {
|
|
2105
|
-
throw query.error;
|
|
2106
|
-
}
|
|
2107
|
-
React3.useEffect(() => {
|
|
2108
|
-
incrementInboxNotificationsSubscribers();
|
|
2109
|
-
return () => {
|
|
2110
|
-
decrementInboxNotificationsSubscribers();
|
|
2111
|
-
};
|
|
2112
|
-
}, []);
|
|
2113
|
-
return useSyncExternalStoreWithSelector2(
|
|
2114
|
-
store.subscribe,
|
|
2115
|
-
store.get,
|
|
2116
|
-
store.get,
|
|
2117
|
-
useInboxNotificationsSuspenseSelector
|
|
2118
|
-
);
|
|
2119
|
-
}
|
|
2120
|
-
function selectUnreadInboxNotificationsCount(state) {
|
|
2121
|
-
let count = 0;
|
|
2122
|
-
for (const notification of selectedInboxNotifications(state)) {
|
|
2123
|
-
if (notification.readAt === null || notification.readAt < notification.notifiedAt) {
|
|
2124
|
-
count++;
|
|
2188
|
+
let inboxNotificationsSubscribers = 0;
|
|
2189
|
+
function useSubscribeToInboxNotificationsEffect(options) {
|
|
2190
|
+
const autoFetch = useInitial(options?.autoFetch ?? true);
|
|
2191
|
+
useEffect6(() => {
|
|
2192
|
+
if (autoFetch) {
|
|
2193
|
+
void fetchInboxNotifications();
|
|
2125
2194
|
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
isLoading: false
|
|
2195
|
+
inboxNotificationsSubscribers++;
|
|
2196
|
+
poller.start(POLLING_INTERVAL2);
|
|
2197
|
+
return () => {
|
|
2198
|
+
if (inboxNotificationsSubscribers <= 0) {
|
|
2199
|
+
console.warn(
|
|
2200
|
+
`Internal unexpected behavior. Cannot decrease subscriber count for query "${INBOX_NOTIFICATIONS_QUERY}"`
|
|
2201
|
+
);
|
|
2202
|
+
return;
|
|
2203
|
+
}
|
|
2204
|
+
inboxNotificationsSubscribers--;
|
|
2205
|
+
if (inboxNotificationsSubscribers <= 0) {
|
|
2206
|
+
poller.stop();
|
|
2207
|
+
}
|
|
2140
2208
|
};
|
|
2141
|
-
}
|
|
2142
|
-
return {
|
|
2143
|
-
isLoading: false,
|
|
2144
|
-
count: selectUnreadInboxNotificationsCount(state)
|
|
2145
|
-
};
|
|
2146
|
-
}
|
|
2147
|
-
function useUnreadInboxNotificationsCount() {
|
|
2148
|
-
useEffect5(() => {
|
|
2149
|
-
void fetchInboxNotifications();
|
|
2150
|
-
incrementInboxNotificationsSubscribers();
|
|
2151
|
-
return () => decrementInboxNotificationsSubscribers();
|
|
2152
|
-
}, []);
|
|
2153
|
-
return useSyncExternalStoreWithSelector2(
|
|
2154
|
-
store.subscribe,
|
|
2155
|
-
store.get,
|
|
2156
|
-
store.get,
|
|
2157
|
-
useUnreadInboxNotificationsCountSelector
|
|
2158
|
-
);
|
|
2209
|
+
}, [autoFetch]);
|
|
2159
2210
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2211
|
+
return {
|
|
2212
|
+
store,
|
|
2213
|
+
notifications,
|
|
2214
|
+
fetchInboxNotifications,
|
|
2215
|
+
useSubscribeToInboxNotificationsEffect
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
function makeLiveblocksContextBundle(client) {
|
|
2219
|
+
const useInboxNotificationThread = (inboxNotificationId) => useInboxNotificationThread_withClient(client, inboxNotificationId);
|
|
2220
|
+
const useMarkInboxNotificationAsRead = () => useMarkInboxNotificationAsRead_withClient(client);
|
|
2221
|
+
const useMarkAllInboxNotificationsAsRead = () => useMarkAllInboxNotificationsAsRead_withClient(client);
|
|
2222
|
+
function LiveblocksProvider2(props) {
|
|
2223
|
+
return /* @__PURE__ */ React4.createElement(ClientContext.Provider, { value: client }, props.children);
|
|
2165
2224
|
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2225
|
+
const shared = createSharedContext(client);
|
|
2226
|
+
const bundle = {
|
|
2227
|
+
LiveblocksProvider: LiveblocksProvider2,
|
|
2228
|
+
useInboxNotifications: () => useInboxNotifications_withClient(client),
|
|
2229
|
+
useUnreadInboxNotificationsCount: () => useUnreadInboxNotificationsCount_withClient(client),
|
|
2230
|
+
useMarkInboxNotificationAsRead,
|
|
2231
|
+
useMarkAllInboxNotificationsAsRead,
|
|
2232
|
+
useInboxNotificationThread,
|
|
2233
|
+
...shared.classic,
|
|
2234
|
+
suspense: {
|
|
2235
|
+
LiveblocksProvider: LiveblocksProvider2,
|
|
2236
|
+
useInboxNotifications: () => useInboxNotificationsSuspense_withClient(client),
|
|
2237
|
+
useUnreadInboxNotificationsCount: () => useUnreadInboxNotificationsCountSuspense_withClient(client),
|
|
2238
|
+
useMarkInboxNotificationAsRead,
|
|
2239
|
+
useMarkAllInboxNotificationsAsRead,
|
|
2240
|
+
useInboxNotificationThread,
|
|
2241
|
+
...shared.suspense
|
|
2242
|
+
},
|
|
2243
|
+
[kInternal3]: {
|
|
2244
|
+
useCurrentUserId: () => useCurrentUserId_withClient(client)
|
|
2170
2245
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2246
|
+
};
|
|
2247
|
+
return Object.defineProperty(bundle, kInternal3, {
|
|
2248
|
+
enumerable: false
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
function useInboxNotifications_withClient(client) {
|
|
2252
|
+
const { store, useSubscribeToInboxNotificationsEffect } = getExtrasForClient2(client);
|
|
2253
|
+
useSubscribeToInboxNotificationsEffect();
|
|
2254
|
+
return useSyncExternalStoreWithSelector2(
|
|
2255
|
+
store.subscribe,
|
|
2256
|
+
store.get,
|
|
2257
|
+
store.get,
|
|
2258
|
+
() => selectorFor_useInboxNotifications(client, store.get())
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
function useInboxNotificationsSuspense_withClient(client) {
|
|
2262
|
+
const {
|
|
2263
|
+
store,
|
|
2264
|
+
fetchInboxNotifications,
|
|
2265
|
+
useSubscribeToInboxNotificationsEffect
|
|
2266
|
+
} = getExtrasForClient2(client);
|
|
2267
|
+
const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
|
|
2268
|
+
if (query === void 0 || query.isLoading) {
|
|
2269
|
+
throw fetchInboxNotifications();
|
|
2270
|
+
}
|
|
2271
|
+
if (query.error !== void 0) {
|
|
2272
|
+
throw query.error;
|
|
2273
|
+
}
|
|
2274
|
+
useSubscribeToInboxNotificationsEffect({ autoFetch: false });
|
|
2275
|
+
return useSyncExternalStoreWithSelector2(
|
|
2276
|
+
store.subscribe,
|
|
2277
|
+
store.get,
|
|
2278
|
+
store.get,
|
|
2279
|
+
() => selectorFor_useInboxNotificationsSuspense(client, store.get())
|
|
2280
|
+
);
|
|
2281
|
+
}
|
|
2282
|
+
function useUnreadInboxNotificationsCount_withClient(client) {
|
|
2283
|
+
const { store, useSubscribeToInboxNotificationsEffect } = getExtrasForClient2(client);
|
|
2284
|
+
useSubscribeToInboxNotificationsEffect();
|
|
2285
|
+
return useSyncExternalStoreWithSelector2(
|
|
2286
|
+
store.subscribe,
|
|
2287
|
+
store.get,
|
|
2288
|
+
store.get,
|
|
2289
|
+
() => selectorFor_useUnreadInboxNotificationsCount(client, store.get())
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
function useUnreadInboxNotificationsCountSuspense_withClient(client) {
|
|
2293
|
+
const {
|
|
2294
|
+
store,
|
|
2295
|
+
fetchInboxNotifications,
|
|
2296
|
+
useSubscribeToInboxNotificationsEffect
|
|
2297
|
+
} = getExtrasForClient2(client);
|
|
2298
|
+
const query = store.get().queries[INBOX_NOTIFICATIONS_QUERY];
|
|
2299
|
+
if (query === void 0 || query.isLoading) {
|
|
2300
|
+
throw fetchInboxNotifications();
|
|
2301
|
+
}
|
|
2302
|
+
useSubscribeToInboxNotificationsEffect({ autoFetch: false });
|
|
2303
|
+
return useSyncExternalStoreWithSelector2(
|
|
2304
|
+
store.subscribe,
|
|
2305
|
+
store.get,
|
|
2306
|
+
store.get,
|
|
2307
|
+
() => selectorFor_useUnreadInboxNotificationsCountSuspense(client, store.get())
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
function useMarkInboxNotificationAsRead_withClient(client) {
|
|
2311
|
+
return useCallback3(
|
|
2312
|
+
(inboxNotificationId) => {
|
|
2313
|
+
const { store, notifications } = getExtrasForClient2(client);
|
|
2314
|
+
const optimisticUpdateId = nanoid2();
|
|
2187
2315
|
const readAt = /* @__PURE__ */ new Date();
|
|
2188
2316
|
store.pushOptimisticUpdate({
|
|
2189
2317
|
type: "mark-inbox-notification-as-read",
|
|
@@ -2227,96 +2355,99 @@ function createLiveblocksContext(client) {
|
|
|
2227
2355
|
}));
|
|
2228
2356
|
}
|
|
2229
2357
|
);
|
|
2230
|
-
},
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
(update) => update.id !== optimisticUpdateId
|
|
2255
|
-
)
|
|
2256
|
-
}));
|
|
2257
|
-
},
|
|
2258
|
-
() => {
|
|
2259
|
-
store.set((state) => ({
|
|
2260
|
-
...state,
|
|
2261
|
-
optimisticUpdates: state.optimisticUpdates.filter(
|
|
2262
|
-
(update) => update.id !== optimisticUpdateId
|
|
2358
|
+
},
|
|
2359
|
+
[client]
|
|
2360
|
+
);
|
|
2361
|
+
}
|
|
2362
|
+
function useMarkAllInboxNotificationsAsRead_withClient(client) {
|
|
2363
|
+
return useCallback3(() => {
|
|
2364
|
+
const { store, notifications } = getExtrasForClient2(client);
|
|
2365
|
+
const optimisticUpdateId = nanoid2();
|
|
2366
|
+
const readAt = /* @__PURE__ */ new Date();
|
|
2367
|
+
store.pushOptimisticUpdate({
|
|
2368
|
+
type: "mark-inbox-notifications-as-read",
|
|
2369
|
+
id: optimisticUpdateId,
|
|
2370
|
+
readAt
|
|
2371
|
+
});
|
|
2372
|
+
notifications.markAllInboxNotificationsAsRead().then(
|
|
2373
|
+
() => {
|
|
2374
|
+
store.set((state) => ({
|
|
2375
|
+
...state,
|
|
2376
|
+
inboxNotifications: Object.fromEntries(
|
|
2377
|
+
Array.from(Object.entries(state.inboxNotifications)).map(
|
|
2378
|
+
([id, inboxNotification]) => [
|
|
2379
|
+
id,
|
|
2380
|
+
{ ...inboxNotification, readAt }
|
|
2381
|
+
]
|
|
2263
2382
|
)
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
function useThreadFromCache(threadId) {
|
|
2270
|
-
const selector = useCallback3(
|
|
2271
|
-
(state) => {
|
|
2272
|
-
const thread = state.threads[threadId];
|
|
2273
|
-
if (thread === void 0) {
|
|
2274
|
-
throw new Error(
|
|
2275
|
-
`Internal error: thread with id "${threadId}" not found in cache`
|
|
2276
|
-
);
|
|
2277
|
-
}
|
|
2278
|
-
return thread;
|
|
2383
|
+
),
|
|
2384
|
+
optimisticUpdates: state.optimisticUpdates.filter(
|
|
2385
|
+
(update) => update.id !== optimisticUpdateId
|
|
2386
|
+
)
|
|
2387
|
+
}));
|
|
2279
2388
|
},
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
}
|
|
2289
|
-
const currentUserIdStore = client[kInternal3].currentUserIdStore;
|
|
2290
|
-
function useCurrentUserId() {
|
|
2291
|
-
return useSyncExternalStore3(
|
|
2292
|
-
currentUserIdStore.subscribe,
|
|
2293
|
-
currentUserIdStore.get,
|
|
2294
|
-
currentUserIdStore.get
|
|
2389
|
+
() => {
|
|
2390
|
+
store.set((state) => ({
|
|
2391
|
+
...state,
|
|
2392
|
+
optimisticUpdates: state.optimisticUpdates.filter(
|
|
2393
|
+
(update) => update.id !== optimisticUpdateId
|
|
2394
|
+
)
|
|
2395
|
+
}));
|
|
2396
|
+
}
|
|
2295
2397
|
);
|
|
2296
|
-
}
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2398
|
+
}, [client]);
|
|
2399
|
+
}
|
|
2400
|
+
function useInboxNotificationThread_withClient(client, inboxNotificationId) {
|
|
2401
|
+
const { store } = getExtrasForClient2(client);
|
|
2402
|
+
const selector = useCallback3(
|
|
2403
|
+
(state) => {
|
|
2404
|
+
const inboxNotification = state.inboxNotifications[inboxNotificationId] ?? raise2(`Inbox notification with ID "${inboxNotificationId}" not found`);
|
|
2405
|
+
if (inboxNotification.kind !== "thread") {
|
|
2406
|
+
raise2(
|
|
2407
|
+
`Inbox notification with ID "${inboxNotificationId}" is not of kind "thread"`
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
2410
|
+
const thread = state.threads[inboxNotification.threadId] ?? raise2(
|
|
2411
|
+
`Thread with ID "${inboxNotification.threadId}" not found, this inbox notification might not be of kind "thread"`
|
|
2412
|
+
);
|
|
2413
|
+
return thread;
|
|
2311
2414
|
},
|
|
2312
|
-
[
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2415
|
+
[inboxNotificationId]
|
|
2416
|
+
);
|
|
2417
|
+
return useSyncExternalStoreWithSelector2(
|
|
2418
|
+
store.subscribe,
|
|
2419
|
+
store.get,
|
|
2420
|
+
store.get,
|
|
2421
|
+
selector
|
|
2422
|
+
);
|
|
2423
|
+
}
|
|
2424
|
+
function useCurrentUserId_withClient(client) {
|
|
2425
|
+
const currentUserIdStore = client[kInternal3].currentUserIdStore;
|
|
2426
|
+
return useSyncExternalStore3(
|
|
2427
|
+
currentUserIdStore.subscribe,
|
|
2428
|
+
currentUserIdStore.get,
|
|
2429
|
+
currentUserIdStore.get
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
function useClientOrNull() {
|
|
2433
|
+
return useContext2(ClientContext);
|
|
2434
|
+
}
|
|
2435
|
+
function useClient() {
|
|
2436
|
+
return useClientOrNull() ?? raise2("LiveblocksProvider is missing from the React tree.");
|
|
2437
|
+
}
|
|
2438
|
+
function LiveblocksProvider(props) {
|
|
2439
|
+
return /* @__PURE__ */ React4.createElement(ClientContext.Provider, { value: props.client }, props.children);
|
|
2440
|
+
}
|
|
2441
|
+
function useLiveblocksContextBundleOrNull() {
|
|
2442
|
+
const client = useClientOrNull();
|
|
2443
|
+
return client !== null ? getOrCreateContextBundle(client) : null;
|
|
2444
|
+
}
|
|
2445
|
+
function useLiveblocksContextBundle() {
|
|
2446
|
+
const client = useClient();
|
|
2447
|
+
return getOrCreateContextBundle(client);
|
|
2448
|
+
}
|
|
2449
|
+
function createLiveblocksContext(client) {
|
|
2450
|
+
return getOrCreateContextBundle(client);
|
|
2320
2451
|
}
|
|
2321
2452
|
|
|
2322
2453
|
// src/index.ts
|
|
@@ -2324,10 +2455,14 @@ import { shallow as shallow2 } from "@liveblocks/client";
|
|
|
2324
2455
|
detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
2325
2456
|
export {
|
|
2326
2457
|
ClientSideSuspense,
|
|
2458
|
+
CreateThreadError,
|
|
2459
|
+
DeleteCommentError,
|
|
2327
2460
|
createLiveblocksContext,
|
|
2328
2461
|
createRoomContext,
|
|
2329
2462
|
shallow2 as shallow,
|
|
2463
|
+
useClient,
|
|
2330
2464
|
useLiveblocksContextBundle,
|
|
2465
|
+
useLiveblocksContextBundleOrNull,
|
|
2331
2466
|
useRoomContextBundle,
|
|
2332
2467
|
useSharedContextBundle
|
|
2333
2468
|
};
|