@liveblocks/react 2.9.3-experimental1 → 2.10.1-react19
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/_private/README.md +5 -0
- package/_private/package.json +4 -0
- package/dist/_private.d.mts +14 -0
- package/dist/_private.d.ts +14 -0
- package/dist/_private.js +67 -0
- package/dist/_private.js.map +1 -0
- package/dist/_private.mjs +67 -0
- package/dist/_private.mjs.map +1 -0
- package/dist/{chunk-PZIVKFDZ.js → chunk-3MM4G6XB.js} +794 -776
- package/dist/chunk-3MM4G6XB.js.map +1 -0
- package/dist/{chunk-SNEUTGU4.mjs → chunk-A7GJNN4L.mjs} +794 -776
- package/dist/chunk-A7GJNN4L.mjs.map +1 -0
- package/dist/chunk-DNACURSM.mjs +22 -0
- package/dist/chunk-DNACURSM.mjs.map +1 -0
- package/dist/chunk-EXS4G6PT.js +22 -0
- package/dist/chunk-EXS4G6PT.js.map +1 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -12
- package/dist/index.mjs.map +1 -1
- package/dist/{suspense-fYGGJ3D9.d.mts → liveblocks-SAVcXwMX.d.mts} +112 -782
- package/dist/{suspense-fYGGJ3D9.d.ts → liveblocks-SAVcXwMX.d.ts} +112 -782
- package/dist/suspense-W7Cp9ygn.d.ts +726 -0
- package/dist/suspense-vGJE9Mgq.d.mts +726 -0
- package/dist/suspense.d.mts +2 -1
- package/dist/suspense.d.ts +2 -1
- package/dist/suspense.js +5 -3
- package/dist/suspense.js.map +1 -1
- package/dist/suspense.mjs +8 -6
- package/dist/suspense.mjs.map +1 -1
- package/package.json +16 -4
- package/dist/chunk-PZIVKFDZ.js.map +0 -1
- package/dist/chunk-SNEUTGU4.mjs.map +0 -1
|
@@ -1,41 +1,133 @@
|
|
|
1
|
-
// src/version.ts
|
|
2
|
-
var PKG_NAME = "@liveblocks/react";
|
|
3
|
-
var PKG_VERSION = "2.9.3-experimental1";
|
|
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 ? typeof props.children === "function" ? props.children() : props.children : props.fallback);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
1
|
// src/contexts.ts
|
|
17
|
-
import * as
|
|
18
|
-
var RoomContext =
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
var RoomContext = React.createContext(null);
|
|
19
4
|
function useRoomOrNull() {
|
|
20
|
-
return
|
|
5
|
+
return React.useContext(RoomContext);
|
|
21
6
|
}
|
|
22
7
|
function useIsInsideRoom() {
|
|
23
8
|
const room = useRoomOrNull();
|
|
24
9
|
return room !== null;
|
|
25
10
|
}
|
|
26
11
|
|
|
12
|
+
// src/liveblocks.tsx
|
|
13
|
+
import {
|
|
14
|
+
assert,
|
|
15
|
+
createClient,
|
|
16
|
+
kInternal as kInternal2,
|
|
17
|
+
makePoller,
|
|
18
|
+
raise,
|
|
19
|
+
shallow as shallow3
|
|
20
|
+
} from "@liveblocks/core";
|
|
21
|
+
import React2, {
|
|
22
|
+
createContext as createContext2,
|
|
23
|
+
useCallback as useCallback2,
|
|
24
|
+
useContext as useContext2,
|
|
25
|
+
useEffect as useEffect2,
|
|
26
|
+
useMemo
|
|
27
|
+
} from "react";
|
|
28
|
+
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
29
|
+
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
|
|
30
|
+
|
|
31
|
+
// src/config.ts
|
|
32
|
+
var SECONDS = 1e3;
|
|
33
|
+
var MINUTES = 60 * SECONDS;
|
|
34
|
+
var config = {
|
|
35
|
+
NOTIFICATIONS_POLL_INTERVAL: 1 * MINUTES,
|
|
36
|
+
NOTIFICATIONS_MAX_STALE_TIME: 5 * SECONDS,
|
|
37
|
+
ROOM_THREADS_POLL_INTERVAL: 5 * MINUTES,
|
|
38
|
+
ROOM_THREADS_MAX_STALE_TIME: 5 * SECONDS,
|
|
39
|
+
USER_THREADS_POLL_INTERVAL: 1 * MINUTES,
|
|
40
|
+
USER_THREADS_MAX_STALE_TIME: 5 * SECONDS,
|
|
41
|
+
HISTORY_VERSIONS_POLL_INTERVAL: 1 * MINUTES,
|
|
42
|
+
HISTORY_VERSIONS_MAX_STALE_TIME: 5 * SECONDS,
|
|
43
|
+
NOTIFICATION_SETTINGS_POLL_INTERVAL: 1 * MINUTES,
|
|
44
|
+
NOTIFICATION_SETTINGS_MAX_STALE_TIME: 5 * SECONDS
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/lib/shallow2.ts
|
|
48
|
+
import { isPlainObject, shallow } from "@liveblocks/core";
|
|
49
|
+
function shallow2(a, b) {
|
|
50
|
+
if (!isPlainObject(a) || !isPlainObject(b)) {
|
|
51
|
+
return shallow(a, b);
|
|
52
|
+
}
|
|
53
|
+
const keysA = Object.keys(a);
|
|
54
|
+
if (keysA.length !== Object.keys(b).length) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return keysA.every(
|
|
58
|
+
(key) => Object.prototype.hasOwnProperty.call(b, key) && shallow(a[key], b[key])
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/lib/use-initial.ts
|
|
63
|
+
import { useCallback, useReducer } from "react";
|
|
64
|
+
|
|
65
|
+
// src/lib/use-latest.ts
|
|
66
|
+
import { useEffect, useRef } from "react";
|
|
67
|
+
function useLatest(value) {
|
|
68
|
+
const ref = useRef(value);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
ref.current = value;
|
|
71
|
+
}, [value]);
|
|
72
|
+
return ref;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/lib/use-initial.ts
|
|
76
|
+
var noop = (state) => state;
|
|
77
|
+
function useInitial(value) {
|
|
78
|
+
return useReducer(noop, value)[0];
|
|
79
|
+
}
|
|
80
|
+
function useInitialUnlessFunction(latestValue) {
|
|
81
|
+
const frozenValue = useInitial(latestValue);
|
|
82
|
+
if (typeof frozenValue === "function") {
|
|
83
|
+
const ref = useLatest(latestValue);
|
|
84
|
+
return useCallback((...args) => ref.current(...args), [
|
|
85
|
+
ref
|
|
86
|
+
]);
|
|
87
|
+
} else {
|
|
88
|
+
return frozenValue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/lib/use-polyfill.ts
|
|
93
|
+
var use = (
|
|
94
|
+
// React.use ||
|
|
95
|
+
(promise) => {
|
|
96
|
+
if (promise.status === "pending") {
|
|
97
|
+
throw promise;
|
|
98
|
+
} else if (promise.status === "fulfilled") {
|
|
99
|
+
return promise.value;
|
|
100
|
+
} else if (promise.status === "rejected") {
|
|
101
|
+
throw promise.reason;
|
|
102
|
+
} else {
|
|
103
|
+
promise.status = "pending";
|
|
104
|
+
promise.then(
|
|
105
|
+
(v) => {
|
|
106
|
+
promise.status = "fulfilled";
|
|
107
|
+
promise.value = v;
|
|
108
|
+
},
|
|
109
|
+
(e) => {
|
|
110
|
+
promise.status = "rejected";
|
|
111
|
+
promise.reason = e;
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
throw promise;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
27
119
|
// src/umbrella-store.ts
|
|
28
120
|
import {
|
|
29
121
|
autoRetry,
|
|
30
122
|
compactObject,
|
|
31
123
|
console as console2,
|
|
32
124
|
createStore,
|
|
125
|
+
HttpError,
|
|
33
126
|
kInternal,
|
|
34
127
|
makeEventSource,
|
|
35
128
|
mapValues,
|
|
36
129
|
nanoid,
|
|
37
130
|
nn,
|
|
38
|
-
StopRetrying,
|
|
39
131
|
stringify
|
|
40
132
|
} from "@liveblocks/core";
|
|
41
133
|
|
|
@@ -56,21 +148,13 @@ function autobind(self) {
|
|
|
56
148
|
} while ((obj = Reflect.getPrototypeOf(obj)) && obj !== Object.prototype);
|
|
57
149
|
}
|
|
58
150
|
|
|
59
|
-
// src/
|
|
60
|
-
|
|
61
|
-
return a.createdAt.getTime() - b.createdAt.getTime();
|
|
62
|
-
}
|
|
63
|
-
function isMoreRecentlyUpdated(a, b) {
|
|
64
|
-
return byMostRecentlyUpdated(a, b) < 0;
|
|
65
|
-
}
|
|
66
|
-
function byMostRecentlyUpdated(a, b) {
|
|
67
|
-
return b.updatedAt.getTime() - a.updatedAt.getTime();
|
|
68
|
-
}
|
|
151
|
+
// src/ThreadDB.ts
|
|
152
|
+
import { SortedList } from "@liveblocks/core";
|
|
69
153
|
|
|
70
154
|
// src/lib/guards.ts
|
|
71
|
-
import { isPlainObject } from "@liveblocks/core";
|
|
155
|
+
import { isPlainObject as isPlainObject2 } from "@liveblocks/core";
|
|
72
156
|
function isStartsWith(blob) {
|
|
73
|
-
return
|
|
157
|
+
return isPlainObject2(blob) && isString(blob.startsWith);
|
|
74
158
|
}
|
|
75
159
|
function isString(value) {
|
|
76
160
|
return typeof value === "string";
|
|
@@ -103,8 +187,124 @@ function matchesOperator(value, op) {
|
|
|
103
187
|
}
|
|
104
188
|
}
|
|
105
189
|
|
|
190
|
+
// src/ThreadDB.ts
|
|
191
|
+
function sanitizeThread(thread) {
|
|
192
|
+
if (thread.deletedAt) {
|
|
193
|
+
if (thread.comments.length > 0) {
|
|
194
|
+
return { ...thread, comments: [] };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const hasComment = thread.comments.some((c) => !c.deletedAt);
|
|
198
|
+
if (!hasComment) {
|
|
199
|
+
return { ...thread, deletedAt: /* @__PURE__ */ new Date(), comments: [] };
|
|
200
|
+
}
|
|
201
|
+
return thread;
|
|
202
|
+
}
|
|
203
|
+
var ThreadDB = class _ThreadDB {
|
|
204
|
+
// The version is auto-incremented on every mutation and can be used as a reliable indicator to tell if the contents of the thread pool has changed
|
|
205
|
+
constructor() {
|
|
206
|
+
this._asc = SortedList.from([], (t1, t2) => {
|
|
207
|
+
const d1 = t1.createdAt;
|
|
208
|
+
const d2 = t2.createdAt;
|
|
209
|
+
return d1 < d2 ? true : d1 === d2 ? t1.id < t2.id : false;
|
|
210
|
+
});
|
|
211
|
+
this._desc = SortedList.from([], (t1, t2) => {
|
|
212
|
+
const d2 = t2.updatedAt;
|
|
213
|
+
const d1 = t1.updatedAt;
|
|
214
|
+
return d2 < d1 ? true : d2 === d1 ? t2.id < t1.id : false;
|
|
215
|
+
});
|
|
216
|
+
this._byId = /* @__PURE__ */ new Map();
|
|
217
|
+
this._version = 0;
|
|
218
|
+
}
|
|
219
|
+
//
|
|
220
|
+
// Public APIs
|
|
221
|
+
//
|
|
222
|
+
clone() {
|
|
223
|
+
const newPool = new _ThreadDB();
|
|
224
|
+
newPool._byId = new Map(this._byId);
|
|
225
|
+
newPool._asc = this._asc.clone();
|
|
226
|
+
newPool._desc = this._desc.clone();
|
|
227
|
+
newPool._version = this._version;
|
|
228
|
+
return newPool;
|
|
229
|
+
}
|
|
230
|
+
/** Gets the transaction count for this DB. Increments any time the DB is modified. */
|
|
231
|
+
get version() {
|
|
232
|
+
return this._version;
|
|
233
|
+
}
|
|
234
|
+
/** Returns an existing thread by ID. Will never return a deleted thread. */
|
|
235
|
+
get(threadId) {
|
|
236
|
+
const thread = this.getEvenIfDeleted(threadId);
|
|
237
|
+
return thread?.deletedAt ? void 0 : thread;
|
|
238
|
+
}
|
|
239
|
+
/** Returns the (possibly deleted) thread by ID. */
|
|
240
|
+
getEvenIfDeleted(threadId) {
|
|
241
|
+
return this._byId.get(threadId);
|
|
242
|
+
}
|
|
243
|
+
/** Adds or updates a thread in the DB. If the newly given thread is a deleted one, it will get deleted. */
|
|
244
|
+
upsert(thread) {
|
|
245
|
+
thread = sanitizeThread(thread);
|
|
246
|
+
const id = thread.id;
|
|
247
|
+
const toRemove = this._byId.get(id);
|
|
248
|
+
if (toRemove) {
|
|
249
|
+
if (toRemove.deletedAt) return;
|
|
250
|
+
this._asc.remove(toRemove);
|
|
251
|
+
this._desc.remove(toRemove);
|
|
252
|
+
}
|
|
253
|
+
if (!thread.deletedAt) {
|
|
254
|
+
this._asc.add(thread);
|
|
255
|
+
this._desc.add(thread);
|
|
256
|
+
}
|
|
257
|
+
this._byId.set(id, thread);
|
|
258
|
+
this.touch();
|
|
259
|
+
}
|
|
260
|
+
/** Like .upsert(), except it won't update if a thread by this ID already exists. */
|
|
261
|
+
// TODO Consider renaming this to just .upsert(). I'm not sure if we really
|
|
262
|
+
// TODO need the raw .upsert(). Would be nice if this behavior was the default.
|
|
263
|
+
upsertIfNewer(thread) {
|
|
264
|
+
const existing = this.get(thread.id);
|
|
265
|
+
if (!existing || thread.updatedAt >= existing.updatedAt) {
|
|
266
|
+
this.upsert(thread);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Marks a thread as deleted. It will no longer pop up in .findMany()
|
|
271
|
+
* queries, but it can still be accessed via `.getEvenIfDeleted()`.
|
|
272
|
+
*/
|
|
273
|
+
delete(threadId, deletedAt) {
|
|
274
|
+
const existing = this._byId.get(threadId);
|
|
275
|
+
if (existing && !existing.deletedAt) {
|
|
276
|
+
this.upsert({ ...existing, deletedAt, updatedAt: deletedAt });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Returns all threads matching a given roomId and query. If roomId is not
|
|
281
|
+
* specified, it will return all threads matching the query, across all
|
|
282
|
+
* rooms.
|
|
283
|
+
*
|
|
284
|
+
* Returns the results in the requested order. Please note:
|
|
285
|
+
* 'asc' means by createdAt ASC
|
|
286
|
+
* 'desc' means by updatedAt DESC
|
|
287
|
+
*
|
|
288
|
+
* Will never return deleted threads in the result.
|
|
289
|
+
*/
|
|
290
|
+
findMany(roomId, query, direction) {
|
|
291
|
+
const index = direction === "desc" ? this._desc : this._asc;
|
|
292
|
+
const crit = [];
|
|
293
|
+
if (roomId !== void 0) {
|
|
294
|
+
crit.push((t) => t.roomId === roomId);
|
|
295
|
+
}
|
|
296
|
+
crit.push(makeThreadsFilter(query));
|
|
297
|
+
return Array.from(index.filter((t) => crit.every((pred) => pred(t))));
|
|
298
|
+
}
|
|
299
|
+
//
|
|
300
|
+
// Private APIs
|
|
301
|
+
//
|
|
302
|
+
touch() {
|
|
303
|
+
++this._version;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
106
307
|
// src/umbrella-store.ts
|
|
107
|
-
var ASYNC_OK = Object.freeze({ isLoading: false, data: void 0 });
|
|
108
308
|
function makeRoomThreadsQueryKey(roomId, query) {
|
|
109
309
|
return `${roomId}-${stringify(query ?? {})}`;
|
|
110
310
|
}
|
|
@@ -117,19 +317,6 @@ function makeNotificationSettingsQueryKey(roomId) {
|
|
|
117
317
|
function makeVersionsQueryKey(roomId) {
|
|
118
318
|
return `${roomId}-VERSIONS`;
|
|
119
319
|
}
|
|
120
|
-
function selectThreads(state, options) {
|
|
121
|
-
let threads = state.threads;
|
|
122
|
-
if (options.roomId !== null) {
|
|
123
|
-
threads = threads.filter((thread) => thread.roomId === options.roomId);
|
|
124
|
-
}
|
|
125
|
-
const query = options.query;
|
|
126
|
-
if (query) {
|
|
127
|
-
threads = threads.filter(makeThreadsFilter(query));
|
|
128
|
-
}
|
|
129
|
-
return threads.sort(
|
|
130
|
-
options.orderBy === "last-update" ? byMostRecentlyUpdated : byFirstCreated
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
320
|
function usify(promise) {
|
|
134
321
|
if ("status" in promise) {
|
|
135
322
|
return promise;
|
|
@@ -148,7 +335,7 @@ function usify(promise) {
|
|
|
148
335
|
);
|
|
149
336
|
return usable;
|
|
150
337
|
}
|
|
151
|
-
var
|
|
338
|
+
var noop2 = Promise.resolve();
|
|
152
339
|
var ASYNC_LOADING = Object.freeze({ isLoading: true });
|
|
153
340
|
var PaginatedResource = class {
|
|
154
341
|
constructor(fetchPage) {
|
|
@@ -189,7 +376,7 @@ var PaginatedResource = class {
|
|
|
189
376
|
fetchMore() {
|
|
190
377
|
const state = this._paginationState;
|
|
191
378
|
if (state?.cursor === null) {
|
|
192
|
-
return
|
|
379
|
+
return noop2;
|
|
193
380
|
}
|
|
194
381
|
if (!this._pendingFetchMore) {
|
|
195
382
|
this._pendingFetchMore = this._fetchMore().finally(() => {
|
|
@@ -252,8 +439,54 @@ var PaginatedResource = class {
|
|
|
252
439
|
return promise;
|
|
253
440
|
}
|
|
254
441
|
};
|
|
442
|
+
var SinglePageResource = class {
|
|
443
|
+
constructor(fetchPage) {
|
|
444
|
+
this._cachedPromise = null;
|
|
445
|
+
this._fetchPage = fetchPage;
|
|
446
|
+
this._eventSource = makeEventSource();
|
|
447
|
+
this.observable = this._eventSource.observable;
|
|
448
|
+
autobind(this);
|
|
449
|
+
}
|
|
450
|
+
get() {
|
|
451
|
+
const usable = this._cachedPromise;
|
|
452
|
+
if (usable === null || usable.status === "pending") {
|
|
453
|
+
return ASYNC_LOADING;
|
|
454
|
+
}
|
|
455
|
+
if (usable.status === "rejected") {
|
|
456
|
+
return { isLoading: false, error: usable.reason };
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
isLoading: false,
|
|
460
|
+
data: void 0
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
waitUntilLoaded() {
|
|
464
|
+
if (this._cachedPromise) {
|
|
465
|
+
return this._cachedPromise;
|
|
466
|
+
}
|
|
467
|
+
const initialFetcher = autoRetry(
|
|
468
|
+
() => this._fetchPage(),
|
|
469
|
+
5,
|
|
470
|
+
[5e3, 5e3, 1e4, 15e3]
|
|
471
|
+
);
|
|
472
|
+
const promise = usify(initialFetcher);
|
|
473
|
+
promise.then(
|
|
474
|
+
() => this._eventSource.notify(),
|
|
475
|
+
() => {
|
|
476
|
+
this._eventSource.notify();
|
|
477
|
+
setTimeout(() => {
|
|
478
|
+
this._cachedPromise = null;
|
|
479
|
+
this._eventSource.notify();
|
|
480
|
+
}, 5e3);
|
|
481
|
+
}
|
|
482
|
+
);
|
|
483
|
+
this._cachedPromise = promise;
|
|
484
|
+
return promise;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
255
487
|
var UmbrellaStore = class {
|
|
256
488
|
constructor(client) {
|
|
489
|
+
this._prevVersion = -1;
|
|
257
490
|
this._prevState = null;
|
|
258
491
|
this._stateCached = null;
|
|
259
492
|
// Notifications
|
|
@@ -264,16 +497,16 @@ var UmbrellaStore = class {
|
|
|
264
497
|
// User Threads
|
|
265
498
|
this._userThreadsLastRequestedAt = null;
|
|
266
499
|
this._userThreads = /* @__PURE__ */ new Map();
|
|
500
|
+
// Room versions
|
|
501
|
+
this._roomVersions = /* @__PURE__ */ new Map();
|
|
502
|
+
this._roomVersionsLastRequestedAtByRoom = /* @__PURE__ */ new Map();
|
|
503
|
+
// Room notification settings
|
|
504
|
+
this._roomNotificationSettings = /* @__PURE__ */ new Map();
|
|
505
|
+
this._client = client[kInternal].as();
|
|
267
506
|
const inboxFetcher = async (cursor) => {
|
|
268
|
-
|
|
269
|
-
throw new StopRetrying(
|
|
270
|
-
"Client is required in order to load threads for the room"
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
const result = await client.getInboxNotifications({ cursor });
|
|
507
|
+
const result = await this._client.getInboxNotifications({ cursor });
|
|
274
508
|
this.updateThreadsAndNotifications(
|
|
275
509
|
result.threads,
|
|
276
|
-
// TODO: Figure out how to remove this casting
|
|
277
510
|
result.inboxNotifications
|
|
278
511
|
);
|
|
279
512
|
if (this._notificationsLastRequestedAt === null) {
|
|
@@ -282,7 +515,6 @@ var UmbrellaStore = class {
|
|
|
282
515
|
const nextCursor = result.nextCursor;
|
|
283
516
|
return nextCursor;
|
|
284
517
|
};
|
|
285
|
-
this._client = client;
|
|
286
518
|
this._notifications = new PaginatedResource(inboxFetcher);
|
|
287
519
|
this._notifications.observable.subscribe(
|
|
288
520
|
() => (
|
|
@@ -291,10 +523,8 @@ var UmbrellaStore = class {
|
|
|
291
523
|
this._store.set((store) => ({ ...store }))
|
|
292
524
|
)
|
|
293
525
|
);
|
|
526
|
+
this._rawThreadsDB = new ThreadDB();
|
|
294
527
|
this._store = createStore({
|
|
295
|
-
rawThreadsById: {},
|
|
296
|
-
queries3: {},
|
|
297
|
-
queries4: {},
|
|
298
528
|
optimisticUpdates: [],
|
|
299
529
|
notificationsById: {},
|
|
300
530
|
settingsByRoomId: {},
|
|
@@ -304,9 +534,11 @@ var UmbrellaStore = class {
|
|
|
304
534
|
}
|
|
305
535
|
get() {
|
|
306
536
|
const rawState = this._store.get();
|
|
307
|
-
if (this.
|
|
537
|
+
if (this._prevVersion !== this._rawThreadsDB.version || // Note: Version check is only needed temporarily, until we can get rid of the Zustand-like update model
|
|
538
|
+
this._prevState !== rawState || this._stateCached === null) {
|
|
539
|
+
this._stateCached = internalToExternalState(rawState, this._rawThreadsDB);
|
|
308
540
|
this._prevState = rawState;
|
|
309
|
-
this.
|
|
541
|
+
this._prevVersion = this._rawThreadsDB.version;
|
|
310
542
|
}
|
|
311
543
|
return this._stateCached;
|
|
312
544
|
}
|
|
@@ -321,8 +553,7 @@ var UmbrellaStore = class {
|
|
|
321
553
|
* then it will return the threads that match that provided query and room id.
|
|
322
554
|
*
|
|
323
555
|
*/
|
|
324
|
-
|
|
325
|
-
getRoomThreadsAsync(roomId, query) {
|
|
556
|
+
getRoomThreadsLoadingState(roomId, query) {
|
|
326
557
|
const queryKey = makeRoomThreadsQueryKey(roomId, query);
|
|
327
558
|
const paginatedResource = this._roomThreads.get(queryKey);
|
|
328
559
|
if (paginatedResource === void 0) {
|
|
@@ -332,11 +563,11 @@ var UmbrellaStore = class {
|
|
|
332
563
|
if (asyncResult.isLoading || asyncResult.error) {
|
|
333
564
|
return asyncResult;
|
|
334
565
|
}
|
|
335
|
-
const threads =
|
|
566
|
+
const threads = this.getFullState().threadsDB.findMany(
|
|
336
567
|
roomId,
|
|
337
|
-
query,
|
|
338
|
-
|
|
339
|
-
|
|
568
|
+
query ?? {},
|
|
569
|
+
"asc"
|
|
570
|
+
);
|
|
340
571
|
const page = asyncResult.data;
|
|
341
572
|
return {
|
|
342
573
|
isLoading: false,
|
|
@@ -347,8 +578,7 @@ var UmbrellaStore = class {
|
|
|
347
578
|
fetchMore: page.fetchMore
|
|
348
579
|
};
|
|
349
580
|
}
|
|
350
|
-
|
|
351
|
-
getUserThreadsAsync(query) {
|
|
581
|
+
getUserThreadsLoadingState(query) {
|
|
352
582
|
const queryKey = makeUserThreadsQueryKey(query);
|
|
353
583
|
const paginatedResource = this._userThreads.get(queryKey);
|
|
354
584
|
if (paginatedResource === void 0) {
|
|
@@ -358,12 +588,12 @@ var UmbrellaStore = class {
|
|
|
358
588
|
if (asyncResult.isLoading || asyncResult.error) {
|
|
359
589
|
return asyncResult;
|
|
360
590
|
}
|
|
361
|
-
const threads =
|
|
362
|
-
|
|
591
|
+
const threads = this.getFullState().threadsDB.findMany(
|
|
592
|
+
void 0,
|
|
363
593
|
// Do _not_ filter by roomId
|
|
364
|
-
query,
|
|
365
|
-
|
|
366
|
-
|
|
594
|
+
query ?? {},
|
|
595
|
+
"desc"
|
|
596
|
+
);
|
|
367
597
|
const page = asyncResult.data;
|
|
368
598
|
return {
|
|
369
599
|
isLoading: false,
|
|
@@ -375,8 +605,7 @@ var UmbrellaStore = class {
|
|
|
375
605
|
};
|
|
376
606
|
}
|
|
377
607
|
// NOTE: This will read the async result, but WILL NOT start loading at the moment!
|
|
378
|
-
|
|
379
|
-
getInboxNotificationsAsync() {
|
|
608
|
+
getInboxNotificationsLoadingState() {
|
|
380
609
|
const asyncResult = this._notifications.get();
|
|
381
610
|
if (asyncResult.isLoading || asyncResult.error) {
|
|
382
611
|
return asyncResult;
|
|
@@ -384,7 +613,7 @@ var UmbrellaStore = class {
|
|
|
384
613
|
const page = asyncResult.data;
|
|
385
614
|
return {
|
|
386
615
|
isLoading: false,
|
|
387
|
-
inboxNotifications: this.getFullState().
|
|
616
|
+
inboxNotifications: this.getFullState().cleanedNotifications,
|
|
388
617
|
hasFetchedAll: page.hasFetchedAll,
|
|
389
618
|
isFetchingMore: page.isFetchingMore,
|
|
390
619
|
fetchMoreError: page.fetchMoreError,
|
|
@@ -392,32 +621,34 @@ var UmbrellaStore = class {
|
|
|
392
621
|
};
|
|
393
622
|
}
|
|
394
623
|
// NOTE: This will read the async result, but WILL NOT start loading at the moment!
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
const
|
|
398
|
-
if (
|
|
624
|
+
getNotificationSettingsLoadingState(roomId) {
|
|
625
|
+
const queryKey = makeNotificationSettingsQueryKey(roomId);
|
|
626
|
+
const resource = this._roomNotificationSettings.get(queryKey);
|
|
627
|
+
if (resource === void 0) {
|
|
399
628
|
return ASYNC_LOADING;
|
|
400
629
|
}
|
|
401
|
-
|
|
402
|
-
|
|
630
|
+
const asyncResult = resource.get();
|
|
631
|
+
if (asyncResult.isLoading || asyncResult.error) {
|
|
632
|
+
return asyncResult;
|
|
403
633
|
}
|
|
404
634
|
return {
|
|
405
635
|
isLoading: false,
|
|
406
|
-
settings: nn(
|
|
636
|
+
settings: nn(this.get().settingsByRoomId[roomId])
|
|
407
637
|
};
|
|
408
638
|
}
|
|
409
|
-
|
|
410
|
-
const
|
|
411
|
-
const
|
|
412
|
-
if (
|
|
639
|
+
getRoomVersionsLoadingState(roomId) {
|
|
640
|
+
const queryKey = makeVersionsQueryKey(roomId);
|
|
641
|
+
const resource = this._roomVersions.get(queryKey);
|
|
642
|
+
if (resource === void 0) {
|
|
413
643
|
return ASYNC_LOADING;
|
|
414
644
|
}
|
|
415
|
-
|
|
416
|
-
|
|
645
|
+
const asyncResult = resource.get();
|
|
646
|
+
if (asyncResult.isLoading || asyncResult.error) {
|
|
647
|
+
return asyncResult;
|
|
417
648
|
}
|
|
418
649
|
return {
|
|
419
650
|
isLoading: false,
|
|
420
|
-
versions:
|
|
651
|
+
versions: Object.values(this.get().versionsByRoomId[roomId] ?? {})
|
|
421
652
|
};
|
|
422
653
|
}
|
|
423
654
|
/**
|
|
@@ -429,33 +660,14 @@ var UmbrellaStore = class {
|
|
|
429
660
|
subscribe(callback) {
|
|
430
661
|
return this._store.subscribe(callback);
|
|
431
662
|
}
|
|
432
|
-
/**
|
|
433
|
-
* @private Only used by the E2E test suite.
|
|
434
|
-
*/
|
|
435
|
-
_subscribeOptimisticUpdates(callback) {
|
|
436
|
-
return this.subscribe(callback);
|
|
437
|
-
}
|
|
438
|
-
subscribeThreads(callback) {
|
|
439
|
-
return this.subscribe(callback);
|
|
440
|
-
}
|
|
441
|
-
subscribeUserThreads(callback) {
|
|
442
|
-
return this.subscribe(callback);
|
|
443
|
-
}
|
|
444
|
-
subscribeThreadsOrInboxNotifications(callback) {
|
|
445
|
-
return this.subscribe(callback);
|
|
446
|
-
}
|
|
447
|
-
subscribeNotificationSettings(callback) {
|
|
448
|
-
return this.subscribe(callback);
|
|
449
|
-
}
|
|
450
|
-
subscribeVersions(callback) {
|
|
451
|
-
return this.subscribe(callback);
|
|
452
|
-
}
|
|
453
663
|
// Direct low-level cache mutations ------------------------------------------------- {{{
|
|
454
|
-
|
|
455
|
-
this.
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
664
|
+
mutateThreadsDB(mutate) {
|
|
665
|
+
const db = this._rawThreadsDB;
|
|
666
|
+
const old = db.version;
|
|
667
|
+
mutate(db);
|
|
668
|
+
if (old !== db.version) {
|
|
669
|
+
this._store.set((state) => ({ ...state }));
|
|
670
|
+
}
|
|
459
671
|
}
|
|
460
672
|
updateInboxNotificationsCache(mapFn) {
|
|
461
673
|
this._store.set((state) => {
|
|
@@ -472,32 +684,23 @@ var UmbrellaStore = class {
|
|
|
472
684
|
}
|
|
473
685
|
}));
|
|
474
686
|
}
|
|
475
|
-
|
|
476
|
-
this._store.set((state) =>
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
})
|
|
492
|
-
}
|
|
493
|
-
setQuery4State(queryKey, queryState) {
|
|
494
|
-
this._store.set((state) => ({
|
|
495
|
-
...state,
|
|
496
|
-
queries4: {
|
|
497
|
-
...state.queries4,
|
|
498
|
-
[queryKey]: queryState
|
|
499
|
-
}
|
|
500
|
-
}));
|
|
687
|
+
updateRoomVersions(roomId, versions) {
|
|
688
|
+
this._store.set((state) => {
|
|
689
|
+
const versionsById = Object.fromEntries(
|
|
690
|
+
versions.map((version2) => [version2.id, version2])
|
|
691
|
+
);
|
|
692
|
+
return {
|
|
693
|
+
...state,
|
|
694
|
+
versionsByRoomId: {
|
|
695
|
+
...state.versionsByRoomId,
|
|
696
|
+
[roomId]: {
|
|
697
|
+
// Merge with existing versions for the room, or start with an empty object
|
|
698
|
+
...state.versionsByRoomId[roomId] ?? {},
|
|
699
|
+
...versionsById
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
});
|
|
501
704
|
}
|
|
502
705
|
updateOptimisticUpdatesCache(mapFn) {
|
|
503
706
|
this._store.set((state) => ({
|
|
@@ -572,7 +775,7 @@ var UmbrellaStore = class {
|
|
|
572
775
|
createThread(optimisticUpdateId, thread) {
|
|
573
776
|
this._store.batch(() => {
|
|
574
777
|
this.removeOptimisticUpdate(optimisticUpdateId);
|
|
575
|
-
this.
|
|
778
|
+
this.mutateThreadsDB((db) => db.upsert(thread));
|
|
576
779
|
});
|
|
577
780
|
}
|
|
578
781
|
/**
|
|
@@ -590,18 +793,11 @@ var UmbrellaStore = class {
|
|
|
590
793
|
if (optimisticUpdateId !== null) {
|
|
591
794
|
this.removeOptimisticUpdate(optimisticUpdateId);
|
|
592
795
|
}
|
|
593
|
-
this.
|
|
594
|
-
const existing =
|
|
595
|
-
if (!existing)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
if (existing.deletedAt !== void 0) {
|
|
599
|
-
return cache;
|
|
600
|
-
}
|
|
601
|
-
if (!!updatedAt && existing.updatedAt > updatedAt) {
|
|
602
|
-
return cache;
|
|
603
|
-
}
|
|
604
|
-
return { ...cache, [threadId]: callback(existing) };
|
|
796
|
+
this.mutateThreadsDB((db) => {
|
|
797
|
+
const existing = db.get(threadId);
|
|
798
|
+
if (!existing) return;
|
|
799
|
+
if (!!updatedAt && existing.updatedAt > updatedAt) return;
|
|
800
|
+
db.upsert(callback(existing));
|
|
605
801
|
});
|
|
606
802
|
});
|
|
607
803
|
}
|
|
@@ -652,14 +848,13 @@ var UmbrellaStore = class {
|
|
|
652
848
|
createComment(newComment, optimisticUpdateId) {
|
|
653
849
|
this._store.batch(() => {
|
|
654
850
|
this.removeOptimisticUpdate(optimisticUpdateId);
|
|
655
|
-
const existingThread = this.
|
|
851
|
+
const existingThread = this._rawThreadsDB.get(newComment.threadId);
|
|
656
852
|
if (!existingThread) {
|
|
657
853
|
return;
|
|
658
854
|
}
|
|
659
|
-
this.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
}));
|
|
855
|
+
this.mutateThreadsDB(
|
|
856
|
+
(db) => db.upsert(applyUpsertComment(existingThread, newComment))
|
|
857
|
+
);
|
|
663
858
|
this.updateInboxNotificationsCache((cache) => {
|
|
664
859
|
const existingNotification = Object.values(cache).find(
|
|
665
860
|
(notification) => notification.kind === "thread" && notification.threadId === newComment.threadId
|
|
@@ -695,10 +890,7 @@ var UmbrellaStore = class {
|
|
|
695
890
|
}
|
|
696
891
|
updateThreadAndNotification(thread, inboxNotification) {
|
|
697
892
|
this._store.batch(() => {
|
|
698
|
-
this.
|
|
699
|
-
const existingThread = cache[thread.id];
|
|
700
|
-
return existingThread === void 0 || isMoreRecentlyUpdated(thread, existingThread) ? { ...cache, [thread.id]: thread } : cache;
|
|
701
|
-
});
|
|
893
|
+
this.mutateThreadsDB((db) => db.upsertIfNewer(thread));
|
|
702
894
|
if (inboxNotification !== void 0) {
|
|
703
895
|
this.updateInboxNotificationsCache((cache) => ({
|
|
704
896
|
...cache,
|
|
@@ -709,11 +901,8 @@ var UmbrellaStore = class {
|
|
|
709
901
|
}
|
|
710
902
|
updateThreadsAndNotifications(threads, inboxNotifications, deletedThreads = [], deletedInboxNotifications = []) {
|
|
711
903
|
this._store.batch(() => {
|
|
712
|
-
this.
|
|
713
|
-
(
|
|
714
|
-
newThreads: threads,
|
|
715
|
-
deletedThreads
|
|
716
|
-
})
|
|
904
|
+
this.mutateThreadsDB(
|
|
905
|
+
(db) => applyThreadDeltaUpdates(db, { newThreads: threads, deletedThreads })
|
|
717
906
|
);
|
|
718
907
|
this.updateInboxNotificationsCache(
|
|
719
908
|
(cache) => applyNotificationsUpdates(cache, {
|
|
@@ -727,28 +916,12 @@ var UmbrellaStore = class {
|
|
|
727
916
|
* Updates existing notification setting for a room with a new value,
|
|
728
917
|
* replacing the corresponding optimistic update.
|
|
729
918
|
*/
|
|
730
|
-
|
|
731
|
-
updateRoomInboxNotificationSettings2(roomId, optimisticUpdateId, settings) {
|
|
919
|
+
updateRoomNotificationSettings_confirmOptimisticUpdate(roomId, optimisticUpdateId, settings) {
|
|
732
920
|
this._store.batch(() => {
|
|
733
921
|
this.removeOptimisticUpdate(optimisticUpdateId);
|
|
734
922
|
this.setNotificationSettings(roomId, settings);
|
|
735
923
|
});
|
|
736
924
|
}
|
|
737
|
-
// XXXX Rename this helper method
|
|
738
|
-
updateRoomInboxNotificationSettings(roomId, settings, queryKey) {
|
|
739
|
-
this._store.batch(() => {
|
|
740
|
-
this.setQuery3OK(queryKey);
|
|
741
|
-
this.setNotificationSettings(roomId, settings);
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
updateRoomVersions(roomId, versions, queryKey) {
|
|
745
|
-
this._store.batch(() => {
|
|
746
|
-
this.setVersions(roomId, versions);
|
|
747
|
-
if (queryKey !== void 0) {
|
|
748
|
-
this.setQuery4OK(queryKey);
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
925
|
addOptimisticUpdate(optimisticUpdate) {
|
|
753
926
|
const id = nanoid();
|
|
754
927
|
const newUpdate = { ...optimisticUpdate, id };
|
|
@@ -760,36 +933,15 @@ var UmbrellaStore = class {
|
|
|
760
933
|
(cache) => cache.filter((ou) => ou.id !== optimisticUpdateId)
|
|
761
934
|
);
|
|
762
935
|
}
|
|
763
|
-
|
|
764
|
-
setQuery3Loading(queryKey) {
|
|
765
|
-
this.setQuery3State(queryKey, ASYNC_LOADING);
|
|
766
|
-
}
|
|
767
|
-
setQuery3OK(queryKey) {
|
|
768
|
-
this.setQuery3State(queryKey, ASYNC_OK);
|
|
769
|
-
}
|
|
770
|
-
setQuery3Error(queryKey, error) {
|
|
771
|
-
this.setQuery3State(queryKey, { isLoading: false, error });
|
|
772
|
-
}
|
|
773
|
-
// Query 4
|
|
774
|
-
setQuery4Loading(queryKey) {
|
|
775
|
-
this.setQuery4State(queryKey, ASYNC_LOADING);
|
|
776
|
-
}
|
|
777
|
-
setQuery4OK(queryKey) {
|
|
778
|
-
this.setQuery4State(queryKey, ASYNC_OK);
|
|
779
|
-
}
|
|
780
|
-
setQuery4Error(queryKey, error) {
|
|
781
|
-
this.setQuery4State(queryKey, { isLoading: false, error });
|
|
782
|
-
}
|
|
783
|
-
async fetchNotificationsDeltaUpdate() {
|
|
936
|
+
async fetchNotificationsDeltaUpdate(signal) {
|
|
784
937
|
const lastRequestedAt = this._notificationsLastRequestedAt;
|
|
785
938
|
if (lastRequestedAt === null) {
|
|
786
939
|
return;
|
|
787
940
|
}
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
);
|
|
792
|
-
const result = await client.getInboxNotificationsSince(lastRequestedAt);
|
|
941
|
+
const result = await this._client.getInboxNotificationsSince({
|
|
942
|
+
since: lastRequestedAt,
|
|
943
|
+
signal
|
|
944
|
+
});
|
|
793
945
|
if (lastRequestedAt < result.requestedAt) {
|
|
794
946
|
this._notificationsLastRequestedAt = result.requestedAt;
|
|
795
947
|
}
|
|
@@ -805,21 +957,13 @@ var UmbrellaStore = class {
|
|
|
805
957
|
}
|
|
806
958
|
waitUntilRoomThreadsLoaded(roomId, query) {
|
|
807
959
|
const threadsFetcher = async (cursor) => {
|
|
808
|
-
if (this._client === void 0) {
|
|
809
|
-
throw new StopRetrying(
|
|
810
|
-
"Client is required in order to load threads for the room"
|
|
811
|
-
);
|
|
812
|
-
}
|
|
813
960
|
const room = this._client.getRoom(roomId);
|
|
814
961
|
if (room === null) {
|
|
815
|
-
throw new
|
|
816
|
-
`Room with id ${roomId} is not available on client`
|
|
817
|
-
);
|
|
962
|
+
throw new HttpError(`Room '${roomId}' is not available on client`, 479);
|
|
818
963
|
}
|
|
819
964
|
const result = await room.getThreads({ cursor, query });
|
|
820
965
|
this.updateThreadsAndNotifications(
|
|
821
966
|
result.threads,
|
|
822
|
-
// TODO: Figure out how to remove this casting
|
|
823
967
|
result.inboxNotifications
|
|
824
968
|
);
|
|
825
969
|
const lastRequestedAt = this._roomThreadsLastRequestedAtByRoom.get(roomId);
|
|
@@ -843,21 +987,18 @@ var UmbrellaStore = class {
|
|
|
843
987
|
this._roomThreads.set(queryKey, paginatedResource);
|
|
844
988
|
return paginatedResource.waitUntilLoaded();
|
|
845
989
|
}
|
|
846
|
-
async fetchRoomThreadsDeltaUpdate(roomId) {
|
|
990
|
+
async fetchRoomThreadsDeltaUpdate(roomId, signal) {
|
|
847
991
|
const lastRequestedAt = this._roomThreadsLastRequestedAtByRoom.get(roomId);
|
|
848
992
|
if (lastRequestedAt === void 0) {
|
|
849
993
|
return;
|
|
850
994
|
}
|
|
851
|
-
const client = nn(
|
|
852
|
-
this._client,
|
|
853
|
-
"Client is required in order to load notifications for the room"
|
|
854
|
-
);
|
|
855
995
|
const room = nn(
|
|
856
|
-
|
|
996
|
+
this._client.getRoom(roomId),
|
|
857
997
|
`Room with id ${roomId} is not available on client`
|
|
858
998
|
);
|
|
859
999
|
const updates = await room.getThreadsSince({
|
|
860
|
-
since: lastRequestedAt
|
|
1000
|
+
since: lastRequestedAt,
|
|
1001
|
+
signal
|
|
861
1002
|
});
|
|
862
1003
|
this.updateThreadsAndNotifications(
|
|
863
1004
|
updates.threads.updated,
|
|
@@ -872,18 +1013,12 @@ var UmbrellaStore = class {
|
|
|
872
1013
|
waitUntilUserThreadsLoaded(query) {
|
|
873
1014
|
const queryKey = makeUserThreadsQueryKey(query);
|
|
874
1015
|
const threadsFetcher = async (cursor) => {
|
|
875
|
-
if (this._client === void 0) {
|
|
876
|
-
throw new StopRetrying(
|
|
877
|
-
"Client is required in order to load threads for the room"
|
|
878
|
-
);
|
|
879
|
-
}
|
|
880
1016
|
const result = await this._client[kInternal].getUserThreads_experimental({
|
|
881
1017
|
cursor,
|
|
882
1018
|
query
|
|
883
1019
|
});
|
|
884
1020
|
this.updateThreadsAndNotifications(
|
|
885
1021
|
result.threads,
|
|
886
|
-
// TODO: Figure out how to remove this casting
|
|
887
1022
|
result.inboxNotifications
|
|
888
1023
|
);
|
|
889
1024
|
if (this._userThreadsLastRequestedAt === null) {
|
|
@@ -905,17 +1040,14 @@ var UmbrellaStore = class {
|
|
|
905
1040
|
this._userThreads.set(queryKey, paginatedResource);
|
|
906
1041
|
return paginatedResource.waitUntilLoaded();
|
|
907
1042
|
}
|
|
908
|
-
async fetchUserThreadsDeltaUpdate() {
|
|
1043
|
+
async fetchUserThreadsDeltaUpdate(signal) {
|
|
909
1044
|
const lastRequestedAt = this._userThreadsLastRequestedAt;
|
|
910
1045
|
if (lastRequestedAt === null) {
|
|
911
1046
|
return;
|
|
912
1047
|
}
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
);
|
|
917
|
-
const result = await client[kInternal].getUserThreadsSince_experimental({
|
|
918
|
-
since: lastRequestedAt
|
|
1048
|
+
const result = await this._client[kInternal].getUserThreadsSince_experimental({
|
|
1049
|
+
since: lastRequestedAt,
|
|
1050
|
+
signal
|
|
919
1051
|
});
|
|
920
1052
|
if (lastRequestedAt < result.requestedAt) {
|
|
921
1053
|
this._notificationsLastRequestedAt = result.requestedAt;
|
|
@@ -927,77 +1059,138 @@ var UmbrellaStore = class {
|
|
|
927
1059
|
result.inboxNotifications.deleted
|
|
928
1060
|
);
|
|
929
1061
|
}
|
|
1062
|
+
waitUntilRoomVersionsLoaded(roomId) {
|
|
1063
|
+
const queryKey = makeVersionsQueryKey(roomId);
|
|
1064
|
+
let resource = this._roomVersions.get(queryKey);
|
|
1065
|
+
if (resource === void 0) {
|
|
1066
|
+
const versionsFetcher = async () => {
|
|
1067
|
+
const room = this._client.getRoom(roomId);
|
|
1068
|
+
if (room === null) {
|
|
1069
|
+
throw new HttpError(
|
|
1070
|
+
`Room '${roomId}' is not available on client`,
|
|
1071
|
+
479
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
const result = await room[kInternal].listTextVersions();
|
|
1075
|
+
this.updateRoomVersions(roomId, result.versions);
|
|
1076
|
+
const lastRequestedAt = this._roomVersionsLastRequestedAtByRoom.get(roomId);
|
|
1077
|
+
if (lastRequestedAt === void 0 || lastRequestedAt > result.requestedAt) {
|
|
1078
|
+
this._roomVersionsLastRequestedAtByRoom.set(
|
|
1079
|
+
roomId,
|
|
1080
|
+
result.requestedAt
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
resource = new SinglePageResource(versionsFetcher);
|
|
1085
|
+
}
|
|
1086
|
+
resource.observable.subscribe(
|
|
1087
|
+
() => (
|
|
1088
|
+
// Note that the store itself does not change, but it's only vehicle at
|
|
1089
|
+
// the moment to trigger a re-render, so we'll do a no-op update here.
|
|
1090
|
+
this._store.set((store) => ({ ...store }))
|
|
1091
|
+
)
|
|
1092
|
+
);
|
|
1093
|
+
this._roomVersions.set(queryKey, resource);
|
|
1094
|
+
return resource.waitUntilLoaded();
|
|
1095
|
+
}
|
|
1096
|
+
async fetchRoomVersionsDeltaUpdate(roomId, signal) {
|
|
1097
|
+
const lastRequestedAt = this._roomVersionsLastRequestedAtByRoom.get(roomId);
|
|
1098
|
+
if (lastRequestedAt === void 0) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
const room = nn(
|
|
1102
|
+
this._client.getRoom(roomId),
|
|
1103
|
+
`Room with id ${roomId} is not available on client`
|
|
1104
|
+
);
|
|
1105
|
+
const updates = await room[kInternal].listTextVersionsSince({
|
|
1106
|
+
since: lastRequestedAt,
|
|
1107
|
+
signal
|
|
1108
|
+
});
|
|
1109
|
+
this.updateRoomVersions(roomId, updates.versions);
|
|
1110
|
+
if (lastRequestedAt < updates.requestedAt) {
|
|
1111
|
+
this._roomVersionsLastRequestedAtByRoom.set(roomId, updates.requestedAt);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
waitUntilRoomNotificationSettingsLoaded(roomId) {
|
|
1115
|
+
const queryKey = makeNotificationSettingsQueryKey(roomId);
|
|
1116
|
+
let resource = this._roomNotificationSettings.get(queryKey);
|
|
1117
|
+
if (resource === void 0) {
|
|
1118
|
+
const notificationSettingsFetcher = async () => {
|
|
1119
|
+
const room = this._client.getRoom(roomId);
|
|
1120
|
+
if (room === null) {
|
|
1121
|
+
throw new HttpError(
|
|
1122
|
+
`Room '${roomId}' is not available on client`,
|
|
1123
|
+
479
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
const result = await room.getNotificationSettings();
|
|
1127
|
+
this.setNotificationSettings(roomId, result);
|
|
1128
|
+
};
|
|
1129
|
+
resource = new SinglePageResource(notificationSettingsFetcher);
|
|
1130
|
+
}
|
|
1131
|
+
resource.observable.subscribe(
|
|
1132
|
+
() => (
|
|
1133
|
+
// Note that the store itself does not change, but it's only vehicle at
|
|
1134
|
+
// the moment to trigger a re-render, so we'll do a no-op update here.
|
|
1135
|
+
this._store.set((store) => ({ ...store }))
|
|
1136
|
+
)
|
|
1137
|
+
);
|
|
1138
|
+
this._roomNotificationSettings.set(queryKey, resource);
|
|
1139
|
+
return resource.waitUntilLoaded();
|
|
1140
|
+
}
|
|
1141
|
+
async refreshRoomNotificationSettings(roomId, signal) {
|
|
1142
|
+
const room = nn(
|
|
1143
|
+
this._client.getRoom(roomId),
|
|
1144
|
+
`Room with id ${roomId} is not available on client`
|
|
1145
|
+
);
|
|
1146
|
+
const result = await room.getNotificationSettings({ signal });
|
|
1147
|
+
this.setNotificationSettings(roomId, result);
|
|
1148
|
+
}
|
|
930
1149
|
};
|
|
931
|
-
function internalToExternalState(state) {
|
|
1150
|
+
function internalToExternalState(state, rawThreadsDB) {
|
|
1151
|
+
const threadsDB = rawThreadsDB.clone();
|
|
932
1152
|
const computed = {
|
|
933
|
-
threadsById: { ...state.rawThreadsById },
|
|
934
1153
|
notificationsById: { ...state.notificationsById },
|
|
935
1154
|
settingsByRoomId: { ...state.settingsByRoomId }
|
|
936
1155
|
};
|
|
937
1156
|
for (const optimisticUpdate of state.optimisticUpdates) {
|
|
938
1157
|
switch (optimisticUpdate.type) {
|
|
939
1158
|
case "create-thread": {
|
|
940
|
-
|
|
1159
|
+
threadsDB.upsert(optimisticUpdate.thread);
|
|
941
1160
|
break;
|
|
942
1161
|
}
|
|
943
1162
|
case "edit-thread-metadata": {
|
|
944
|
-
const thread =
|
|
945
|
-
if (thread === void 0)
|
|
946
|
-
break;
|
|
947
|
-
}
|
|
948
|
-
if (thread.deletedAt !== void 0) {
|
|
949
|
-
break;
|
|
950
|
-
}
|
|
1163
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1164
|
+
if (thread === void 0) break;
|
|
951
1165
|
if (thread.updatedAt > optimisticUpdate.updatedAt) {
|
|
952
1166
|
break;
|
|
953
1167
|
}
|
|
954
|
-
|
|
1168
|
+
threadsDB.upsert({
|
|
955
1169
|
...thread,
|
|
956
1170
|
updatedAt: optimisticUpdate.updatedAt,
|
|
957
1171
|
metadata: {
|
|
958
1172
|
...thread.metadata,
|
|
959
1173
|
...optimisticUpdate.metadata
|
|
960
1174
|
}
|
|
961
|
-
};
|
|
1175
|
+
});
|
|
962
1176
|
break;
|
|
963
1177
|
}
|
|
964
1178
|
case "mark-thread-as-resolved": {
|
|
965
|
-
const thread =
|
|
966
|
-
if (thread === void 0)
|
|
967
|
-
|
|
968
|
-
}
|
|
969
|
-
if (thread.deletedAt !== void 0) {
|
|
970
|
-
break;
|
|
971
|
-
}
|
|
972
|
-
computed.threadsById[thread.id] = {
|
|
973
|
-
...thread,
|
|
974
|
-
resolved: true
|
|
975
|
-
};
|
|
1179
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1180
|
+
if (thread === void 0) break;
|
|
1181
|
+
threadsDB.upsert({ ...thread, resolved: true });
|
|
976
1182
|
break;
|
|
977
1183
|
}
|
|
978
1184
|
case "mark-thread-as-unresolved": {
|
|
979
|
-
const thread =
|
|
980
|
-
if (thread === void 0)
|
|
981
|
-
|
|
982
|
-
}
|
|
983
|
-
if (thread.deletedAt !== void 0) {
|
|
984
|
-
break;
|
|
985
|
-
}
|
|
986
|
-
computed.threadsById[thread.id] = {
|
|
987
|
-
...thread,
|
|
988
|
-
resolved: false
|
|
989
|
-
};
|
|
1185
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1186
|
+
if (thread === void 0) break;
|
|
1187
|
+
threadsDB.upsert({ ...thread, resolved: false });
|
|
990
1188
|
break;
|
|
991
1189
|
}
|
|
992
1190
|
case "create-comment": {
|
|
993
|
-
const thread =
|
|
994
|
-
if (thread === void 0)
|
|
995
|
-
|
|
996
|
-
}
|
|
997
|
-
computed.threadsById[thread.id] = applyUpsertComment(
|
|
998
|
-
thread,
|
|
999
|
-
optimisticUpdate.comment
|
|
1000
|
-
);
|
|
1191
|
+
const thread = threadsDB.get(optimisticUpdate.comment.threadId);
|
|
1192
|
+
if (thread === void 0) break;
|
|
1193
|
+
threadsDB.upsert(applyUpsertComment(thread, optimisticUpdate.comment));
|
|
1001
1194
|
const inboxNotification = Object.values(
|
|
1002
1195
|
computed.notificationsById
|
|
1003
1196
|
).find(
|
|
@@ -1012,66 +1205,59 @@ function internalToExternalState(state) {
|
|
|
1012
1205
|
readAt: optimisticUpdate.comment.createdAt
|
|
1013
1206
|
};
|
|
1014
1207
|
break;
|
|
1015
|
-
}
|
|
1016
|
-
case "edit-comment": {
|
|
1017
|
-
const thread =
|
|
1018
|
-
if (thread === void 0)
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1021
|
-
computed.threadsById[thread.id] = applyUpsertComment(
|
|
1022
|
-
thread,
|
|
1023
|
-
optimisticUpdate.comment
|
|
1024
|
-
);
|
|
1208
|
+
}
|
|
1209
|
+
case "edit-comment": {
|
|
1210
|
+
const thread = threadsDB.get(optimisticUpdate.comment.threadId);
|
|
1211
|
+
if (thread === void 0) break;
|
|
1212
|
+
threadsDB.upsert(applyUpsertComment(thread, optimisticUpdate.comment));
|
|
1025
1213
|
break;
|
|
1026
1214
|
}
|
|
1027
1215
|
case "delete-comment": {
|
|
1028
|
-
const thread =
|
|
1029
|
-
if (thread === void 0)
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1216
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1217
|
+
if (thread === void 0) break;
|
|
1218
|
+
threadsDB.upsert(
|
|
1219
|
+
applyDeleteComment(
|
|
1220
|
+
thread,
|
|
1221
|
+
optimisticUpdate.commentId,
|
|
1222
|
+
optimisticUpdate.deletedAt
|
|
1223
|
+
)
|
|
1036
1224
|
);
|
|
1037
1225
|
break;
|
|
1038
1226
|
}
|
|
1039
1227
|
case "delete-thread": {
|
|
1040
|
-
const thread =
|
|
1041
|
-
if (thread === void 0)
|
|
1042
|
-
|
|
1043
|
-
}
|
|
1044
|
-
computed.threadsById[optimisticUpdate.threadId] = {
|
|
1228
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1229
|
+
if (thread === void 0) break;
|
|
1230
|
+
threadsDB.upsert({
|
|
1045
1231
|
...thread,
|
|
1046
1232
|
deletedAt: optimisticUpdate.deletedAt,
|
|
1047
1233
|
updatedAt: optimisticUpdate.deletedAt,
|
|
1048
1234
|
comments: []
|
|
1049
|
-
};
|
|
1235
|
+
});
|
|
1050
1236
|
break;
|
|
1051
1237
|
}
|
|
1052
1238
|
case "add-reaction": {
|
|
1053
|
-
const thread =
|
|
1054
|
-
if (thread === void 0)
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1239
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1240
|
+
if (thread === void 0) break;
|
|
1241
|
+
threadsDB.upsert(
|
|
1242
|
+
applyAddReaction(
|
|
1243
|
+
thread,
|
|
1244
|
+
optimisticUpdate.commentId,
|
|
1245
|
+
optimisticUpdate.reaction
|
|
1246
|
+
)
|
|
1061
1247
|
);
|
|
1062
1248
|
break;
|
|
1063
1249
|
}
|
|
1064
1250
|
case "remove-reaction": {
|
|
1065
|
-
const thread =
|
|
1066
|
-
if (thread === void 0)
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1251
|
+
const thread = threadsDB.get(optimisticUpdate.threadId);
|
|
1252
|
+
if (thread === void 0) break;
|
|
1253
|
+
threadsDB.upsert(
|
|
1254
|
+
applyRemoveReaction(
|
|
1255
|
+
thread,
|
|
1256
|
+
optimisticUpdate.commentId,
|
|
1257
|
+
optimisticUpdate.emoji,
|
|
1258
|
+
optimisticUpdate.userId,
|
|
1259
|
+
optimisticUpdate.removedAt
|
|
1260
|
+
)
|
|
1075
1261
|
);
|
|
1076
1262
|
break;
|
|
1077
1263
|
}
|
|
@@ -1119,51 +1305,27 @@ function internalToExternalState(state) {
|
|
|
1119
1305
|
}
|
|
1120
1306
|
}
|
|
1121
1307
|
}
|
|
1122
|
-
const cleanedThreads = (
|
|
1123
|
-
// Don't expose any soft-deleted threads
|
|
1124
|
-
Object.values(computed.threadsById).filter((thread) => !thread.deletedAt).filter(
|
|
1125
|
-
(thread) => (
|
|
1126
|
-
// Only keep a thread if there is at least one non-deleted comment
|
|
1127
|
-
thread.comments.some((c) => c.deletedAt === void 0)
|
|
1128
|
-
)
|
|
1129
|
-
)
|
|
1130
|
-
);
|
|
1131
1308
|
const cleanedNotifications = (
|
|
1132
1309
|
// Sort so that the most recent notifications are first
|
|
1133
1310
|
Object.values(computed.notificationsById).filter(
|
|
1134
|
-
(ibn) => ibn.kind === "thread" ?
|
|
1311
|
+
(ibn) => ibn.kind === "thread" ? threadsDB.get(ibn.threadId) !== void 0 : true
|
|
1135
1312
|
).sort((a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime())
|
|
1136
1313
|
);
|
|
1137
1314
|
return {
|
|
1138
|
-
|
|
1315
|
+
cleanedNotifications,
|
|
1139
1316
|
notificationsById: computed.notificationsById,
|
|
1140
1317
|
settingsByRoomId: computed.settingsByRoomId,
|
|
1141
|
-
|
|
1142
|
-
queries4: state.queries4,
|
|
1143
|
-
threads: cleanedThreads,
|
|
1144
|
-
threadsById: computed.threadsById,
|
|
1318
|
+
threadsDB,
|
|
1145
1319
|
versionsByRoomId: state.versionsByRoomId
|
|
1146
1320
|
};
|
|
1147
1321
|
}
|
|
1148
|
-
function
|
|
1149
|
-
|
|
1150
|
-
updates.newThreads.forEach((thread) => {
|
|
1151
|
-
const existingThread = updatedThreads[thread.id];
|
|
1152
|
-
if (existingThread) {
|
|
1153
|
-
if (isMoreRecentlyUpdated(existingThread, thread)) {
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
updatedThreads[thread.id] = thread;
|
|
1158
|
-
});
|
|
1322
|
+
function applyThreadDeltaUpdates(db, updates) {
|
|
1323
|
+
updates.newThreads.forEach((thread) => db.upsertIfNewer(thread));
|
|
1159
1324
|
updates.deletedThreads.forEach(({ id, deletedAt }) => {
|
|
1160
|
-
const
|
|
1161
|
-
if (
|
|
1162
|
-
|
|
1163
|
-
existingThread.updatedAt = deletedAt;
|
|
1164
|
-
existingThread.comments = [];
|
|
1325
|
+
const existing = db.getEvenIfDeleted(id);
|
|
1326
|
+
if (!existing) return;
|
|
1327
|
+
db.delete(id, deletedAt);
|
|
1165
1328
|
});
|
|
1166
|
-
return updatedThreads;
|
|
1167
1329
|
}
|
|
1168
1330
|
function applyNotificationsUpdates(existingInboxNotifications, updates) {
|
|
1169
1331
|
const updatedInboxNotifications = { ...existingInboxNotifications };
|
|
@@ -1361,97 +1523,6 @@ function upsertReaction(reactions, reaction) {
|
|
|
1361
1523
|
return reactions;
|
|
1362
1524
|
}
|
|
1363
1525
|
|
|
1364
|
-
// src/liveblocks.tsx
|
|
1365
|
-
import {
|
|
1366
|
-
assert,
|
|
1367
|
-
createClient,
|
|
1368
|
-
kInternal as kInternal2,
|
|
1369
|
-
makePoller,
|
|
1370
|
-
raise,
|
|
1371
|
-
shallow as shallow3
|
|
1372
|
-
} from "@liveblocks/core";
|
|
1373
|
-
import React3, {
|
|
1374
|
-
createContext as createContext2,
|
|
1375
|
-
useCallback as useCallback2,
|
|
1376
|
-
useContext as useContext2,
|
|
1377
|
-
useEffect as useEffect3,
|
|
1378
|
-
useMemo
|
|
1379
|
-
} from "react";
|
|
1380
|
-
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
1381
|
-
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
|
|
1382
|
-
|
|
1383
|
-
// src/lib/shallow2.ts
|
|
1384
|
-
import { isPlainObject as isPlainObject2, shallow } from "@liveblocks/core";
|
|
1385
|
-
function shallow2(a, b) {
|
|
1386
|
-
if (!isPlainObject2(a) || !isPlainObject2(b)) {
|
|
1387
|
-
return shallow(a, b);
|
|
1388
|
-
}
|
|
1389
|
-
const keysA = Object.keys(a);
|
|
1390
|
-
if (keysA.length !== Object.keys(b).length) {
|
|
1391
|
-
return false;
|
|
1392
|
-
}
|
|
1393
|
-
return keysA.every(
|
|
1394
|
-
(key) => Object.prototype.hasOwnProperty.call(b, key) && shallow(a[key], b[key])
|
|
1395
|
-
);
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
// src/lib/use-initial.ts
|
|
1399
|
-
import { useCallback, useReducer } from "react";
|
|
1400
|
-
|
|
1401
|
-
// src/lib/use-latest.ts
|
|
1402
|
-
import { useEffect as useEffect2, useRef } from "react";
|
|
1403
|
-
function useLatest(value) {
|
|
1404
|
-
const ref = useRef(value);
|
|
1405
|
-
useEffect2(() => {
|
|
1406
|
-
ref.current = value;
|
|
1407
|
-
}, [value]);
|
|
1408
|
-
return ref;
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
// src/lib/use-initial.ts
|
|
1412
|
-
var noop2 = (state) => state;
|
|
1413
|
-
function useInitial(value) {
|
|
1414
|
-
return useReducer(noop2, value)[0];
|
|
1415
|
-
}
|
|
1416
|
-
function useInitialUnlessFunction(latestValue) {
|
|
1417
|
-
const frozenValue = useInitial(latestValue);
|
|
1418
|
-
if (typeof frozenValue === "function") {
|
|
1419
|
-
const ref = useLatest(latestValue);
|
|
1420
|
-
return useCallback((...args) => ref.current(...args), [
|
|
1421
|
-
ref
|
|
1422
|
-
]);
|
|
1423
|
-
} else {
|
|
1424
|
-
return frozenValue;
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
// src/lib/use-polyfill.ts
|
|
1429
|
-
var use = (
|
|
1430
|
-
// React.use ||
|
|
1431
|
-
(promise) => {
|
|
1432
|
-
if (promise.status === "pending") {
|
|
1433
|
-
throw promise;
|
|
1434
|
-
} else if (promise.status === "fulfilled") {
|
|
1435
|
-
return promise.value;
|
|
1436
|
-
} else if (promise.status === "rejected") {
|
|
1437
|
-
throw promise.reason;
|
|
1438
|
-
} else {
|
|
1439
|
-
promise.status = "pending";
|
|
1440
|
-
promise.then(
|
|
1441
|
-
(v) => {
|
|
1442
|
-
promise.status = "fulfilled";
|
|
1443
|
-
promise.value = v;
|
|
1444
|
-
},
|
|
1445
|
-
(e) => {
|
|
1446
|
-
promise.status = "rejected";
|
|
1447
|
-
promise.reason = e;
|
|
1448
|
-
}
|
|
1449
|
-
);
|
|
1450
|
-
throw promise;
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
);
|
|
1454
|
-
|
|
1455
1526
|
// src/liveblocks.tsx
|
|
1456
1527
|
var ClientContext = createContext2(null);
|
|
1457
1528
|
function missingUserError(userId) {
|
|
@@ -1468,7 +1539,6 @@ function identity(x) {
|
|
|
1468
1539
|
var _umbrellaStores = /* @__PURE__ */ new WeakMap();
|
|
1469
1540
|
var _extras = /* @__PURE__ */ new WeakMap();
|
|
1470
1541
|
var _bundles = /* @__PURE__ */ new WeakMap();
|
|
1471
|
-
var POLLING_INTERVAL = 60 * 1e3;
|
|
1472
1542
|
function selectUnreadInboxNotificationsCount(inboxNotifications) {
|
|
1473
1543
|
let count = 0;
|
|
1474
1544
|
for (const notification of inboxNotifications) {
|
|
@@ -1547,61 +1617,36 @@ function getLiveblocksExtrasForClient(client) {
|
|
|
1547
1617
|
}
|
|
1548
1618
|
return extras;
|
|
1549
1619
|
}
|
|
1550
|
-
function makeDeltaPoller_Notifications(store) {
|
|
1551
|
-
const poller = makePoller(async () => {
|
|
1552
|
-
try {
|
|
1553
|
-
await store.waitUntilNotificationsLoaded();
|
|
1554
|
-
await store.fetchNotificationsDeltaUpdate();
|
|
1555
|
-
} catch (err) {
|
|
1556
|
-
console.warn(`Polling new inbox notifications failed: ${String(err)}`);
|
|
1557
|
-
}
|
|
1558
|
-
}, POLLING_INTERVAL);
|
|
1559
|
-
let pollerSubscribers = 0;
|
|
1560
|
-
return () => {
|
|
1561
|
-
pollerSubscribers++;
|
|
1562
|
-
poller.enable(pollerSubscribers > 0);
|
|
1563
|
-
return () => {
|
|
1564
|
-
pollerSubscribers--;
|
|
1565
|
-
poller.enable(pollerSubscribers > 0);
|
|
1566
|
-
};
|
|
1567
|
-
};
|
|
1568
|
-
}
|
|
1569
|
-
function makeDeltaPoller_UserThreads(store) {
|
|
1570
|
-
const poller = makePoller(async () => {
|
|
1571
|
-
try {
|
|
1572
|
-
await store.fetchUserThreadsDeltaUpdate();
|
|
1573
|
-
} catch (err) {
|
|
1574
|
-
console.warn(`Polling new user threads failed: ${String(err)}`);
|
|
1575
|
-
}
|
|
1576
|
-
}, POLLING_INTERVAL);
|
|
1577
|
-
let pollerSubscribers = 0;
|
|
1578
|
-
return () => {
|
|
1579
|
-
pollerSubscribers++;
|
|
1580
|
-
poller.enable(pollerSubscribers > 0);
|
|
1581
|
-
return () => {
|
|
1582
|
-
pollerSubscribers--;
|
|
1583
|
-
poller.enable(pollerSubscribers > 0);
|
|
1584
|
-
};
|
|
1585
|
-
};
|
|
1586
|
-
}
|
|
1587
1620
|
function makeLiveblocksExtrasForClient(client) {
|
|
1588
1621
|
const store = getUmbrellaStoreForClient(client);
|
|
1622
|
+
const notificationsPoller = makePoller(
|
|
1623
|
+
async (signal) => {
|
|
1624
|
+
try {
|
|
1625
|
+
return await store.fetchNotificationsDeltaUpdate(signal);
|
|
1626
|
+
} catch (err) {
|
|
1627
|
+
console.warn(`Polling new inbox notifications failed: ${String(err)}`);
|
|
1628
|
+
throw err;
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
config.NOTIFICATIONS_POLL_INTERVAL,
|
|
1632
|
+
{ maxStaleTimeMs: config.NOTIFICATIONS_MAX_STALE_TIME }
|
|
1633
|
+
);
|
|
1634
|
+
const userThreadsPoller = makePoller(
|
|
1635
|
+
async (signal) => {
|
|
1636
|
+
try {
|
|
1637
|
+
return await store.fetchUserThreadsDeltaUpdate(signal);
|
|
1638
|
+
} catch (err) {
|
|
1639
|
+
console.warn(`Polling new user threads failed: ${String(err)}`);
|
|
1640
|
+
throw err;
|
|
1641
|
+
}
|
|
1642
|
+
},
|
|
1643
|
+
config.USER_THREADS_POLL_INTERVAL,
|
|
1644
|
+
{ maxStaleTimeMs: config.USER_THREADS_MAX_STALE_TIME }
|
|
1645
|
+
);
|
|
1589
1646
|
return {
|
|
1590
1647
|
store,
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
* notifications through a stream of delta updates. Call the unsub function
|
|
1594
|
-
* returned to stop this subscription when unmounting. Currently
|
|
1595
|
-
* implemented by a periodic poller.
|
|
1596
|
-
*/
|
|
1597
|
-
subscribeToNotificationsDeltaUpdates: makeDeltaPoller_Notifications(store),
|
|
1598
|
-
/**
|
|
1599
|
-
* Sub/unsub pair to start the process of watching for new user threads
|
|
1600
|
-
* through a stream of delta updates. Call the unsub function returned to
|
|
1601
|
-
* stop this subscription when unmounting. Currently implemented by
|
|
1602
|
-
* a periodic poller.
|
|
1603
|
-
*/
|
|
1604
|
-
subscribeToUserThreadsDeltaUpdates: makeDeltaPoller_UserThreads(store)
|
|
1648
|
+
notificationsPoller,
|
|
1649
|
+
userThreadsPoller
|
|
1605
1650
|
};
|
|
1606
1651
|
}
|
|
1607
1652
|
function makeLiveblocksContextBundle(client) {
|
|
@@ -1612,7 +1657,7 @@ function makeLiveblocksContextBundle(client) {
|
|
|
1612
1657
|
const useDeleteAllInboxNotifications2 = () => useDeleteAllInboxNotifications_withClient(client);
|
|
1613
1658
|
function LiveblocksProvider2(props) {
|
|
1614
1659
|
useEnsureNoLiveblocksProvider();
|
|
1615
|
-
return /* @__PURE__ */
|
|
1660
|
+
return /* @__PURE__ */ React2.createElement(ClientContext.Provider, { value: client }, props.children);
|
|
1616
1661
|
}
|
|
1617
1662
|
const shared = createSharedContext(client);
|
|
1618
1663
|
const bundle = {
|
|
@@ -1642,19 +1687,21 @@ function makeLiveblocksContextBundle(client) {
|
|
|
1642
1687
|
return bundle;
|
|
1643
1688
|
}
|
|
1644
1689
|
function useInboxNotifications_withClient(client, selector, isEqual) {
|
|
1645
|
-
const {
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
} = getLiveblocksExtrasForClient(client);
|
|
1649
|
-
useEffect3(() => {
|
|
1650
|
-
void store.waitUntilNotificationsLoaded().catch(() => {
|
|
1651
|
-
});
|
|
1690
|
+
const { store, notificationsPoller: poller } = getLiveblocksExtrasForClient(client);
|
|
1691
|
+
useEffect2(() => {
|
|
1692
|
+
void store.waitUntilNotificationsLoaded();
|
|
1652
1693
|
});
|
|
1653
|
-
|
|
1694
|
+
useEffect2(() => {
|
|
1695
|
+
poller.inc();
|
|
1696
|
+
poller.pollNowIfStale();
|
|
1697
|
+
return () => {
|
|
1698
|
+
poller.dec();
|
|
1699
|
+
};
|
|
1700
|
+
}, [poller]);
|
|
1654
1701
|
return useSyncExternalStoreWithSelector(
|
|
1655
|
-
store.
|
|
1656
|
-
store.
|
|
1657
|
-
store.
|
|
1702
|
+
store.subscribe,
|
|
1703
|
+
store.getInboxNotificationsLoadingState,
|
|
1704
|
+
store.getInboxNotificationsLoadingState,
|
|
1658
1705
|
selector,
|
|
1659
1706
|
isEqual
|
|
1660
1707
|
);
|
|
@@ -1783,7 +1830,7 @@ function useInboxNotificationThread_withClient(client, inboxNotificationId) {
|
|
|
1783
1830
|
`Inbox notification with ID "${inboxNotificationId}" is not of kind "thread"`
|
|
1784
1831
|
);
|
|
1785
1832
|
}
|
|
1786
|
-
const thread = state.
|
|
1833
|
+
const thread = state.threadsDB.get(inboxNotification.threadId) ?? raise(
|
|
1787
1834
|
`Thread with ID "${inboxNotification.threadId}" not found, this inbox notification might not be of kind "thread"`
|
|
1788
1835
|
);
|
|
1789
1836
|
return thread;
|
|
@@ -1791,7 +1838,7 @@ function useInboxNotificationThread_withClient(client, inboxNotificationId) {
|
|
|
1791
1838
|
[inboxNotificationId]
|
|
1792
1839
|
);
|
|
1793
1840
|
return useSyncExternalStoreWithSelector(
|
|
1794
|
-
store.
|
|
1841
|
+
store.subscribe,
|
|
1795
1842
|
// Re-evaluate if we need to update any time the notification changes over time
|
|
1796
1843
|
getter,
|
|
1797
1844
|
getter,
|
|
@@ -1804,20 +1851,21 @@ function useUser_withClient(client, userId) {
|
|
|
1804
1851
|
() => usersStore.getState(userId),
|
|
1805
1852
|
[usersStore, userId]
|
|
1806
1853
|
);
|
|
1807
|
-
useEffect3(() => {
|
|
1808
|
-
void usersStore.get(userId);
|
|
1809
|
-
}, [usersStore, userId]);
|
|
1810
1854
|
const selector = useCallback2(
|
|
1811
1855
|
(state) => selectorFor_useUser(state, userId),
|
|
1812
1856
|
[userId]
|
|
1813
1857
|
);
|
|
1814
|
-
|
|
1858
|
+
const result = useSyncExternalStoreWithSelector(
|
|
1815
1859
|
usersStore.subscribe,
|
|
1816
1860
|
getUserState,
|
|
1817
1861
|
getUserState,
|
|
1818
1862
|
selector,
|
|
1819
1863
|
shallow3
|
|
1820
1864
|
);
|
|
1865
|
+
useEffect2(() => {
|
|
1866
|
+
void usersStore.get(userId);
|
|
1867
|
+
}, [usersStore, userId, result]);
|
|
1868
|
+
return result;
|
|
1821
1869
|
}
|
|
1822
1870
|
function useUserSuspense_withClient(client, userId) {
|
|
1823
1871
|
const usersStore = client[kInternal2].usersStore;
|
|
@@ -1859,16 +1907,17 @@ function useRoomInfo_withClient(client, roomId) {
|
|
|
1859
1907
|
(state) => selectorFor_useRoomInfo(state, roomId),
|
|
1860
1908
|
[roomId]
|
|
1861
1909
|
);
|
|
1862
|
-
|
|
1863
|
-
void roomsInfoStore.get(roomId);
|
|
1864
|
-
}, [roomsInfoStore, roomId]);
|
|
1865
|
-
return useSyncExternalStoreWithSelector(
|
|
1910
|
+
const result = useSyncExternalStoreWithSelector(
|
|
1866
1911
|
roomsInfoStore.subscribe,
|
|
1867
1912
|
getRoomInfoState,
|
|
1868
1913
|
getRoomInfoState,
|
|
1869
1914
|
selector,
|
|
1870
1915
|
shallow3
|
|
1871
1916
|
);
|
|
1917
|
+
useEffect2(() => {
|
|
1918
|
+
void roomsInfoStore.get(roomId);
|
|
1919
|
+
}, [roomsInfoStore, roomId, result]);
|
|
1920
|
+
return result;
|
|
1872
1921
|
}
|
|
1873
1922
|
function useRoomInfoSuspense_withClient(client, roomId) {
|
|
1874
1923
|
const roomsInfoStore = client[kInternal2].roomsInfoStore;
|
|
@@ -1934,7 +1983,7 @@ function useClient() {
|
|
|
1934
1983
|
}
|
|
1935
1984
|
function LiveblocksProviderWithClient(props) {
|
|
1936
1985
|
useEnsureNoLiveblocksProvider(props);
|
|
1937
|
-
return /* @__PURE__ */
|
|
1986
|
+
return /* @__PURE__ */ React2.createElement(ClientContext.Provider, { value: props.client }, props.children);
|
|
1938
1987
|
}
|
|
1939
1988
|
function LiveblocksProvider(props) {
|
|
1940
1989
|
const { children, ...o } = props;
|
|
@@ -1962,7 +2011,7 @@ function LiveblocksProvider(props) {
|
|
|
1962
2011
|
)
|
|
1963
2012
|
};
|
|
1964
2013
|
const client = useMemo(() => createClient(options), []);
|
|
1965
|
-
return /* @__PURE__ */
|
|
2014
|
+
return /* @__PURE__ */ React2.createElement(LiveblocksProviderWithClient, { client }, children);
|
|
1966
2015
|
}
|
|
1967
2016
|
function createLiveblocksContext(client) {
|
|
1968
2017
|
return getOrCreateContextBundle(client);
|
|
@@ -1973,11 +2022,10 @@ function useUserThreads_experimental(options = {
|
|
|
1973
2022
|
}
|
|
1974
2023
|
}) {
|
|
1975
2024
|
const client = useClient();
|
|
1976
|
-
const { store,
|
|
1977
|
-
|
|
2025
|
+
const { store, userThreadsPoller: poller } = getLiveblocksExtrasForClient(client);
|
|
2026
|
+
useEffect2(
|
|
1978
2027
|
() => {
|
|
1979
|
-
void store.waitUntilUserThreadsLoaded(options.query)
|
|
1980
|
-
});
|
|
2028
|
+
void store.waitUntilUserThreadsLoaded(options.query);
|
|
1981
2029
|
}
|
|
1982
2030
|
// NOTE: Deliberately *not* using a dependency array here!
|
|
1983
2031
|
//
|
|
@@ -1988,13 +2036,19 @@ function useUserThreads_experimental(options = {
|
|
|
1988
2036
|
// 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very
|
|
1989
2037
|
// *next* render after that, a *new* fetch/promise will get created.
|
|
1990
2038
|
);
|
|
1991
|
-
|
|
2039
|
+
useEffect2(() => {
|
|
2040
|
+
poller.inc();
|
|
2041
|
+
poller.pollNowIfStale();
|
|
2042
|
+
return () => {
|
|
2043
|
+
poller.dec();
|
|
2044
|
+
};
|
|
2045
|
+
}, [poller]);
|
|
1992
2046
|
const getter = useCallback2(
|
|
1993
|
-
() => store.
|
|
2047
|
+
() => store.getUserThreadsLoadingState(options.query),
|
|
1994
2048
|
[store, options.query]
|
|
1995
2049
|
);
|
|
1996
2050
|
return useSyncExternalStoreWithSelector(
|
|
1997
|
-
store.
|
|
2051
|
+
store.subscribe,
|
|
1998
2052
|
getter,
|
|
1999
2053
|
getter,
|
|
2000
2054
|
identity,
|
|
@@ -2167,34 +2221,22 @@ var UpdateNotificationSettingsError = class extends Error {
|
|
|
2167
2221
|
import { shallow as shallow4 } from "@liveblocks/client";
|
|
2168
2222
|
import {
|
|
2169
2223
|
assert as assert2,
|
|
2170
|
-
CommentsApiError,
|
|
2171
2224
|
console as console3,
|
|
2172
2225
|
createCommentId,
|
|
2173
2226
|
createThreadId,
|
|
2174
2227
|
deprecateIf,
|
|
2175
2228
|
errorIf,
|
|
2229
|
+
HttpError as HttpError2,
|
|
2176
2230
|
kInternal as kInternal3,
|
|
2177
2231
|
makeEventSource as makeEventSource2,
|
|
2178
2232
|
makePoller as makePoller2,
|
|
2179
|
-
NotificationsApiError,
|
|
2180
2233
|
ServerMsgCode
|
|
2181
2234
|
} from "@liveblocks/core";
|
|
2182
|
-
import * as
|
|
2235
|
+
import * as React4 from "react";
|
|
2183
2236
|
import { useSyncExternalStoreWithSelector as useSyncExternalStoreWithSelector2 } from "use-sync-external-store/shim/with-selector.js";
|
|
2184
2237
|
|
|
2185
|
-
// src/lib/retry-error.ts
|
|
2186
|
-
var MAX_ERROR_RETRY_COUNT = 5;
|
|
2187
|
-
var ERROR_RETRY_INTERVAL = 5e3;
|
|
2188
|
-
function retryError(action, retryCount) {
|
|
2189
|
-
if (retryCount >= MAX_ERROR_RETRY_COUNT) return;
|
|
2190
|
-
const timeout = Math.pow(2, retryCount) * ERROR_RETRY_INTERVAL;
|
|
2191
|
-
setTimeout(() => {
|
|
2192
|
-
void action();
|
|
2193
|
-
}, timeout);
|
|
2194
|
-
}
|
|
2195
|
-
|
|
2196
2238
|
// src/use-scroll-to-comment-on-load-effect.ts
|
|
2197
|
-
import * as
|
|
2239
|
+
import * as React3 from "react";
|
|
2198
2240
|
function handleScrollToCommentOnLoad(shouldScrollOnLoad, state) {
|
|
2199
2241
|
if (shouldScrollOnLoad === false) return;
|
|
2200
2242
|
if (!state.threads) return;
|
|
@@ -2213,7 +2255,7 @@ function handleScrollToCommentOnLoad(shouldScrollOnLoad, state) {
|
|
|
2213
2255
|
comment.scrollIntoView();
|
|
2214
2256
|
}
|
|
2215
2257
|
function useScrollToCommentOnLoadEffect(shouldScrollOnLoad, state) {
|
|
2216
|
-
|
|
2258
|
+
React3.useEffect(
|
|
2217
2259
|
() => {
|
|
2218
2260
|
handleScrollToCommentOnLoad(shouldScrollOnLoad, state);
|
|
2219
2261
|
},
|
|
@@ -2243,7 +2285,6 @@ function useSyncExternalStore2(s, gs, gss) {
|
|
|
2243
2285
|
return useSyncExternalStoreWithSelector2(s, gs, gss, identity2);
|
|
2244
2286
|
}
|
|
2245
2287
|
var STABLE_EMPTY_LIST = Object.freeze([]);
|
|
2246
|
-
var POLLING_INTERVAL2 = 5 * 60 * 1e3;
|
|
2247
2288
|
function alwaysEmptyList() {
|
|
2248
2289
|
return STABLE_EMPTY_LIST;
|
|
2249
2290
|
}
|
|
@@ -2298,28 +2339,6 @@ function handleApiError(err) {
|
|
|
2298
2339
|
}
|
|
2299
2340
|
return new Error(message);
|
|
2300
2341
|
}
|
|
2301
|
-
function makeDeltaPoller_RoomThreads(client) {
|
|
2302
|
-
const store = getUmbrellaStoreForClient(client);
|
|
2303
|
-
const poller = makePoller2(async () => {
|
|
2304
|
-
const roomIds = client[kInternal3].getRoomIds();
|
|
2305
|
-
await Promise.allSettled(
|
|
2306
|
-
roomIds.map((roomId) => {
|
|
2307
|
-
const room = client.getRoom(roomId);
|
|
2308
|
-
if (room === null) return;
|
|
2309
|
-
return store.fetchRoomThreadsDeltaUpdate(room.id);
|
|
2310
|
-
})
|
|
2311
|
-
);
|
|
2312
|
-
}, POLLING_INTERVAL2);
|
|
2313
|
-
let pollerSubscribers = 0;
|
|
2314
|
-
return () => {
|
|
2315
|
-
pollerSubscribers++;
|
|
2316
|
-
poller.enable(pollerSubscribers > 0);
|
|
2317
|
-
return () => {
|
|
2318
|
-
pollerSubscribers--;
|
|
2319
|
-
poller.enable(pollerSubscribers > 0);
|
|
2320
|
-
};
|
|
2321
|
-
};
|
|
2322
|
-
}
|
|
2323
2342
|
var _extras2 = /* @__PURE__ */ new WeakMap();
|
|
2324
2343
|
var _bundles2 = /* @__PURE__ */ new WeakMap();
|
|
2325
2344
|
function getOrCreateRoomContextBundle(client) {
|
|
@@ -2340,83 +2359,92 @@ function getRoomExtrasForClient(client) {
|
|
|
2340
2359
|
}
|
|
2341
2360
|
function makeRoomExtrasForClient(client) {
|
|
2342
2361
|
const store = getUmbrellaStoreForClient(client);
|
|
2343
|
-
const requestsByQuery = /* @__PURE__ */ new Map();
|
|
2344
|
-
async function getRoomVersions(room, { retryCount } = { retryCount: 0 }) {
|
|
2345
|
-
const queryKey = makeVersionsQueryKey(room.id);
|
|
2346
|
-
const existingRequest = requestsByQuery.get(queryKey);
|
|
2347
|
-
if (existingRequest !== void 0) return existingRequest;
|
|
2348
|
-
const request = room[kInternal3].listTextVersions();
|
|
2349
|
-
requestsByQuery.set(queryKey, request);
|
|
2350
|
-
store.setQuery4Loading(queryKey);
|
|
2351
|
-
try {
|
|
2352
|
-
const result = await request;
|
|
2353
|
-
const data = await result.json();
|
|
2354
|
-
const versions = data.versions.map(({ createdAt, ...version2 }) => {
|
|
2355
|
-
return {
|
|
2356
|
-
createdAt: new Date(createdAt),
|
|
2357
|
-
...version2
|
|
2358
|
-
};
|
|
2359
|
-
});
|
|
2360
|
-
store.updateRoomVersions(room.id, versions, queryKey);
|
|
2361
|
-
requestsByQuery.delete(queryKey);
|
|
2362
|
-
} catch (err) {
|
|
2363
|
-
requestsByQuery.delete(queryKey);
|
|
2364
|
-
retryError(() => {
|
|
2365
|
-
void getRoomVersions(room, {
|
|
2366
|
-
retryCount: retryCount + 1
|
|
2367
|
-
});
|
|
2368
|
-
}, retryCount);
|
|
2369
|
-
store.setQuery4Error(queryKey, err);
|
|
2370
|
-
}
|
|
2371
|
-
return;
|
|
2372
|
-
}
|
|
2373
|
-
async function getInboxNotificationSettings(room, { retryCount } = { retryCount: 0 }) {
|
|
2374
|
-
const queryKey = makeNotificationSettingsQueryKey(room.id);
|
|
2375
|
-
const existingRequest = requestsByQuery.get(queryKey);
|
|
2376
|
-
if (existingRequest !== void 0) return existingRequest;
|
|
2377
|
-
try {
|
|
2378
|
-
const request = room.getNotificationSettings();
|
|
2379
|
-
requestsByQuery.set(queryKey, request);
|
|
2380
|
-
store.setQuery3Loading(queryKey);
|
|
2381
|
-
const settings = await request;
|
|
2382
|
-
store.updateRoomInboxNotificationSettings(room.id, settings, queryKey);
|
|
2383
|
-
} catch (err) {
|
|
2384
|
-
requestsByQuery.delete(queryKey);
|
|
2385
|
-
retryError(() => {
|
|
2386
|
-
void getInboxNotificationSettings(room, {
|
|
2387
|
-
retryCount: retryCount + 1
|
|
2388
|
-
});
|
|
2389
|
-
}, retryCount);
|
|
2390
|
-
store.setQuery3Error(queryKey, err);
|
|
2391
|
-
}
|
|
2392
|
-
return;
|
|
2393
|
-
}
|
|
2394
2362
|
const commentsErrorEventSource = makeEventSource2();
|
|
2395
2363
|
function onMutationFailure(innerError, optimisticUpdateId, createPublicError) {
|
|
2396
2364
|
store.removeOptimisticUpdate(optimisticUpdateId);
|
|
2397
|
-
if (innerError instanceof
|
|
2365
|
+
if (innerError instanceof HttpError2) {
|
|
2398
2366
|
const error = handleApiError(innerError);
|
|
2399
2367
|
commentsErrorEventSource.notify(createPublicError(error));
|
|
2400
2368
|
return;
|
|
2401
2369
|
}
|
|
2402
|
-
if (innerError instanceof
|
|
2370
|
+
if (innerError instanceof HttpError2) {
|
|
2403
2371
|
handleApiError(innerError);
|
|
2404
2372
|
return;
|
|
2405
2373
|
}
|
|
2406
2374
|
throw innerError;
|
|
2407
2375
|
}
|
|
2376
|
+
const threadsPollersByRoomId = /* @__PURE__ */ new Map();
|
|
2377
|
+
const versionsPollersByRoomId = /* @__PURE__ */ new Map();
|
|
2378
|
+
const roomNotificationSettingsPollersByRoomId = /* @__PURE__ */ new Map();
|
|
2379
|
+
function getOrCreateThreadsPollerForRoomId(roomId) {
|
|
2380
|
+
let poller = threadsPollersByRoomId.get(roomId);
|
|
2381
|
+
if (!poller) {
|
|
2382
|
+
poller = makePoller2(
|
|
2383
|
+
async (signal) => {
|
|
2384
|
+
try {
|
|
2385
|
+
return await store.fetchRoomThreadsDeltaUpdate(roomId, signal);
|
|
2386
|
+
} catch (err) {
|
|
2387
|
+
console3.warn(`Polling new threads for '${roomId}' failed: ${String(err)}`);
|
|
2388
|
+
throw err;
|
|
2389
|
+
}
|
|
2390
|
+
},
|
|
2391
|
+
config.ROOM_THREADS_POLL_INTERVAL,
|
|
2392
|
+
{ maxStaleTimeMs: config.ROOM_THREADS_MAX_STALE_TIME }
|
|
2393
|
+
);
|
|
2394
|
+
threadsPollersByRoomId.set(roomId, poller);
|
|
2395
|
+
}
|
|
2396
|
+
return poller;
|
|
2397
|
+
}
|
|
2398
|
+
function getOrCreateVersionsPollerForRoomId(roomId) {
|
|
2399
|
+
let poller = versionsPollersByRoomId.get(roomId);
|
|
2400
|
+
if (!poller) {
|
|
2401
|
+
poller = makePoller2(
|
|
2402
|
+
async (signal) => {
|
|
2403
|
+
try {
|
|
2404
|
+
return await store.fetchRoomVersionsDeltaUpdate(roomId, signal);
|
|
2405
|
+
} catch (err) {
|
|
2406
|
+
console3.warn(`Polling new history versions for '${roomId}' failed: ${String(err)}`);
|
|
2407
|
+
throw err;
|
|
2408
|
+
}
|
|
2409
|
+
},
|
|
2410
|
+
config.HISTORY_VERSIONS_POLL_INTERVAL,
|
|
2411
|
+
{ maxStaleTimeMs: config.HISTORY_VERSIONS_MAX_STALE_TIME }
|
|
2412
|
+
);
|
|
2413
|
+
versionsPollersByRoomId.set(roomId, poller);
|
|
2414
|
+
}
|
|
2415
|
+
return poller;
|
|
2416
|
+
}
|
|
2417
|
+
function getOrCreateNotificationsSettingsPollerForRoomId(roomId) {
|
|
2418
|
+
let poller = roomNotificationSettingsPollersByRoomId.get(roomId);
|
|
2419
|
+
if (!poller) {
|
|
2420
|
+
poller = makePoller2(
|
|
2421
|
+
async (signal) => {
|
|
2422
|
+
try {
|
|
2423
|
+
return await store.refreshRoomNotificationSettings(roomId, signal);
|
|
2424
|
+
} catch (err) {
|
|
2425
|
+
console3.warn(`Polling notification settings for '${roomId}' failed: ${String(err)}`);
|
|
2426
|
+
throw err;
|
|
2427
|
+
}
|
|
2428
|
+
},
|
|
2429
|
+
config.NOTIFICATION_SETTINGS_POLL_INTERVAL,
|
|
2430
|
+
{ maxStaleTimeMs: config.NOTIFICATION_SETTINGS_MAX_STALE_TIME }
|
|
2431
|
+
);
|
|
2432
|
+
roomNotificationSettingsPollersByRoomId.set(roomId, poller);
|
|
2433
|
+
}
|
|
2434
|
+
return poller;
|
|
2435
|
+
}
|
|
2408
2436
|
return {
|
|
2409
2437
|
store,
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2438
|
+
commentsErrorEventSource: commentsErrorEventSource.observable,
|
|
2439
|
+
onMutationFailure,
|
|
2440
|
+
getOrCreateThreadsPollerForRoomId,
|
|
2441
|
+
getOrCreateVersionsPollerForRoomId,
|
|
2442
|
+
getOrCreateNotificationsSettingsPollerForRoomId
|
|
2415
2443
|
};
|
|
2416
2444
|
}
|
|
2417
2445
|
function makeRoomContextBundle(client) {
|
|
2418
2446
|
function RoomProvider_withImplicitLiveblocksProvider(props) {
|
|
2419
|
-
return /* @__PURE__ */
|
|
2447
|
+
return /* @__PURE__ */ React4.createElement(LiveblocksProviderWithClient, { client, allowNesting: true }, /* @__PURE__ */ React4.createElement(RoomProvider, { ...props }));
|
|
2420
2448
|
}
|
|
2421
2449
|
const shared = createSharedContext(client);
|
|
2422
2450
|
const bundle = {
|
|
@@ -2520,10 +2548,10 @@ function makeRoomContextBundle(client) {
|
|
|
2520
2548
|
}
|
|
2521
2549
|
function RoomProvider(props) {
|
|
2522
2550
|
const client = useClient();
|
|
2523
|
-
const [cache] =
|
|
2551
|
+
const [cache] = React4.useState(
|
|
2524
2552
|
() => /* @__PURE__ */ new Map()
|
|
2525
2553
|
);
|
|
2526
|
-
const stableEnterRoom =
|
|
2554
|
+
const stableEnterRoom = React4.useCallback(
|
|
2527
2555
|
(roomId, options) => {
|
|
2528
2556
|
const cached = cache.get(roomId);
|
|
2529
2557
|
if (cached) return cached;
|
|
@@ -2538,7 +2566,7 @@ function RoomProvider(props) {
|
|
|
2538
2566
|
},
|
|
2539
2567
|
[client, cache]
|
|
2540
2568
|
);
|
|
2541
|
-
return /* @__PURE__ */
|
|
2569
|
+
return /* @__PURE__ */ React4.createElement(
|
|
2542
2570
|
RoomProviderInner,
|
|
2543
2571
|
{
|
|
2544
2572
|
...props,
|
|
@@ -2558,7 +2586,7 @@ function RoomProviderInner(props) {
|
|
|
2558
2586
|
if (!isString(roomId)) {
|
|
2559
2587
|
throw new Error("RoomProvider id property should be a string.");
|
|
2560
2588
|
}
|
|
2561
|
-
const majorReactVersion = parseInt(
|
|
2589
|
+
const majorReactVersion = parseInt(React4.version) || 1;
|
|
2562
2590
|
const oldReactVersion = majorReactVersion < 18;
|
|
2563
2591
|
errorIf(
|
|
2564
2592
|
oldReactVersion && props.unstable_batchedUpdates === void 0,
|
|
@@ -2575,14 +2603,14 @@ function RoomProviderInner(props) {
|
|
|
2575
2603
|
unstable_batchedUpdates: props.unstable_batchedUpdates,
|
|
2576
2604
|
autoConnect: props.autoConnect ?? typeof window !== "undefined"
|
|
2577
2605
|
});
|
|
2578
|
-
const [{ room }, setRoomLeavePair] =
|
|
2606
|
+
const [{ room }, setRoomLeavePair] = React4.useState(
|
|
2579
2607
|
() => stableEnterRoom(roomId, {
|
|
2580
2608
|
...frozenProps,
|
|
2581
2609
|
autoConnect: false
|
|
2582
2610
|
// Deliberately using false here on the first render, see below
|
|
2583
2611
|
})
|
|
2584
2612
|
);
|
|
2585
|
-
|
|
2613
|
+
React4.useEffect(() => {
|
|
2586
2614
|
const { store } = getRoomExtrasForClient(client);
|
|
2587
2615
|
async function handleCommentEvent(message) {
|
|
2588
2616
|
if (message.type === ServerMsgCode.THREAD_DELETED) {
|
|
@@ -2595,7 +2623,7 @@ function RoomProviderInner(props) {
|
|
|
2595
2623
|
return;
|
|
2596
2624
|
}
|
|
2597
2625
|
const { thread, inboxNotification } = info;
|
|
2598
|
-
const existingThread = store.getFullState().
|
|
2626
|
+
const existingThread = store.getFullState().threadsDB.getEvenIfDeleted(message.threadId);
|
|
2599
2627
|
switch (message.type) {
|
|
2600
2628
|
case ServerMsgCode.COMMENT_EDITED:
|
|
2601
2629
|
case ServerMsgCode.THREAD_METADATA_UPDATED:
|
|
@@ -2617,23 +2645,7 @@ function RoomProviderInner(props) {
|
|
|
2617
2645
|
(message) => void handleCommentEvent(message)
|
|
2618
2646
|
);
|
|
2619
2647
|
}, [client, room]);
|
|
2620
|
-
|
|
2621
|
-
const store = getRoomExtrasForClient(client).store;
|
|
2622
|
-
void store.fetchRoomThreadsDeltaUpdate(room.id).catch(() => {
|
|
2623
|
-
});
|
|
2624
|
-
}, [client, room.id]);
|
|
2625
|
-
React5.useEffect(() => {
|
|
2626
|
-
function handleIsOnline() {
|
|
2627
|
-
const store = getRoomExtrasForClient(client).store;
|
|
2628
|
-
void store.fetchRoomThreadsDeltaUpdate(room.id).catch(() => {
|
|
2629
|
-
});
|
|
2630
|
-
}
|
|
2631
|
-
window.addEventListener("online", handleIsOnline);
|
|
2632
|
-
return () => {
|
|
2633
|
-
window.removeEventListener("online", handleIsOnline);
|
|
2634
|
-
};
|
|
2635
|
-
}, [client, room.id]);
|
|
2636
|
-
React5.useEffect(() => {
|
|
2648
|
+
React4.useEffect(() => {
|
|
2637
2649
|
const pair = stableEnterRoom(roomId, frozenProps);
|
|
2638
2650
|
setRoomLeavePair(pair);
|
|
2639
2651
|
const { room: room2, leave } = pair;
|
|
@@ -2644,7 +2656,7 @@ function RoomProviderInner(props) {
|
|
|
2644
2656
|
leave();
|
|
2645
2657
|
};
|
|
2646
2658
|
}, [roomId, frozenProps, stableEnterRoom]);
|
|
2647
|
-
return /* @__PURE__ */
|
|
2659
|
+
return /* @__PURE__ */ React4.createElement(RoomContext.Provider, { value: room }, props.children);
|
|
2648
2660
|
}
|
|
2649
2661
|
function useRoom() {
|
|
2650
2662
|
const room = useRoomOrNull();
|
|
@@ -2677,9 +2689,9 @@ function useStorageStatusImmediate() {
|
|
|
2677
2689
|
}
|
|
2678
2690
|
function useStorageStatusSmooth() {
|
|
2679
2691
|
const room = useRoom();
|
|
2680
|
-
const [status, setStatus] =
|
|
2692
|
+
const [status, setStatus] = React4.useState(room.getStorageStatus);
|
|
2681
2693
|
const oldStatus = useLatest(room.getStorageStatus());
|
|
2682
|
-
|
|
2694
|
+
React4.useEffect(() => {
|
|
2683
2695
|
let timeoutId;
|
|
2684
2696
|
const unsub = room.events.storageStatus.subscribe((newStatus) => {
|
|
2685
2697
|
if (oldStatus.current === "synchronizing" && newStatus === "synchronized") {
|
|
@@ -2701,7 +2713,7 @@ function useBatch() {
|
|
|
2701
2713
|
}
|
|
2702
2714
|
function useBroadcastEvent() {
|
|
2703
2715
|
const room = useRoom();
|
|
2704
|
-
return
|
|
2716
|
+
return React4.useCallback(
|
|
2705
2717
|
(event, options = { shouldQueueEventIfNotReady: false }) => {
|
|
2706
2718
|
room.broadcastEvent(event, options);
|
|
2707
2719
|
},
|
|
@@ -2711,7 +2723,7 @@ function useBroadcastEvent() {
|
|
|
2711
2723
|
function useOthersListener(callback) {
|
|
2712
2724
|
const room = useRoom();
|
|
2713
2725
|
const savedCallback = useLatest(callback);
|
|
2714
|
-
|
|
2726
|
+
React4.useEffect(
|
|
2715
2727
|
() => room.events.others.subscribe((event) => savedCallback.current(event)),
|
|
2716
2728
|
[room, savedCallback]
|
|
2717
2729
|
);
|
|
@@ -2719,7 +2731,7 @@ function useOthersListener(callback) {
|
|
|
2719
2731
|
function useLostConnectionListener(callback) {
|
|
2720
2732
|
const room = useRoom();
|
|
2721
2733
|
const savedCallback = useLatest(callback);
|
|
2722
|
-
|
|
2734
|
+
React4.useEffect(
|
|
2723
2735
|
() => room.events.lostConnection.subscribe(
|
|
2724
2736
|
(event) => savedCallback.current(event)
|
|
2725
2737
|
),
|
|
@@ -2729,7 +2741,7 @@ function useLostConnectionListener(callback) {
|
|
|
2729
2741
|
function useErrorListener(callback) {
|
|
2730
2742
|
const room = useRoom();
|
|
2731
2743
|
const savedCallback = useLatest(callback);
|
|
2732
|
-
|
|
2744
|
+
React4.useEffect(
|
|
2733
2745
|
() => room.events.error.subscribe((e) => savedCallback.current(e)),
|
|
2734
2746
|
[room, savedCallback]
|
|
2735
2747
|
);
|
|
@@ -2737,7 +2749,7 @@ function useErrorListener(callback) {
|
|
|
2737
2749
|
function useEventListener(callback) {
|
|
2738
2750
|
const room = useRoom();
|
|
2739
2751
|
const savedCallback = useLatest(callback);
|
|
2740
|
-
|
|
2752
|
+
React4.useEffect(() => {
|
|
2741
2753
|
const listener = (eventData) => {
|
|
2742
2754
|
savedCallback.current(eventData);
|
|
2743
2755
|
};
|
|
@@ -2770,7 +2782,7 @@ function useSelf(maybeSelector, isEqual) {
|
|
|
2770
2782
|
const subscribe = room.events.self.subscribe;
|
|
2771
2783
|
const getSnapshot = room.getSelf;
|
|
2772
2784
|
const selector = maybeSelector ?? identity2;
|
|
2773
|
-
const wrappedSelector =
|
|
2785
|
+
const wrappedSelector = React4.useCallback(
|
|
2774
2786
|
(me) => me !== null ? selector(me) : null,
|
|
2775
2787
|
[selector]
|
|
2776
2788
|
);
|
|
@@ -2808,11 +2820,11 @@ function useOthers(selector, isEqual) {
|
|
|
2808
2820
|
);
|
|
2809
2821
|
}
|
|
2810
2822
|
function useOthersMapped(itemSelector, itemIsEqual) {
|
|
2811
|
-
const wrappedSelector =
|
|
2823
|
+
const wrappedSelector = React4.useCallback(
|
|
2812
2824
|
(others) => others.map((other) => [other.connectionId, itemSelector(other)]),
|
|
2813
2825
|
[itemSelector]
|
|
2814
2826
|
);
|
|
2815
|
-
const wrappedIsEqual =
|
|
2827
|
+
const wrappedIsEqual = React4.useCallback(
|
|
2816
2828
|
(a, b) => {
|
|
2817
2829
|
const eq = itemIsEqual ?? Object.is;
|
|
2818
2830
|
return a.length === b.length && a.every((atuple, index) => {
|
|
@@ -2829,14 +2841,14 @@ function useOthersConnectionIds() {
|
|
|
2829
2841
|
}
|
|
2830
2842
|
var NOT_FOUND = Symbol();
|
|
2831
2843
|
function useOther(connectionId, selector, isEqual) {
|
|
2832
|
-
const wrappedSelector =
|
|
2844
|
+
const wrappedSelector = React4.useCallback(
|
|
2833
2845
|
(others) => {
|
|
2834
2846
|
const other2 = others.find((other3) => other3.connectionId === connectionId);
|
|
2835
2847
|
return other2 !== void 0 ? selector(other2) : NOT_FOUND;
|
|
2836
2848
|
},
|
|
2837
2849
|
[connectionId, selector]
|
|
2838
2850
|
);
|
|
2839
|
-
const wrappedIsEqual =
|
|
2851
|
+
const wrappedIsEqual = React4.useCallback(
|
|
2840
2852
|
(prev, curr) => {
|
|
2841
2853
|
if (prev === NOT_FOUND || curr === NOT_FOUND) {
|
|
2842
2854
|
return prev === curr;
|
|
@@ -2867,15 +2879,15 @@ function useStorageRoot() {
|
|
|
2867
2879
|
function useStorage(selector, isEqual) {
|
|
2868
2880
|
const room = useRoom();
|
|
2869
2881
|
const rootOrNull = useMutableStorageRoot();
|
|
2870
|
-
const wrappedSelector =
|
|
2882
|
+
const wrappedSelector = React4.useCallback(
|
|
2871
2883
|
(rootOrNull2) => rootOrNull2 !== null ? selector(rootOrNull2) : null,
|
|
2872
2884
|
[selector]
|
|
2873
2885
|
);
|
|
2874
|
-
const subscribe =
|
|
2886
|
+
const subscribe = React4.useCallback(
|
|
2875
2887
|
(onStoreChange) => rootOrNull !== null ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true }) : noop3,
|
|
2876
2888
|
[room, rootOrNull]
|
|
2877
2889
|
);
|
|
2878
|
-
const getSnapshot =
|
|
2890
|
+
const getSnapshot = React4.useCallback(() => {
|
|
2879
2891
|
if (rootOrNull === null) {
|
|
2880
2892
|
return null;
|
|
2881
2893
|
} else {
|
|
@@ -2895,7 +2907,7 @@ function useStorage(selector, isEqual) {
|
|
|
2895
2907
|
}
|
|
2896
2908
|
function useMutation(callback, deps) {
|
|
2897
2909
|
const room = useRoom();
|
|
2898
|
-
return
|
|
2910
|
+
return React4.useMemo(
|
|
2899
2911
|
() => {
|
|
2900
2912
|
return (...args) => (
|
|
2901
2913
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
@@ -2920,11 +2932,11 @@ function useThreads(options = {
|
|
|
2920
2932
|
const { scrollOnLoad = true } = options;
|
|
2921
2933
|
const client = useClient();
|
|
2922
2934
|
const room = useRoom();
|
|
2923
|
-
const { store,
|
|
2924
|
-
|
|
2935
|
+
const { store, getOrCreateThreadsPollerForRoomId } = getRoomExtrasForClient(client);
|
|
2936
|
+
const poller = getOrCreateThreadsPollerForRoomId(room.id);
|
|
2937
|
+
React4.useEffect(
|
|
2925
2938
|
() => {
|
|
2926
|
-
void store.waitUntilRoomThreadsLoaded(room.id, options.query)
|
|
2927
|
-
});
|
|
2939
|
+
void store.waitUntilRoomThreadsLoaded(room.id, options.query);
|
|
2928
2940
|
}
|
|
2929
2941
|
// NOTE: Deliberately *not* using a dependency array here!
|
|
2930
2942
|
//
|
|
@@ -2935,13 +2947,17 @@ function useThreads(options = {
|
|
|
2935
2947
|
// 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very
|
|
2936
2948
|
// *next* render after that, a *new* fetch/promise will get created.
|
|
2937
2949
|
);
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2950
|
+
React4.useEffect(() => {
|
|
2951
|
+
poller.inc();
|
|
2952
|
+
poller.pollNowIfStale();
|
|
2953
|
+
return () => poller.dec();
|
|
2954
|
+
}, [poller]);
|
|
2955
|
+
const getter = React4.useCallback(
|
|
2956
|
+
() => store.getRoomThreadsLoadingState(room.id, options.query),
|
|
2941
2957
|
[store, room.id, options.query]
|
|
2942
2958
|
);
|
|
2943
2959
|
const state = useSyncExternalStoreWithSelector2(
|
|
2944
|
-
store.
|
|
2960
|
+
store.subscribe,
|
|
2945
2961
|
getter,
|
|
2946
2962
|
getter,
|
|
2947
2963
|
identity2,
|
|
@@ -2955,14 +2971,14 @@ function useCommentsErrorListener(callback) {
|
|
|
2955
2971
|
const client = useClient();
|
|
2956
2972
|
const savedCallback = useLatest(callback);
|
|
2957
2973
|
const { commentsErrorEventSource } = getRoomExtrasForClient(client);
|
|
2958
|
-
|
|
2974
|
+
React4.useEffect(() => {
|
|
2959
2975
|
return commentsErrorEventSource.subscribe(savedCallback.current);
|
|
2960
2976
|
}, [savedCallback, commentsErrorEventSource]);
|
|
2961
2977
|
}
|
|
2962
2978
|
function useCreateThread() {
|
|
2963
2979
|
const client = useClient();
|
|
2964
2980
|
const room = useRoom();
|
|
2965
|
-
return
|
|
2981
|
+
return React4.useCallback(
|
|
2966
2982
|
(options) => {
|
|
2967
2983
|
const body = options.body;
|
|
2968
2984
|
const metadata = options.metadata ?? {};
|
|
@@ -3022,12 +3038,12 @@ function useCreateThread() {
|
|
|
3022
3038
|
function useDeleteThread() {
|
|
3023
3039
|
const client = useClient();
|
|
3024
3040
|
const room = useRoom();
|
|
3025
|
-
return
|
|
3041
|
+
return React4.useCallback(
|
|
3026
3042
|
(threadId) => {
|
|
3027
3043
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
3028
|
-
const thread = store.getFullState().threadsById[threadId];
|
|
3029
3044
|
const userId = getCurrentUserId(room);
|
|
3030
|
-
|
|
3045
|
+
const existing = store.getFullState().threadsDB.get(threadId);
|
|
3046
|
+
if (existing?.comments?.[0]?.userId !== userId) {
|
|
3031
3047
|
throw new Error("Only the thread creator can delete the thread");
|
|
3032
3048
|
}
|
|
3033
3049
|
const optimisticUpdateId = store.addOptimisticUpdate({
|
|
@@ -3053,7 +3069,7 @@ function useDeleteThread() {
|
|
|
3053
3069
|
function useEditThreadMetadata() {
|
|
3054
3070
|
const client = useClient();
|
|
3055
3071
|
const room = useRoom();
|
|
3056
|
-
return
|
|
3072
|
+
return React4.useCallback(
|
|
3057
3073
|
(options) => {
|
|
3058
3074
|
if (!options.metadata) {
|
|
3059
3075
|
return;
|
|
@@ -3095,7 +3111,7 @@ function useEditThreadMetadata() {
|
|
|
3095
3111
|
function useCreateComment() {
|
|
3096
3112
|
const client = useClient();
|
|
3097
3113
|
const room = useRoom();
|
|
3098
|
-
return
|
|
3114
|
+
return React4.useCallback(
|
|
3099
3115
|
({ threadId, body, attachments }) => {
|
|
3100
3116
|
const commentId = createCommentId();
|
|
3101
3117
|
const createdAt = /* @__PURE__ */ new Date();
|
|
@@ -3139,18 +3155,18 @@ function useCreateComment() {
|
|
|
3139
3155
|
function useEditComment() {
|
|
3140
3156
|
const client = useClient();
|
|
3141
3157
|
const room = useRoom();
|
|
3142
|
-
return
|
|
3158
|
+
return React4.useCallback(
|
|
3143
3159
|
({ threadId, commentId, body, attachments }) => {
|
|
3144
3160
|
const editedAt = /* @__PURE__ */ new Date();
|
|
3145
3161
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
3146
|
-
const
|
|
3147
|
-
if (
|
|
3162
|
+
const existing = store.getFullState().threadsDB.getEvenIfDeleted(threadId);
|
|
3163
|
+
if (existing === void 0) {
|
|
3148
3164
|
console3.warn(
|
|
3149
3165
|
`Internal unexpected behavior. Cannot edit comment in thread "${threadId}" because the thread does not exist in the cache.`
|
|
3150
3166
|
);
|
|
3151
3167
|
return;
|
|
3152
3168
|
}
|
|
3153
|
-
const comment =
|
|
3169
|
+
const comment = existing.comments.find(
|
|
3154
3170
|
(comment2) => comment2.id === commentId
|
|
3155
3171
|
);
|
|
3156
3172
|
if (comment === void 0 || comment.deletedAt !== void 0) {
|
|
@@ -3191,7 +3207,7 @@ function useEditComment() {
|
|
|
3191
3207
|
function useDeleteComment() {
|
|
3192
3208
|
const client = useClient();
|
|
3193
3209
|
const room = useRoom();
|
|
3194
|
-
return
|
|
3210
|
+
return React4.useCallback(
|
|
3195
3211
|
({ threadId, commentId }) => {
|
|
3196
3212
|
const deletedAt = /* @__PURE__ */ new Date();
|
|
3197
3213
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
@@ -3228,7 +3244,7 @@ function useDeleteComment() {
|
|
|
3228
3244
|
function useAddReaction() {
|
|
3229
3245
|
const client = useClient();
|
|
3230
3246
|
const room = useRoom();
|
|
3231
|
-
return
|
|
3247
|
+
return React4.useCallback(
|
|
3232
3248
|
({ threadId, commentId, emoji }) => {
|
|
3233
3249
|
const createdAt = /* @__PURE__ */ new Date();
|
|
3234
3250
|
const userId = getCurrentUserId(room);
|
|
@@ -3271,7 +3287,7 @@ function useAddReaction() {
|
|
|
3271
3287
|
function useRemoveReaction() {
|
|
3272
3288
|
const client = useClient();
|
|
3273
3289
|
const room = useRoom();
|
|
3274
|
-
return
|
|
3290
|
+
return React4.useCallback(
|
|
3275
3291
|
({ threadId, commentId, emoji }) => {
|
|
3276
3292
|
const userId = getCurrentUserId(room);
|
|
3277
3293
|
const removedAt = /* @__PURE__ */ new Date();
|
|
@@ -3313,7 +3329,7 @@ function useRemoveReaction() {
|
|
|
3313
3329
|
function useMarkThreadAsRead() {
|
|
3314
3330
|
const client = useClient();
|
|
3315
3331
|
const room = useRoom();
|
|
3316
|
-
return
|
|
3332
|
+
return React4.useCallback(
|
|
3317
3333
|
(threadId) => {
|
|
3318
3334
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
3319
3335
|
const inboxNotification = Object.values(
|
|
@@ -3354,7 +3370,7 @@ function useMarkThreadAsRead() {
|
|
|
3354
3370
|
function useMarkThreadAsResolved() {
|
|
3355
3371
|
const client = useClient();
|
|
3356
3372
|
const room = useRoom();
|
|
3357
|
-
return
|
|
3373
|
+
return React4.useCallback(
|
|
3358
3374
|
(threadId) => {
|
|
3359
3375
|
const updatedAt = /* @__PURE__ */ new Date();
|
|
3360
3376
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
@@ -3388,7 +3404,7 @@ function useMarkThreadAsResolved() {
|
|
|
3388
3404
|
function useMarkThreadAsUnresolved() {
|
|
3389
3405
|
const client = useClient();
|
|
3390
3406
|
const room = useRoom();
|
|
3391
|
-
return
|
|
3407
|
+
return React4.useCallback(
|
|
3392
3408
|
(threadId) => {
|
|
3393
3409
|
const updatedAt = /* @__PURE__ */ new Date();
|
|
3394
3410
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
@@ -3422,26 +3438,24 @@ function useMarkThreadAsUnresolved() {
|
|
|
3422
3438
|
function useThreadSubscription(threadId) {
|
|
3423
3439
|
const client = useClient();
|
|
3424
3440
|
const { store } = getRoomExtrasForClient(client);
|
|
3425
|
-
const selector =
|
|
3441
|
+
const selector = React4.useCallback(
|
|
3426
3442
|
(state) => {
|
|
3427
|
-
const
|
|
3428
|
-
(
|
|
3443
|
+
const notification = state.cleanedNotifications.find(
|
|
3444
|
+
(inboxNotification) => inboxNotification.kind === "thread" && inboxNotification.threadId === threadId
|
|
3429
3445
|
);
|
|
3430
|
-
const thread = state.
|
|
3431
|
-
if (
|
|
3432
|
-
return {
|
|
3433
|
-
status: "not-subscribed"
|
|
3434
|
-
};
|
|
3446
|
+
const thread = state.threadsDB.get(threadId);
|
|
3447
|
+
if (notification === void 0 || thread === void 0) {
|
|
3448
|
+
return { status: "not-subscribed" };
|
|
3435
3449
|
}
|
|
3436
3450
|
return {
|
|
3437
3451
|
status: "subscribed",
|
|
3438
|
-
unreadSince:
|
|
3452
|
+
unreadSince: notification.readAt
|
|
3439
3453
|
};
|
|
3440
3454
|
},
|
|
3441
3455
|
[threadId]
|
|
3442
3456
|
);
|
|
3443
3457
|
return useSyncExternalStoreWithSelector2(
|
|
3444
|
-
store.
|
|
3458
|
+
store.subscribe,
|
|
3445
3459
|
store.getFullState,
|
|
3446
3460
|
store.getFullState,
|
|
3447
3461
|
selector
|
|
@@ -3451,58 +3465,61 @@ function useRoomNotificationSettings() {
|
|
|
3451
3465
|
const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
|
|
3452
3466
|
const client = useClient();
|
|
3453
3467
|
const room = useRoom();
|
|
3454
|
-
const { store } = getRoomExtrasForClient(client);
|
|
3455
|
-
const
|
|
3456
|
-
|
|
3468
|
+
const { store, getOrCreateNotificationsSettingsPollerForRoomId } = getRoomExtrasForClient(client);
|
|
3469
|
+
const poller = getOrCreateNotificationsSettingsPollerForRoomId(room.id);
|
|
3470
|
+
React4.useEffect(
|
|
3471
|
+
() => {
|
|
3472
|
+
void store.waitUntilRoomNotificationSettingsLoaded(room.id);
|
|
3473
|
+
}
|
|
3474
|
+
// NOTE: Deliberately *not* using a dependency array here!
|
|
3475
|
+
//
|
|
3476
|
+
// It is important to call waitUntil on *every* render.
|
|
3477
|
+
// This is harmless though, on most renders, except:
|
|
3478
|
+
// 1. The very first render, in which case we'll want to trigger the initial page fetch.
|
|
3479
|
+
// 2. All other subsequent renders now "just" return the same promise (a quick operation).
|
|
3480
|
+
// 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very
|
|
3481
|
+
// *next* render after that, a *new* fetch/promise will get created.
|
|
3482
|
+
);
|
|
3483
|
+
React4.useEffect(() => {
|
|
3484
|
+
poller.inc();
|
|
3485
|
+
poller.pollNowIfStale();
|
|
3486
|
+
return () => {
|
|
3487
|
+
poller.dec();
|
|
3488
|
+
};
|
|
3489
|
+
}, [poller]);
|
|
3490
|
+
const getter = React4.useCallback(
|
|
3491
|
+
() => store.getNotificationSettingsLoadingState(room.id),
|
|
3457
3492
|
[store, room.id]
|
|
3458
3493
|
);
|
|
3459
|
-
React5.useEffect(() => {
|
|
3460
|
-
const { getInboxNotificationSettings } = getRoomExtrasForClient(client);
|
|
3461
|
-
void getInboxNotificationSettings(room);
|
|
3462
|
-
}, [client, room]);
|
|
3463
3494
|
const settings = useSyncExternalStoreWithSelector2(
|
|
3464
|
-
store.
|
|
3495
|
+
store.subscribe,
|
|
3465
3496
|
getter,
|
|
3466
3497
|
getter,
|
|
3467
3498
|
identity2,
|
|
3468
|
-
|
|
3499
|
+
shallow2
|
|
3469
3500
|
);
|
|
3470
|
-
return
|
|
3501
|
+
return React4.useMemo(() => {
|
|
3471
3502
|
return [settings, updateRoomNotificationSettings];
|
|
3472
3503
|
}, [settings, updateRoomNotificationSettings]);
|
|
3473
3504
|
}
|
|
3474
3505
|
function useRoomNotificationSettingsSuspense() {
|
|
3475
|
-
const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();
|
|
3476
3506
|
const client = useClient();
|
|
3507
|
+
const store = getRoomExtrasForClient(client).store;
|
|
3477
3508
|
const room = useRoom();
|
|
3478
|
-
|
|
3479
|
-
const
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
)
|
|
3483
|
-
const settings = useSyncExternalStoreWithSelector2(
|
|
3484
|
-
store.subscribeNotificationSettings,
|
|
3485
|
-
getter,
|
|
3486
|
-
getter,
|
|
3487
|
-
identity2,
|
|
3488
|
-
shallow4
|
|
3489
|
-
);
|
|
3490
|
-
if (settings.isLoading) {
|
|
3491
|
-
const { getInboxNotificationSettings } = getRoomExtrasForClient(client);
|
|
3492
|
-
throw getInboxNotificationSettings(room);
|
|
3493
|
-
} else if (settings.error) {
|
|
3494
|
-
throw settings.error;
|
|
3495
|
-
}
|
|
3496
|
-
return React5.useMemo(() => {
|
|
3509
|
+
use(store.waitUntilRoomNotificationSettingsLoaded(room.id));
|
|
3510
|
+
const [settings, updateRoomNotificationSettings] = useRoomNotificationSettings();
|
|
3511
|
+
assert2(!settings.error, "Did not expect error");
|
|
3512
|
+
assert2(!settings.isLoading, "Did not expect loading");
|
|
3513
|
+
return React4.useMemo(() => {
|
|
3497
3514
|
return [settings, updateRoomNotificationSettings];
|
|
3498
3515
|
}, [settings, updateRoomNotificationSettings]);
|
|
3499
3516
|
}
|
|
3500
3517
|
function useHistoryVersionData(versionId) {
|
|
3501
|
-
const [state, setState] =
|
|
3518
|
+
const [state, setState] = React4.useState({
|
|
3502
3519
|
isLoading: true
|
|
3503
3520
|
});
|
|
3504
3521
|
const room = useRoom();
|
|
3505
|
-
|
|
3522
|
+
React4.useEffect(() => {
|
|
3506
3523
|
setState({ isLoading: true });
|
|
3507
3524
|
const load = async () => {
|
|
3508
3525
|
try {
|
|
@@ -3529,50 +3546,53 @@ function useHistoryVersionData(versionId) {
|
|
|
3529
3546
|
function useHistoryVersions() {
|
|
3530
3547
|
const client = useClient();
|
|
3531
3548
|
const room = useRoom();
|
|
3532
|
-
const { store,
|
|
3533
|
-
const
|
|
3534
|
-
|
|
3549
|
+
const { store, getOrCreateVersionsPollerForRoomId } = getRoomExtrasForClient(client);
|
|
3550
|
+
const poller = getOrCreateVersionsPollerForRoomId(room.id);
|
|
3551
|
+
React4.useEffect(() => {
|
|
3552
|
+
poller.inc();
|
|
3553
|
+
poller.pollNowIfStale();
|
|
3554
|
+
return () => poller.dec();
|
|
3555
|
+
}, [poller]);
|
|
3556
|
+
const getter = React4.useCallback(
|
|
3557
|
+
() => store.getRoomVersionsLoadingState(room.id),
|
|
3535
3558
|
[store, room.id]
|
|
3536
3559
|
);
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3560
|
+
React4.useEffect(
|
|
3561
|
+
() => {
|
|
3562
|
+
void store.waitUntilRoomVersionsLoaded(room.id);
|
|
3563
|
+
}
|
|
3564
|
+
// NOTE: Deliberately *not* using a dependency array here!
|
|
3565
|
+
//
|
|
3566
|
+
// It is important to call waitUntil on *every* render.
|
|
3567
|
+
// This is harmless though, on most renders, except:
|
|
3568
|
+
// 1. The very first render, in which case we'll want to trigger the initial page fetch.
|
|
3569
|
+
// 2. All other subsequent renders now "just" return the same promise (a quick operation).
|
|
3570
|
+
// 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very
|
|
3571
|
+
// *next* render after that, a *new* fetch/promise will get created.
|
|
3572
|
+
);
|
|
3540
3573
|
const state = useSyncExternalStoreWithSelector2(
|
|
3541
|
-
store.
|
|
3574
|
+
store.subscribe,
|
|
3542
3575
|
getter,
|
|
3543
3576
|
getter,
|
|
3544
3577
|
identity2,
|
|
3545
|
-
|
|
3578
|
+
shallow2
|
|
3546
3579
|
);
|
|
3547
3580
|
return state;
|
|
3548
3581
|
}
|
|
3549
3582
|
function useHistoryVersionsSuspense() {
|
|
3550
3583
|
const client = useClient();
|
|
3551
3584
|
const room = useRoom();
|
|
3552
|
-
const
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
);
|
|
3557
|
-
|
|
3558
|
-
store.subscribeVersions,
|
|
3559
|
-
getter,
|
|
3560
|
-
getter,
|
|
3561
|
-
identity2,
|
|
3562
|
-
shallow4
|
|
3563
|
-
);
|
|
3564
|
-
if (state.isLoading) {
|
|
3565
|
-
const { getRoomVersions } = getRoomExtrasForClient(client);
|
|
3566
|
-
throw getRoomVersions(room);
|
|
3567
|
-
} else if (state.error) {
|
|
3568
|
-
throw state.error;
|
|
3569
|
-
}
|
|
3570
|
-
return state;
|
|
3585
|
+
const store = getRoomExtrasForClient(client).store;
|
|
3586
|
+
use(store.waitUntilRoomVersionsLoaded(room.id));
|
|
3587
|
+
const result = useHistoryVersions();
|
|
3588
|
+
assert2(!result.error, "Did not expect error");
|
|
3589
|
+
assert2(!result.isLoading, "Did not expect loading");
|
|
3590
|
+
return result;
|
|
3571
3591
|
}
|
|
3572
3592
|
function useUpdateRoomNotificationSettings() {
|
|
3573
3593
|
const client = useClient();
|
|
3574
3594
|
const room = useRoom();
|
|
3575
|
-
return
|
|
3595
|
+
return React4.useCallback(
|
|
3576
3596
|
(settings) => {
|
|
3577
3597
|
const { store, onMutationFailure } = getRoomExtrasForClient(client);
|
|
3578
3598
|
const optimisticUpdateId = store.addOptimisticUpdate({
|
|
@@ -3582,7 +3602,7 @@ function useUpdateRoomNotificationSettings() {
|
|
|
3582
3602
|
});
|
|
3583
3603
|
room.updateNotificationSettings(settings).then(
|
|
3584
3604
|
(settings2) => {
|
|
3585
|
-
store.
|
|
3605
|
+
store.updateRoomNotificationSettings_confirmOptimisticUpdate(
|
|
3586
3606
|
room.id,
|
|
3587
3607
|
optimisticUpdateId,
|
|
3588
3608
|
settings2
|
|
@@ -3682,11 +3702,11 @@ function selectorFor_useAttachmentUrl(state) {
|
|
|
3682
3702
|
function useAttachmentUrl(attachmentId) {
|
|
3683
3703
|
const room = useRoom();
|
|
3684
3704
|
const { attachmentUrlsStore } = room[kInternal3];
|
|
3685
|
-
const getAttachmentUrlState =
|
|
3705
|
+
const getAttachmentUrlState = React4.useCallback(
|
|
3686
3706
|
() => attachmentUrlsStore.getState(attachmentId),
|
|
3687
3707
|
[attachmentUrlsStore, attachmentId]
|
|
3688
3708
|
);
|
|
3689
|
-
|
|
3709
|
+
React4.useEffect(() => {
|
|
3690
3710
|
void attachmentUrlsStore.get(attachmentId);
|
|
3691
3711
|
}, [attachmentUrlsStore, attachmentId]);
|
|
3692
3712
|
return useSyncExternalStoreWithSelector2(
|
|
@@ -3700,7 +3720,7 @@ function useAttachmentUrl(attachmentId) {
|
|
|
3700
3720
|
function useAttachmentUrlSuspense(attachmentId) {
|
|
3701
3721
|
const room = useRoom();
|
|
3702
3722
|
const { attachmentUrlsStore } = room[kInternal3];
|
|
3703
|
-
const getAttachmentUrlState =
|
|
3723
|
+
const getAttachmentUrlState = React4.useCallback(
|
|
3704
3724
|
() => attachmentUrlsStore.getState(attachmentId),
|
|
3705
3725
|
[attachmentUrlsStore, attachmentId]
|
|
3706
3726
|
);
|
|
@@ -3744,6 +3764,8 @@ var _useOthersMapped = useOthersMapped;
|
|
|
3744
3764
|
var _useOthersMappedSuspense = useOthersMappedSuspense;
|
|
3745
3765
|
var _useThreads = useThreads;
|
|
3746
3766
|
var _useThreadsSuspense = useThreadsSuspense;
|
|
3767
|
+
var _useRoomNotificationSettings = useRoomNotificationSettings;
|
|
3768
|
+
var _useRoomNotificationSettingsSuspense = useRoomNotificationSettingsSuspense;
|
|
3747
3769
|
var _useHistoryVersions = useHistoryVersions;
|
|
3748
3770
|
var _useHistoryVersionsSuspense = useHistoryVersionsSuspense;
|
|
3749
3771
|
var _useOther = useOther;
|
|
@@ -3766,12 +3788,7 @@ var _useStorageRoot = useStorageRoot;
|
|
|
3766
3788
|
var _useUpdateMyPresence = useUpdateMyPresence;
|
|
3767
3789
|
|
|
3768
3790
|
export {
|
|
3769
|
-
PKG_NAME,
|
|
3770
|
-
PKG_VERSION,
|
|
3771
|
-
PKG_FORMAT,
|
|
3772
|
-
ClientSideSuspense,
|
|
3773
3791
|
RoomContext,
|
|
3774
|
-
selectThreads,
|
|
3775
3792
|
ClientContext,
|
|
3776
3793
|
getUmbrellaStoreForClient,
|
|
3777
3794
|
useClient,
|
|
@@ -3813,7 +3830,6 @@ export {
|
|
|
3813
3830
|
useMarkThreadAsResolved,
|
|
3814
3831
|
useMarkThreadAsUnresolved,
|
|
3815
3832
|
useThreadSubscription,
|
|
3816
|
-
useRoomNotificationSettings,
|
|
3817
3833
|
useHistoryVersionData,
|
|
3818
3834
|
useUpdateRoomNotificationSettings,
|
|
3819
3835
|
useOthersConnectionIdsSuspense,
|
|
@@ -3837,6 +3853,8 @@ export {
|
|
|
3837
3853
|
_useOthersMappedSuspense,
|
|
3838
3854
|
_useThreads,
|
|
3839
3855
|
_useThreadsSuspense,
|
|
3856
|
+
_useRoomNotificationSettings,
|
|
3857
|
+
_useRoomNotificationSettingsSuspense,
|
|
3840
3858
|
_useHistoryVersions,
|
|
3841
3859
|
_useHistoryVersionsSuspense,
|
|
3842
3860
|
_useOther,
|
|
@@ -3850,4 +3868,4 @@ export {
|
|
|
3850
3868
|
_useStorageRoot,
|
|
3851
3869
|
_useUpdateMyPresence
|
|
3852
3870
|
};
|
|
3853
|
-
//# sourceMappingURL=chunk-
|
|
3871
|
+
//# sourceMappingURL=chunk-A7GJNN4L.mjs.map
|