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