@liveblocks/core 3.23.0-file2 → 3.23.0-file4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +416 -224
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -115
- package/dist/index.d.ts +120 -115
- package/dist/index.js +255 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
|
|
7
7
|
// src/version.ts
|
|
8
8
|
var PKG_NAME = "@liveblocks/core";
|
|
9
|
-
var PKG_VERSION = "3.23.0-
|
|
9
|
+
var PKG_VERSION = "3.23.0-file4";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1919,8 +1919,10 @@ var Batch = class {
|
|
|
1919
1919
|
this.#clearDelayTimeout();
|
|
1920
1920
|
}
|
|
1921
1921
|
};
|
|
1922
|
-
function createBatchStore(batch2) {
|
|
1922
|
+
function createBatchStore(batch2, options) {
|
|
1923
1923
|
const signal = new MutableSignal(/* @__PURE__ */ new Map());
|
|
1924
|
+
const cacheExpiryTimeouts = /* @__PURE__ */ new Map();
|
|
1925
|
+
const pendingEnqueues = /* @__PURE__ */ new Map();
|
|
1924
1926
|
function getCacheKey(args) {
|
|
1925
1927
|
return stableStringify(args);
|
|
1926
1928
|
}
|
|
@@ -1935,7 +1937,42 @@ function createBatchStore(batch2) {
|
|
|
1935
1937
|
}
|
|
1936
1938
|
});
|
|
1937
1939
|
}
|
|
1940
|
+
function clearCacheExpiry(cacheKey) {
|
|
1941
|
+
const timeoutId = cacheExpiryTimeouts.get(cacheKey);
|
|
1942
|
+
if (timeoutId !== void 0) {
|
|
1943
|
+
clearTimeout(timeoutId);
|
|
1944
|
+
cacheExpiryTimeouts.delete(cacheKey);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
function scheduleCacheExpiry(input, expiresAt) {
|
|
1948
|
+
const cacheKey = getCacheKey(input);
|
|
1949
|
+
clearCacheExpiry(cacheKey);
|
|
1950
|
+
if (expiresAt === void 0 || !Number.isFinite(expiresAt)) {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
const timeoutId = setTimeout(
|
|
1954
|
+
() => {
|
|
1955
|
+
cacheExpiryTimeouts.delete(cacheKey);
|
|
1956
|
+
invalidate([input]);
|
|
1957
|
+
},
|
|
1958
|
+
Math.max(0, expiresAt - Date.now())
|
|
1959
|
+
);
|
|
1960
|
+
cacheExpiryTimeouts.set(cacheKey, timeoutId);
|
|
1961
|
+
}
|
|
1938
1962
|
function invalidate(inputs) {
|
|
1963
|
+
if (Array.isArray(inputs)) {
|
|
1964
|
+
for (const input of inputs) {
|
|
1965
|
+
const cacheKey = getCacheKey(input);
|
|
1966
|
+
clearCacheExpiry(cacheKey);
|
|
1967
|
+
pendingEnqueues.delete(cacheKey);
|
|
1968
|
+
}
|
|
1969
|
+
} else {
|
|
1970
|
+
for (const timeoutId of cacheExpiryTimeouts.values()) {
|
|
1971
|
+
clearTimeout(timeoutId);
|
|
1972
|
+
}
|
|
1973
|
+
cacheExpiryTimeouts.clear();
|
|
1974
|
+
pendingEnqueues.clear();
|
|
1975
|
+
}
|
|
1939
1976
|
signal.mutate((cache) => {
|
|
1940
1977
|
if (Array.isArray(inputs)) {
|
|
1941
1978
|
for (const input of inputs) {
|
|
@@ -1946,23 +1983,54 @@ function createBatchStore(batch2) {
|
|
|
1946
1983
|
}
|
|
1947
1984
|
});
|
|
1948
1985
|
}
|
|
1949
|
-
async function
|
|
1950
|
-
const cacheKey = getCacheKey(input);
|
|
1951
|
-
const cache = signal.get();
|
|
1952
|
-
if (cache.has(cacheKey)) {
|
|
1953
|
-
return;
|
|
1954
|
-
}
|
|
1986
|
+
async function processEnqueue(input, cacheKey, batchResult$, pendingEnqueueId) {
|
|
1955
1987
|
try {
|
|
1956
|
-
|
|
1957
|
-
|
|
1988
|
+
const result = await batchResult$;
|
|
1989
|
+
if (pendingEnqueues.get(cacheKey)?.id !== pendingEnqueueId) {
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1958
1992
|
update({ key: cacheKey, state: { isLoading: false, data: result } });
|
|
1993
|
+
scheduleCacheExpiry(input, options?.getCacheExpiry?.(result));
|
|
1959
1994
|
} catch (error3) {
|
|
1995
|
+
if (pendingEnqueues.get(cacheKey)?.id !== pendingEnqueueId) {
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
scheduleCacheExpiry(input, options?.getErrorCacheExpiry?.(error3));
|
|
1960
1999
|
update({
|
|
1961
2000
|
key: cacheKey,
|
|
1962
2001
|
state: { isLoading: false, error: error3 }
|
|
1963
2002
|
});
|
|
2003
|
+
} finally {
|
|
2004
|
+
if (pendingEnqueues.get(cacheKey)?.id === pendingEnqueueId) {
|
|
2005
|
+
pendingEnqueues.delete(cacheKey);
|
|
2006
|
+
}
|
|
1964
2007
|
}
|
|
1965
2008
|
}
|
|
2009
|
+
function enqueue(input) {
|
|
2010
|
+
const cacheKey = getCacheKey(input);
|
|
2011
|
+
const existingEnqueue = pendingEnqueues.get(cacheKey);
|
|
2012
|
+
if (existingEnqueue !== void 0) {
|
|
2013
|
+
return existingEnqueue.promise;
|
|
2014
|
+
}
|
|
2015
|
+
const cache = signal.get();
|
|
2016
|
+
if (cache.has(cacheKey)) {
|
|
2017
|
+
return Promise.resolve();
|
|
2018
|
+
}
|
|
2019
|
+
const batchResult$ = batch2.get(input);
|
|
2020
|
+
const pendingEnqueueId = /* @__PURE__ */ Symbol();
|
|
2021
|
+
const pendingEnqueue$ = processEnqueue(
|
|
2022
|
+
input,
|
|
2023
|
+
cacheKey,
|
|
2024
|
+
batchResult$,
|
|
2025
|
+
pendingEnqueueId
|
|
2026
|
+
);
|
|
2027
|
+
pendingEnqueues.set(cacheKey, {
|
|
2028
|
+
id: pendingEnqueueId,
|
|
2029
|
+
promise: pendingEnqueue$
|
|
2030
|
+
});
|
|
2031
|
+
update({ key: cacheKey, state: { isLoading: true } });
|
|
2032
|
+
return pendingEnqueue$;
|
|
2033
|
+
}
|
|
1966
2034
|
function setData(entries2) {
|
|
1967
2035
|
update(
|
|
1968
2036
|
entries2.map((entry) => ({
|
|
@@ -1970,6 +2038,9 @@ function createBatchStore(batch2) {
|
|
|
1970
2038
|
state: { isLoading: false, data: entry[1] }
|
|
1971
2039
|
}))
|
|
1972
2040
|
);
|
|
2041
|
+
for (const [input, output] of entries2) {
|
|
2042
|
+
scheduleCacheExpiry(input, options?.getCacheExpiry?.(output));
|
|
2043
|
+
}
|
|
1973
2044
|
}
|
|
1974
2045
|
function getItemState(input) {
|
|
1975
2046
|
const cacheKey = getCacheKey(input);
|
|
@@ -1981,6 +2052,21 @@ function createBatchStore(batch2) {
|
|
|
1981
2052
|
const cache = signal.get();
|
|
1982
2053
|
return cache.get(cacheKey)?.data;
|
|
1983
2054
|
}
|
|
2055
|
+
function waitUntilItemCacheExpires(input) {
|
|
2056
|
+
const cacheKey = getCacheKey(input);
|
|
2057
|
+
if (!cacheExpiryTimeouts.has(cacheKey)) {
|
|
2058
|
+
return void 0;
|
|
2059
|
+
}
|
|
2060
|
+
const initialState = signal.get().get(cacheKey);
|
|
2061
|
+
return new Promise((resolve) => {
|
|
2062
|
+
const unsubscribe = signal.subscribe(() => {
|
|
2063
|
+
if (signal.get().get(cacheKey) !== initialState) {
|
|
2064
|
+
unsubscribe();
|
|
2065
|
+
resolve();
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
1984
2070
|
function _cacheKeys() {
|
|
1985
2071
|
const cache = signal.get();
|
|
1986
2072
|
return [...cache.keys()];
|
|
@@ -1991,6 +2077,7 @@ function createBatchStore(batch2) {
|
|
|
1991
2077
|
setData,
|
|
1992
2078
|
getItemState,
|
|
1993
2079
|
getData,
|
|
2080
|
+
waitUntilItemCacheExpires,
|
|
1994
2081
|
invalidate,
|
|
1995
2082
|
batch: batch2,
|
|
1996
2083
|
_cacheKeys
|
|
@@ -2274,6 +2361,10 @@ function isUrl(string) {
|
|
|
2274
2361
|
// src/api-client.ts
|
|
2275
2362
|
var ROOM_FILE_PART_SIZE = 5 * 1024 * 1024;
|
|
2276
2363
|
var ROOM_FILE_RETRY_ATTEMPTS = 10;
|
|
2364
|
+
var FILE_URL_EXPIRY_BUFFER = 3e4;
|
|
2365
|
+
var FILE_URL_ERROR_CACHE_TTL = 1e3;
|
|
2366
|
+
var FILE_URL_ERROR_MAX_ATTEMPTS = 3;
|
|
2367
|
+
var FILE_URL_ERROR_ATTEMPTS_EXPIRY = 3e4;
|
|
2277
2368
|
var ROOM_FILE_RETRY_DELAYS = [
|
|
2278
2369
|
2e3,
|
|
2279
2370
|
2e3,
|
|
@@ -2286,10 +2377,13 @@ var ROOM_FILE_RETRY_DELAYS = [
|
|
|
2286
2377
|
2e3,
|
|
2287
2378
|
2e3
|
|
2288
2379
|
];
|
|
2380
|
+
var FileUrlUnavailableError = class extends Error {
|
|
2381
|
+
};
|
|
2289
2382
|
async function uploadRoomFile({
|
|
2290
2383
|
file,
|
|
2291
2384
|
signal,
|
|
2292
2385
|
abortErrorMessage,
|
|
2386
|
+
retryMultipartCompletion,
|
|
2293
2387
|
uploadSingle,
|
|
2294
2388
|
createMultipartUpload,
|
|
2295
2389
|
uploadMultipartPart,
|
|
@@ -2304,10 +2398,7 @@ async function uploadRoomFile({
|
|
|
2304
2398
|
if (signal?.aborted) {
|
|
2305
2399
|
throw abortError;
|
|
2306
2400
|
}
|
|
2307
|
-
|
|
2308
|
-
throw err;
|
|
2309
|
-
}
|
|
2310
|
-
return false;
|
|
2401
|
+
return err instanceof HttpError && err.status >= 400 && err.status < 500;
|
|
2311
2402
|
};
|
|
2312
2403
|
if (file.size <= ROOM_FILE_PART_SIZE) {
|
|
2313
2404
|
return autoRetry(
|
|
@@ -2325,6 +2416,17 @@ async function uploadRoomFile({
|
|
|
2325
2416
|
ROOM_FILE_RETRY_DELAYS,
|
|
2326
2417
|
handleRetryError
|
|
2327
2418
|
);
|
|
2419
|
+
const partUploadController = new AbortController();
|
|
2420
|
+
const partUploadSignal = partUploadController.signal;
|
|
2421
|
+
const abortPartUploads = (reason) => {
|
|
2422
|
+
partUploadController.abort(reason);
|
|
2423
|
+
};
|
|
2424
|
+
const handleExternalAbort = () => abortPartUploads();
|
|
2425
|
+
if (signal?.aborted) {
|
|
2426
|
+
handleExternalAbort();
|
|
2427
|
+
} else {
|
|
2428
|
+
signal?.addEventListener("abort", handleExternalAbort, { once: true });
|
|
2429
|
+
}
|
|
2328
2430
|
try {
|
|
2329
2431
|
uploadId = multipartUpload.uploadId;
|
|
2330
2432
|
if (signal?.aborted) {
|
|
@@ -2332,34 +2434,66 @@ async function uploadRoomFile({
|
|
|
2332
2434
|
}
|
|
2333
2435
|
const batches = chunk(splitFileIntoParts(file), 5);
|
|
2334
2436
|
for (const parts of batches) {
|
|
2335
|
-
const
|
|
2437
|
+
const firstPartUploadFailure = {};
|
|
2438
|
+
const partUploads$ = [];
|
|
2336
2439
|
for (const { part, partNumber } of parts) {
|
|
2337
|
-
|
|
2440
|
+
partUploads$.push(
|
|
2338
2441
|
autoRetry(
|
|
2339
|
-
() => uploadMultipartPart(
|
|
2442
|
+
() => uploadMultipartPart(
|
|
2443
|
+
multipartUpload.uploadId,
|
|
2444
|
+
partNumber,
|
|
2445
|
+
part,
|
|
2446
|
+
partUploadSignal
|
|
2447
|
+
),
|
|
2340
2448
|
ROOM_FILE_RETRY_ATTEMPTS,
|
|
2341
2449
|
ROOM_FILE_RETRY_DELAYS,
|
|
2342
|
-
|
|
2343
|
-
|
|
2450
|
+
(error3) => {
|
|
2451
|
+
if (signal?.aborted) {
|
|
2452
|
+
throw abortError;
|
|
2453
|
+
}
|
|
2454
|
+
return partUploadSignal.aborted || handleRetryError(error3);
|
|
2455
|
+
}
|
|
2456
|
+
).catch((error3) => {
|
|
2457
|
+
if (firstPartUploadFailure.value === void 0) {
|
|
2458
|
+
firstPartUploadFailure.value = { error: error3 };
|
|
2459
|
+
abortPartUploads(error3);
|
|
2460
|
+
}
|
|
2461
|
+
throw error3;
|
|
2462
|
+
})
|
|
2344
2463
|
);
|
|
2345
2464
|
}
|
|
2346
|
-
|
|
2465
|
+
const settledPartUploads = await Promise.allSettled(partUploads$);
|
|
2466
|
+
if (firstPartUploadFailure.value !== void 0) {
|
|
2467
|
+
throw firstPartUploadFailure.value.error;
|
|
2468
|
+
}
|
|
2469
|
+
for (const settledPartUpload of settledPartUploads) {
|
|
2470
|
+
if (settledPartUpload.status === "fulfilled") {
|
|
2471
|
+
uploadedParts.push(settledPartUpload.value);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2347
2474
|
}
|
|
2348
2475
|
if (signal?.aborted) {
|
|
2349
2476
|
throw abortError;
|
|
2350
2477
|
}
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
uploadedParts.sort((a, b) => a.partNumber - b.partNumber)
|
|
2478
|
+
const sortedParts = uploadedParts.sort(
|
|
2479
|
+
(a, b) => a.partNumber - b.partNumber
|
|
2354
2480
|
);
|
|
2481
|
+
return retryMultipartCompletion ? autoRetry(
|
|
2482
|
+
() => completeMultipartUpload(multipartUpload.uploadId, sortedParts),
|
|
2483
|
+
ROOM_FILE_RETRY_ATTEMPTS,
|
|
2484
|
+
ROOM_FILE_RETRY_DELAYS,
|
|
2485
|
+
handleRetryError
|
|
2486
|
+
) : completeMultipartUpload(uploadId, sortedParts);
|
|
2355
2487
|
} catch (error3) {
|
|
2356
|
-
if (uploadId
|
|
2488
|
+
if (uploadId) {
|
|
2357
2489
|
try {
|
|
2358
2490
|
await abortMultipartUpload(uploadId);
|
|
2359
2491
|
} catch {
|
|
2360
2492
|
}
|
|
2361
2493
|
}
|
|
2362
2494
|
throw error3;
|
|
2495
|
+
} finally {
|
|
2496
|
+
signal?.removeEventListener("abort", handleExternalAbort);
|
|
2363
2497
|
}
|
|
2364
2498
|
}
|
|
2365
2499
|
function splitFileIntoParts(file) {
|
|
@@ -2375,9 +2509,6 @@ function splitFileIntoParts(file) {
|
|
|
2375
2509
|
}
|
|
2376
2510
|
return parts;
|
|
2377
2511
|
}
|
|
2378
|
-
function isAbortOrTimeoutError(error3) {
|
|
2379
|
-
return error3 instanceof Error && (error3.name === "AbortError" || error3.name === "TimeoutError");
|
|
2380
|
-
}
|
|
2381
2512
|
function createAbortError(message) {
|
|
2382
2513
|
if (typeof DOMException === "function") {
|
|
2383
2514
|
return new DOMException(message, "AbortError");
|
|
@@ -2706,6 +2837,7 @@ function createApiClient({
|
|
|
2706
2837
|
file: attachment.file,
|
|
2707
2838
|
signal: options.signal,
|
|
2708
2839
|
abortErrorMessage: `Upload of attachment ${attachment.id} was aborted.`,
|
|
2840
|
+
retryMultipartCompletion: false,
|
|
2709
2841
|
uploadSingle: async () => httpClient.putBlob(
|
|
2710
2842
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${attachment.name}`,
|
|
2711
2843
|
await authManager.getAuthValue({
|
|
@@ -2728,7 +2860,7 @@ function createApiClient({
|
|
|
2728
2860
|
{ signal: options.signal },
|
|
2729
2861
|
{ fileSize: attachment.size }
|
|
2730
2862
|
),
|
|
2731
|
-
uploadMultipartPart: async (uploadId, partNumber, part) => httpClient.putBlob(
|
|
2863
|
+
uploadMultipartPart: async (uploadId, partNumber, part, signal) => httpClient.putBlob(
|
|
2732
2864
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/${String(partNumber)}`,
|
|
2733
2865
|
await authManager.getAuthValue({
|
|
2734
2866
|
roomId,
|
|
@@ -2737,7 +2869,7 @@ function createApiClient({
|
|
|
2737
2869
|
}),
|
|
2738
2870
|
part,
|
|
2739
2871
|
void 0,
|
|
2740
|
-
{ signal
|
|
2872
|
+
{ signal }
|
|
2741
2873
|
),
|
|
2742
2874
|
completeMultipartUpload: async (uploadId, parts) => httpClient.post(
|
|
2743
2875
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/complete`,
|
|
@@ -2769,6 +2901,7 @@ function createApiClient({
|
|
|
2769
2901
|
file,
|
|
2770
2902
|
signal: options.signal,
|
|
2771
2903
|
abortErrorMessage: `Upload of file ${fileId} was aborted.`,
|
|
2904
|
+
retryMultipartCompletion: true,
|
|
2772
2905
|
uploadSingle: async () => httpClient.putBlob(
|
|
2773
2906
|
url`/v2/c/rooms/${roomId}/storage/files/${fileId}/upload/${file.name}`,
|
|
2774
2907
|
await authManager.getAuthValue({
|
|
@@ -2791,7 +2924,7 @@ function createApiClient({
|
|
|
2791
2924
|
{ signal: options.signal },
|
|
2792
2925
|
{ fileSize: file.size }
|
|
2793
2926
|
),
|
|
2794
|
-
uploadMultipartPart: async (uploadId, partNumber, part) => httpClient.putBlob(
|
|
2927
|
+
uploadMultipartPart: async (uploadId, partNumber, part, signal) => httpClient.putBlob(
|
|
2795
2928
|
url`/v2/c/rooms/${roomId}/storage/files/${fileId}/multipart/${uploadId}/${String(partNumber)}`,
|
|
2796
2929
|
await authManager.getAuthValue({
|
|
2797
2930
|
roomId,
|
|
@@ -2800,7 +2933,7 @@ function createApiClient({
|
|
|
2800
2933
|
}),
|
|
2801
2934
|
part,
|
|
2802
2935
|
void 0,
|
|
2803
|
-
{ signal
|
|
2936
|
+
{ signal }
|
|
2804
2937
|
),
|
|
2805
2938
|
completeMultipartUpload: async (uploadId, parts) => httpClient.post(
|
|
2806
2939
|
url`/v2/c/rooms/${roomId}/storage/files/${fileId}/multipart/${uploadId}/complete`,
|
|
@@ -2854,10 +2987,37 @@ function createApiClient({
|
|
|
2854
2987
|
return batch2.get(options.attachmentId);
|
|
2855
2988
|
}
|
|
2856
2989
|
const fileUrlsBatchStoresByRoom = new DefaultMap((roomId) => {
|
|
2990
|
+
const pendingFileUrlAttempts = /* @__PURE__ */ new Map();
|
|
2991
|
+
const clearPendingFileUrlAttempts = (fileId) => {
|
|
2992
|
+
const attempts = pendingFileUrlAttempts.get(fileId);
|
|
2993
|
+
if (attempts !== void 0) {
|
|
2994
|
+
clearTimeout(attempts.cleanupTimeoutId);
|
|
2995
|
+
pendingFileUrlAttempts.delete(fileId);
|
|
2996
|
+
}
|
|
2997
|
+
};
|
|
2998
|
+
const shouldRetryPendingFileUrl = (fileId) => {
|
|
2999
|
+
const previousAttempts = pendingFileUrlAttempts.get(fileId);
|
|
3000
|
+
if (previousAttempts !== void 0) {
|
|
3001
|
+
clearTimeout(previousAttempts.cleanupTimeoutId);
|
|
3002
|
+
}
|
|
3003
|
+
const count = (previousAttempts?.count ?? 0) + 1;
|
|
3004
|
+
if (count >= FILE_URL_ERROR_MAX_ATTEMPTS) {
|
|
3005
|
+
pendingFileUrlAttempts.delete(fileId);
|
|
3006
|
+
return false;
|
|
3007
|
+
}
|
|
3008
|
+
pendingFileUrlAttempts.set(fileId, {
|
|
3009
|
+
count,
|
|
3010
|
+
cleanupTimeoutId: setTimeout(
|
|
3011
|
+
() => pendingFileUrlAttempts.delete(fileId),
|
|
3012
|
+
FILE_URL_ERROR_ATTEMPTS_EXPIRY
|
|
3013
|
+
)
|
|
3014
|
+
});
|
|
3015
|
+
return true;
|
|
3016
|
+
};
|
|
2857
3017
|
const batch2 = new Batch(
|
|
2858
3018
|
async (batchedFileIds) => {
|
|
2859
3019
|
const fileIds = batchedFileIds.flat();
|
|
2860
|
-
const { urls } = await httpClient.post(
|
|
3020
|
+
const { urls, expiresAt } = await httpClient.post(
|
|
2861
3021
|
url`/v2/c/rooms/${roomId}/storage/files/presigned-urls`,
|
|
2862
3022
|
await authManager.getAuthValue({
|
|
2863
3023
|
roomId,
|
|
@@ -2866,20 +3026,31 @@ function createApiClient({
|
|
|
2866
3026
|
}),
|
|
2867
3027
|
{ fileIds }
|
|
2868
3028
|
);
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
3029
|
+
const expiresAtTimestamp = Date.parse(expiresAt);
|
|
3030
|
+
return urls.map((url2, index) => {
|
|
3031
|
+
const fileId = fileIds[index];
|
|
3032
|
+
if (url2 === false) {
|
|
3033
|
+
return shouldRetryPendingFileUrl(fileId) ? new FileUrlUnavailableError(
|
|
3034
|
+
"There was an error while getting this file's URL"
|
|
3035
|
+
) : new Error("There was an error while getting this file's URL");
|
|
3036
|
+
}
|
|
3037
|
+
clearPendingFileUrlAttempts(fileId);
|
|
3038
|
+
return url2 !== null ? { url: url2, expiresAt: expiresAtTimestamp } : new Error("There was an error while getting this file's URL");
|
|
3039
|
+
});
|
|
2872
3040
|
},
|
|
2873
3041
|
{ delay: 50 }
|
|
2874
3042
|
);
|
|
2875
|
-
return createBatchStore(batch2
|
|
3043
|
+
return createBatchStore(batch2, {
|
|
3044
|
+
getCacheExpiry: ({ expiresAt }) => expiresAt - FILE_URL_EXPIRY_BUFFER,
|
|
3045
|
+
getErrorCacheExpiry: (error3) => error3 instanceof FileUrlUnavailableError ? Date.now() + FILE_URL_ERROR_CACHE_TTL : void 0
|
|
3046
|
+
});
|
|
2876
3047
|
});
|
|
2877
3048
|
function getOrCreateFileUrlsStore(roomId) {
|
|
2878
3049
|
return fileUrlsBatchStoresByRoom.getOrCreate(roomId);
|
|
2879
3050
|
}
|
|
2880
|
-
function getFileUrl(options) {
|
|
3051
|
+
async function getFileUrl(options) {
|
|
2881
3052
|
const batch2 = getOrCreateFileUrlsStore(options.roomId).batch;
|
|
2882
|
-
return batch2.get(options.fileId);
|
|
3053
|
+
return (await batch2.get(options.fileId)).url;
|
|
2883
3054
|
}
|
|
2884
3055
|
async function getSubscriptionSettings(options) {
|
|
2885
3056
|
return httpClient.get(
|
|
@@ -8247,6 +8418,8 @@ function reconcile(live, json, config) {
|
|
|
8247
8418
|
return reconcileLiveList(live, json, config);
|
|
8248
8419
|
} else if (isLiveMap(live) && isPlainObject(json)) {
|
|
8249
8420
|
return reconcileLiveMap(live, config);
|
|
8421
|
+
} else if (isLiveFile(live) && shallow(live.data, json)) {
|
|
8422
|
+
return live;
|
|
8250
8423
|
} else {
|
|
8251
8424
|
return deepLiveify(json, config);
|
|
8252
8425
|
}
|
|
@@ -9173,8 +9346,31 @@ function isJsonEq(a, b) {
|
|
|
9173
9346
|
}
|
|
9174
9347
|
function diffNodeMap(prev, next) {
|
|
9175
9348
|
const ops = [];
|
|
9176
|
-
|
|
9177
|
-
|
|
9349
|
+
const idsToRecreate = /* @__PURE__ */ new Set();
|
|
9350
|
+
next.forEach((nextCrdt, id) => {
|
|
9351
|
+
const currentCrdt = prev.get(id);
|
|
9352
|
+
if (currentCrdt === void 0) {
|
|
9353
|
+
return;
|
|
9354
|
+
}
|
|
9355
|
+
if (currentCrdt.type !== nextCrdt.type || currentCrdt.type === CrdtType.FILE && nextCrdt.type === CrdtType.FILE && (currentCrdt.data.id !== nextCrdt.data.id || currentCrdt.data.name !== nextCrdt.data.name || currentCrdt.data.size !== nextCrdt.data.size || currentCrdt.data.mimeType !== nextCrdt.data.mimeType)) {
|
|
9356
|
+
idsToRecreate.add(id);
|
|
9357
|
+
}
|
|
9358
|
+
});
|
|
9359
|
+
let foundDescendant = true;
|
|
9360
|
+
while (foundDescendant) {
|
|
9361
|
+
foundDescendant = false;
|
|
9362
|
+
for (const nodes of [prev, next]) {
|
|
9363
|
+
nodes.forEach((crdt, id) => {
|
|
9364
|
+
if (!idsToRecreate.has(id) && crdt.parentId !== void 0 && idsToRecreate.has(crdt.parentId)) {
|
|
9365
|
+
idsToRecreate.add(id);
|
|
9366
|
+
foundDescendant = true;
|
|
9367
|
+
}
|
|
9368
|
+
});
|
|
9369
|
+
}
|
|
9370
|
+
}
|
|
9371
|
+
prev.forEach((crdt, id) => {
|
|
9372
|
+
const parentWillBeRecreated = crdt.parentId !== void 0 && idsToRecreate.has(crdt.parentId);
|
|
9373
|
+
if ((!next.has(id) || idsToRecreate.has(id)) && !parentWillBeRecreated) {
|
|
9178
9374
|
ops.push({ type: OpCode.DELETE_CRDT, id });
|
|
9179
9375
|
}
|
|
9180
9376
|
});
|
|
@@ -9185,7 +9381,7 @@ function diffNodeMap(prev, next) {
|
|
|
9185
9381
|
}
|
|
9186
9382
|
emitted.add(id);
|
|
9187
9383
|
const parentId = crdt.parentId;
|
|
9188
|
-
if (parentId !== void 0 && !prev.has(parentId)) {
|
|
9384
|
+
if (parentId !== void 0 && (!prev.has(parentId) || idsToRecreate.has(parentId))) {
|
|
9189
9385
|
const parentCrdt = next.get(parentId);
|
|
9190
9386
|
if (parentCrdt !== void 0) {
|
|
9191
9387
|
emitCreate(parentId, parentCrdt);
|
|
@@ -9244,29 +9440,25 @@ function diffNodeMap(prev, next) {
|
|
|
9244
9440
|
}
|
|
9245
9441
|
next.forEach((crdt, id) => {
|
|
9246
9442
|
const currentCrdt = prev.get(id);
|
|
9247
|
-
if (currentCrdt) {
|
|
9248
|
-
if (crdt.type === CrdtType.OBJECT) {
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
const value = crdt.data[key];
|
|
9255
|
-
if (value !== void 0 && !isJsonEq(value, currentCrdt.data[key])) {
|
|
9256
|
-
changed.set(key, value);
|
|
9257
|
-
}
|
|
9258
|
-
}
|
|
9259
|
-
if (changed.size > 0) {
|
|
9260
|
-
ops.push({
|
|
9261
|
-
type: OpCode.UPDATE_OBJECT,
|
|
9262
|
-
id,
|
|
9263
|
-
data: Object.fromEntries(changed)
|
|
9264
|
-
});
|
|
9443
|
+
if (currentCrdt && !idsToRecreate.has(id)) {
|
|
9444
|
+
if (crdt.type === CrdtType.OBJECT && currentCrdt.type === CrdtType.OBJECT) {
|
|
9445
|
+
const changed = /* @__PURE__ */ new Map();
|
|
9446
|
+
for (const key of Object.keys(crdt.data)) {
|
|
9447
|
+
const value = crdt.data[key];
|
|
9448
|
+
if (value !== void 0 && !isJsonEq(value, currentCrdt.data[key])) {
|
|
9449
|
+
changed.set(key, value);
|
|
9265
9450
|
}
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9451
|
+
}
|
|
9452
|
+
if (changed.size > 0) {
|
|
9453
|
+
ops.push({
|
|
9454
|
+
type: OpCode.UPDATE_OBJECT,
|
|
9455
|
+
id,
|
|
9456
|
+
data: Object.fromEntries(changed)
|
|
9457
|
+
});
|
|
9458
|
+
}
|
|
9459
|
+
for (const key of Object.keys(currentCrdt.data)) {
|
|
9460
|
+
if (!(key in crdt.data)) {
|
|
9461
|
+
ops.push({ type: OpCode.DELETE_OBJECT_KEY, id, key });
|
|
9270
9462
|
}
|
|
9271
9463
|
}
|
|
9272
9464
|
}
|