@liveblocks/core 3.22.0-file1 → 3.22.0
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 +447 -635
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +231 -292
- package/dist/index.d.ts +231 -292
- package/dist/index.js +285 -473
- 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.22.0
|
|
9
|
+
var PKG_VERSION = "3.22.0";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1309,7 +1309,6 @@ var nanoid = (t = 21) => crypto.getRandomValues(new Uint8Array(t)).reduce(
|
|
|
1309
1309
|
var THREAD_ID_PREFIX = "th";
|
|
1310
1310
|
var COMMENT_ID_PREFIX = "cm";
|
|
1311
1311
|
var COMMENT_ATTACHMENT_ID_PREFIX = "at";
|
|
1312
|
-
var STORAGE_FILE_ID_PREFIX = "fl";
|
|
1313
1312
|
var INBOX_NOTIFICATION_ID_PREFIX = "in";
|
|
1314
1313
|
function createOptimisticId(prefix) {
|
|
1315
1314
|
return `${prefix}_${nanoid()}`;
|
|
@@ -1323,9 +1322,6 @@ function createCommentId() {
|
|
|
1323
1322
|
function createCommentAttachmentId() {
|
|
1324
1323
|
return createOptimisticId(COMMENT_ATTACHMENT_ID_PREFIX);
|
|
1325
1324
|
}
|
|
1326
|
-
function createStorageFileId() {
|
|
1327
|
-
return createOptimisticId(STORAGE_FILE_ID_PREFIX);
|
|
1328
|
-
}
|
|
1329
1325
|
function createInboxNotificationId() {
|
|
1330
1326
|
return createOptimisticId(INBOX_NOTIFICATION_ID_PREFIX);
|
|
1331
1327
|
}
|
|
@@ -1571,120 +1567,6 @@ function isUrl(string) {
|
|
|
1571
1567
|
}
|
|
1572
1568
|
|
|
1573
1569
|
// src/api-client.ts
|
|
1574
|
-
var ROOM_FILE_PART_SIZE = 5 * 1024 * 1024;
|
|
1575
|
-
var ROOM_FILE_RETRY_ATTEMPTS = 10;
|
|
1576
|
-
var ROOM_FILE_RETRY_DELAYS = [
|
|
1577
|
-
2e3,
|
|
1578
|
-
2e3,
|
|
1579
|
-
2e3,
|
|
1580
|
-
2e3,
|
|
1581
|
-
2e3,
|
|
1582
|
-
2e3,
|
|
1583
|
-
2e3,
|
|
1584
|
-
2e3,
|
|
1585
|
-
2e3,
|
|
1586
|
-
2e3
|
|
1587
|
-
];
|
|
1588
|
-
async function uploadRoomFile({
|
|
1589
|
-
file,
|
|
1590
|
-
signal,
|
|
1591
|
-
abortErrorMessage,
|
|
1592
|
-
uploadSingle,
|
|
1593
|
-
createMultipartUpload,
|
|
1594
|
-
uploadMultipartPart,
|
|
1595
|
-
completeMultipartUpload,
|
|
1596
|
-
abortMultipartUpload
|
|
1597
|
-
}) {
|
|
1598
|
-
const abortError = createAbortError(abortErrorMessage);
|
|
1599
|
-
if (signal?.aborted) {
|
|
1600
|
-
throw abortError;
|
|
1601
|
-
}
|
|
1602
|
-
const handleRetryError = (err) => {
|
|
1603
|
-
if (signal?.aborted) {
|
|
1604
|
-
throw abortError;
|
|
1605
|
-
}
|
|
1606
|
-
if (err instanceof HttpError && err.status === 413) {
|
|
1607
|
-
throw err;
|
|
1608
|
-
}
|
|
1609
|
-
return false;
|
|
1610
|
-
};
|
|
1611
|
-
if (file.size <= ROOM_FILE_PART_SIZE) {
|
|
1612
|
-
return autoRetry(
|
|
1613
|
-
uploadSingle,
|
|
1614
|
-
ROOM_FILE_RETRY_ATTEMPTS,
|
|
1615
|
-
ROOM_FILE_RETRY_DELAYS,
|
|
1616
|
-
handleRetryError
|
|
1617
|
-
);
|
|
1618
|
-
}
|
|
1619
|
-
let uploadId;
|
|
1620
|
-
const uploadedParts = [];
|
|
1621
|
-
const multipartUpload = await autoRetry(
|
|
1622
|
-
createMultipartUpload,
|
|
1623
|
-
ROOM_FILE_RETRY_ATTEMPTS,
|
|
1624
|
-
ROOM_FILE_RETRY_DELAYS,
|
|
1625
|
-
handleRetryError
|
|
1626
|
-
);
|
|
1627
|
-
try {
|
|
1628
|
-
uploadId = multipartUpload.uploadId;
|
|
1629
|
-
if (signal?.aborted) {
|
|
1630
|
-
throw abortError;
|
|
1631
|
-
}
|
|
1632
|
-
const batches = chunk(splitFileIntoParts(file), 5);
|
|
1633
|
-
for (const parts of batches) {
|
|
1634
|
-
const uploadedPartsPromises = [];
|
|
1635
|
-
for (const { part, partNumber } of parts) {
|
|
1636
|
-
uploadedPartsPromises.push(
|
|
1637
|
-
autoRetry(
|
|
1638
|
-
() => uploadMultipartPart(multipartUpload.uploadId, partNumber, part),
|
|
1639
|
-
ROOM_FILE_RETRY_ATTEMPTS,
|
|
1640
|
-
ROOM_FILE_RETRY_DELAYS,
|
|
1641
|
-
handleRetryError
|
|
1642
|
-
)
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
uploadedParts.push(...await Promise.all(uploadedPartsPromises));
|
|
1646
|
-
}
|
|
1647
|
-
if (signal?.aborted) {
|
|
1648
|
-
throw abortError;
|
|
1649
|
-
}
|
|
1650
|
-
return completeMultipartUpload(
|
|
1651
|
-
uploadId,
|
|
1652
|
-
uploadedParts.sort((a, b) => a.partNumber - b.partNumber)
|
|
1653
|
-
);
|
|
1654
|
-
} catch (error3) {
|
|
1655
|
-
if (uploadId && isAbortOrTimeoutError(error3)) {
|
|
1656
|
-
try {
|
|
1657
|
-
await abortMultipartUpload(uploadId);
|
|
1658
|
-
} catch {
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
throw error3;
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
function splitFileIntoParts(file) {
|
|
1665
|
-
const parts = [];
|
|
1666
|
-
let start = 0;
|
|
1667
|
-
while (start < file.size) {
|
|
1668
|
-
const end = Math.min(start + ROOM_FILE_PART_SIZE, file.size);
|
|
1669
|
-
parts.push({
|
|
1670
|
-
partNumber: parts.length + 1,
|
|
1671
|
-
part: file.slice(start, end)
|
|
1672
|
-
});
|
|
1673
|
-
start = end;
|
|
1674
|
-
}
|
|
1675
|
-
return parts;
|
|
1676
|
-
}
|
|
1677
|
-
function isAbortOrTimeoutError(error3) {
|
|
1678
|
-
return error3 instanceof Error && (error3.name === "AbortError" || error3.name === "TimeoutError");
|
|
1679
|
-
}
|
|
1680
|
-
function createAbortError(message) {
|
|
1681
|
-
if (typeof DOMException === "function") {
|
|
1682
|
-
return new DOMException(message, "AbortError");
|
|
1683
|
-
}
|
|
1684
|
-
const error3 = new Error(message);
|
|
1685
|
-
error3.name = "AbortError";
|
|
1686
|
-
return error3;
|
|
1687
|
-
}
|
|
1688
1570
|
function commentsResourceForVisibility(visibility) {
|
|
1689
1571
|
if (visibility === "private") {
|
|
1690
1572
|
return "comments:private";
|
|
@@ -2000,128 +1882,151 @@ function createApiClient({
|
|
|
2000
1882
|
}
|
|
2001
1883
|
async function uploadAttachment(options) {
|
|
2002
1884
|
const roomId = options.roomId;
|
|
1885
|
+
const abortSignal = options.signal;
|
|
2003
1886
|
const attachment = options.attachment;
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
{
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
abortMultipartUpload: async (uploadId) => {
|
|
2052
|
-
await httpClient.rawDelete(
|
|
2053
|
-
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
|
|
1887
|
+
const abortError = abortSignal ? new DOMException(
|
|
1888
|
+
`Upload of attachment ${options.attachment.id} was aborted.`,
|
|
1889
|
+
"AbortError"
|
|
1890
|
+
) : void 0;
|
|
1891
|
+
if (abortSignal?.aborted) {
|
|
1892
|
+
throw abortError;
|
|
1893
|
+
}
|
|
1894
|
+
const handleRetryError = (err) => {
|
|
1895
|
+
if (abortSignal?.aborted) {
|
|
1896
|
+
throw abortError;
|
|
1897
|
+
}
|
|
1898
|
+
if (err instanceof HttpError && err.status === 413) {
|
|
1899
|
+
throw err;
|
|
1900
|
+
}
|
|
1901
|
+
return false;
|
|
1902
|
+
};
|
|
1903
|
+
const ATTACHMENT_PART_SIZE = 5 * 1024 * 1024;
|
|
1904
|
+
const RETRY_ATTEMPTS = 10;
|
|
1905
|
+
const RETRY_DELAYS = [
|
|
1906
|
+
2e3,
|
|
1907
|
+
2e3,
|
|
1908
|
+
2e3,
|
|
1909
|
+
2e3,
|
|
1910
|
+
2e3,
|
|
1911
|
+
2e3,
|
|
1912
|
+
2e3,
|
|
1913
|
+
2e3,
|
|
1914
|
+
2e3,
|
|
1915
|
+
2e3
|
|
1916
|
+
];
|
|
1917
|
+
function splitFileIntoParts(file) {
|
|
1918
|
+
const parts = [];
|
|
1919
|
+
let start = 0;
|
|
1920
|
+
while (start < file.size) {
|
|
1921
|
+
const end = Math.min(start + ATTACHMENT_PART_SIZE, file.size);
|
|
1922
|
+
parts.push({
|
|
1923
|
+
partNumber: parts.length + 1,
|
|
1924
|
+
part: file.slice(start, end)
|
|
1925
|
+
});
|
|
1926
|
+
start = end;
|
|
1927
|
+
}
|
|
1928
|
+
return parts;
|
|
1929
|
+
}
|
|
1930
|
+
if (attachment.size <= ATTACHMENT_PART_SIZE) {
|
|
1931
|
+
return autoRetry(
|
|
1932
|
+
async () => httpClient.putBlob(
|
|
1933
|
+
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${attachment.name}`,
|
|
2054
1934
|
await authManager.getAuthValue({
|
|
2055
1935
|
roomId,
|
|
2056
1936
|
resource: "comments",
|
|
2057
1937
|
access: "write"
|
|
2058
|
-
})
|
|
1938
|
+
}),
|
|
1939
|
+
attachment.file,
|
|
1940
|
+
{ fileSize: attachment.size },
|
|
1941
|
+
{ signal: abortSignal }
|
|
1942
|
+
),
|
|
1943
|
+
RETRY_ATTEMPTS,
|
|
1944
|
+
RETRY_DELAYS,
|
|
1945
|
+
handleRetryError
|
|
1946
|
+
);
|
|
1947
|
+
} else {
|
|
1948
|
+
let uploadId;
|
|
1949
|
+
const uploadedParts = [];
|
|
1950
|
+
const createMultiPartUpload = await autoRetry(
|
|
1951
|
+
async () => httpClient.post(
|
|
1952
|
+
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${attachment.name}`,
|
|
1953
|
+
await authManager.getAuthValue({
|
|
1954
|
+
roomId,
|
|
1955
|
+
resource: "comments",
|
|
1956
|
+
access: "write"
|
|
1957
|
+
}),
|
|
1958
|
+
void 0,
|
|
1959
|
+
{ signal: abortSignal },
|
|
1960
|
+
{ fileSize: attachment.size }
|
|
1961
|
+
),
|
|
1962
|
+
RETRY_ATTEMPTS,
|
|
1963
|
+
RETRY_DELAYS,
|
|
1964
|
+
handleRetryError
|
|
1965
|
+
);
|
|
1966
|
+
try {
|
|
1967
|
+
uploadId = createMultiPartUpload.uploadId;
|
|
1968
|
+
const parts = splitFileIntoParts(attachment.file);
|
|
1969
|
+
if (abortSignal?.aborted) {
|
|
1970
|
+
throw abortError;
|
|
1971
|
+
}
|
|
1972
|
+
const batches = chunk(parts, 5);
|
|
1973
|
+
for (const parts2 of batches) {
|
|
1974
|
+
const uploadedPartsPromises = [];
|
|
1975
|
+
for (const { part, partNumber } of parts2) {
|
|
1976
|
+
uploadedPartsPromises.push(
|
|
1977
|
+
autoRetry(
|
|
1978
|
+
async () => httpClient.putBlob(
|
|
1979
|
+
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${createMultiPartUpload.uploadId}/${String(partNumber)}`,
|
|
1980
|
+
await authManager.getAuthValue({
|
|
1981
|
+
roomId,
|
|
1982
|
+
resource: "comments",
|
|
1983
|
+
access: "write"
|
|
1984
|
+
}),
|
|
1985
|
+
part,
|
|
1986
|
+
void 0,
|
|
1987
|
+
{ signal: abortSignal }
|
|
1988
|
+
),
|
|
1989
|
+
RETRY_ATTEMPTS,
|
|
1990
|
+
RETRY_DELAYS,
|
|
1991
|
+
handleRetryError
|
|
1992
|
+
)
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
uploadedParts.push(...await Promise.all(uploadedPartsPromises));
|
|
1996
|
+
}
|
|
1997
|
+
if (abortSignal?.aborted) {
|
|
1998
|
+
throw abortError;
|
|
1999
|
+
}
|
|
2000
|
+
const sortedUploadedParts = uploadedParts.sort(
|
|
2001
|
+
(a, b) => a.partNumber - b.partNumber
|
|
2059
2002
|
);
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
}
|
|
2063
|
-
async function uploadFile(options) {
|
|
2064
|
-
const roomId = options.roomId;
|
|
2065
|
-
const file = options.file;
|
|
2066
|
-
const fileId = createStorageFileId();
|
|
2067
|
-
return uploadRoomFile({
|
|
2068
|
-
file,
|
|
2069
|
-
signal: options.signal,
|
|
2070
|
-
abortErrorMessage: `Upload of file ${fileId} was aborted.`,
|
|
2071
|
-
uploadSingle: async () => httpClient.putBlob(
|
|
2072
|
-
url`/v2/c/rooms/${roomId}/storage-files/${fileId}/upload/${encodeURIComponent(file.name)}`,
|
|
2073
|
-
await authManager.getAuthValue({
|
|
2074
|
-
roomId,
|
|
2075
|
-
resource: "storage",
|
|
2076
|
-
access: "write"
|
|
2077
|
-
}),
|
|
2078
|
-
file,
|
|
2079
|
-
{ fileSize: file.size },
|
|
2080
|
-
{ signal: options.signal }
|
|
2081
|
-
),
|
|
2082
|
-
createMultipartUpload: async () => httpClient.post(
|
|
2083
|
-
url`/v2/c/rooms/${roomId}/storage-files/${fileId}/multipart/${encodeURIComponent(file.name)}`,
|
|
2084
|
-
await authManager.getAuthValue({
|
|
2085
|
-
roomId,
|
|
2086
|
-
resource: "storage",
|
|
2087
|
-
access: "write"
|
|
2088
|
-
}),
|
|
2089
|
-
void 0,
|
|
2090
|
-
{ signal: options.signal },
|
|
2091
|
-
{ fileSize: file.size }
|
|
2092
|
-
),
|
|
2093
|
-
uploadMultipartPart: async (uploadId, partNumber, part) => httpClient.putBlob(
|
|
2094
|
-
url`/v2/c/rooms/${roomId}/storage-files/${fileId}/multipart/${uploadId}/${String(partNumber)}`,
|
|
2095
|
-
await authManager.getAuthValue({
|
|
2096
|
-
roomId,
|
|
2097
|
-
resource: "storage",
|
|
2098
|
-
access: "write"
|
|
2099
|
-
}),
|
|
2100
|
-
part,
|
|
2101
|
-
void 0,
|
|
2102
|
-
{ signal: options.signal }
|
|
2103
|
-
),
|
|
2104
|
-
completeMultipartUpload: async (uploadId, parts) => httpClient.post(
|
|
2105
|
-
url`/v2/c/rooms/${roomId}/storage-files/${fileId}/multipart/${uploadId}/complete`,
|
|
2106
|
-
await authManager.getAuthValue({
|
|
2107
|
-
roomId,
|
|
2108
|
-
resource: "storage",
|
|
2109
|
-
access: "write"
|
|
2110
|
-
}),
|
|
2111
|
-
{ parts },
|
|
2112
|
-
{ signal: options.signal }
|
|
2113
|
-
),
|
|
2114
|
-
abortMultipartUpload: async (uploadId) => {
|
|
2115
|
-
await httpClient.rawDelete(
|
|
2116
|
-
url`/v2/c/rooms/${roomId}/storage-files/${fileId}/multipart/${uploadId}`,
|
|
2003
|
+
return httpClient.post(
|
|
2004
|
+
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/complete`,
|
|
2117
2005
|
await authManager.getAuthValue({
|
|
2118
2006
|
roomId,
|
|
2119
|
-
resource: "
|
|
2007
|
+
resource: "comments",
|
|
2120
2008
|
access: "write"
|
|
2121
|
-
})
|
|
2009
|
+
}),
|
|
2010
|
+
{ parts: sortedUploadedParts },
|
|
2011
|
+
{ signal: abortSignal }
|
|
2122
2012
|
);
|
|
2013
|
+
} catch (error3) {
|
|
2014
|
+
if (uploadId && error3?.name && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
|
|
2015
|
+
try {
|
|
2016
|
+
await httpClient.rawDelete(
|
|
2017
|
+
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
|
|
2018
|
+
await authManager.getAuthValue({
|
|
2019
|
+
roomId,
|
|
2020
|
+
resource: "comments",
|
|
2021
|
+
access: "write"
|
|
2022
|
+
})
|
|
2023
|
+
);
|
|
2024
|
+
} catch {
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
throw error3;
|
|
2123
2028
|
}
|
|
2124
|
-
}
|
|
2029
|
+
}
|
|
2125
2030
|
}
|
|
2126
2031
|
const attachmentUrlsBatchStoresByRoom = new DefaultMap((roomId) => {
|
|
2127
2032
|
const batch2 = new Batch(
|
|
@@ -2151,34 +2056,6 @@ function createApiClient({
|
|
|
2151
2056
|
const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).batch;
|
|
2152
2057
|
return batch2.get(options.attachmentId);
|
|
2153
2058
|
}
|
|
2154
|
-
const fileUrlsBatchStoresByRoom = new DefaultMap((roomId) => {
|
|
2155
|
-
const batch2 = new Batch(
|
|
2156
|
-
async (batchedFileIds) => {
|
|
2157
|
-
const fileIds = batchedFileIds.flat();
|
|
2158
|
-
const { urls } = await httpClient.post(
|
|
2159
|
-
url`/v2/c/rooms/${roomId}/storage-files/presigned-urls`,
|
|
2160
|
-
await authManager.getAuthValue({
|
|
2161
|
-
roomId,
|
|
2162
|
-
resource: "storage",
|
|
2163
|
-
access: "read"
|
|
2164
|
-
}),
|
|
2165
|
-
{ fileIds }
|
|
2166
|
-
);
|
|
2167
|
-
return urls.map(
|
|
2168
|
-
(url2) => url2 ?? new Error("There was an error while getting this file's URL")
|
|
2169
|
-
);
|
|
2170
|
-
},
|
|
2171
|
-
{ delay: 50 }
|
|
2172
|
-
);
|
|
2173
|
-
return createBatchStore(batch2);
|
|
2174
|
-
});
|
|
2175
|
-
function getOrCreateFileUrlsStore(roomId) {
|
|
2176
|
-
return fileUrlsBatchStoresByRoom.getOrCreate(roomId);
|
|
2177
|
-
}
|
|
2178
|
-
function getFileUrl(options) {
|
|
2179
|
-
const batch2 = getOrCreateFileUrlsStore(options.roomId).batch;
|
|
2180
|
-
return batch2.get(options.fileId);
|
|
2181
|
-
}
|
|
2182
2059
|
async function getSubscriptionSettings(options) {
|
|
2183
2060
|
return httpClient.get(
|
|
2184
2061
|
url`/v2/c/rooms/${options.roomId}/subscription-settings`,
|
|
@@ -2255,7 +2132,17 @@ function createApiClient({
|
|
|
2255
2132
|
})
|
|
2256
2133
|
);
|
|
2257
2134
|
}
|
|
2258
|
-
async function
|
|
2135
|
+
async function fetchStorageHistoryVersion(options) {
|
|
2136
|
+
return httpClient.rawGet(
|
|
2137
|
+
url`/v2/c/rooms/${options.roomId}/versions/${options.versionId}/storage`,
|
|
2138
|
+
await authManager.getAuthValue({
|
|
2139
|
+
roomId: options.roomId,
|
|
2140
|
+
resource: "storage",
|
|
2141
|
+
access: "read"
|
|
2142
|
+
})
|
|
2143
|
+
);
|
|
2144
|
+
}
|
|
2145
|
+
async function fetchYjsHistoryVersion(options) {
|
|
2259
2146
|
return httpClient.rawGet(
|
|
2260
2147
|
url`/v2/c/rooms/${options.roomId}/versions/${options.versionId}/yjs`,
|
|
2261
2148
|
await authManager.getAuthValue({
|
|
@@ -2275,6 +2162,16 @@ function createApiClient({
|
|
|
2275
2162
|
})
|
|
2276
2163
|
);
|
|
2277
2164
|
}
|
|
2165
|
+
async function deleteHistoryVersion(options) {
|
|
2166
|
+
await httpClient.delete(
|
|
2167
|
+
url`/v2/c/rooms/${options.roomId}/versions/${options.versionId}`,
|
|
2168
|
+
await authManager.getAuthValue({
|
|
2169
|
+
roomId: options.roomId,
|
|
2170
|
+
resource: "storage",
|
|
2171
|
+
access: "write"
|
|
2172
|
+
})
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2278
2175
|
async function reportTextEditor(options) {
|
|
2279
2176
|
await httpClient.rawPost(
|
|
2280
2177
|
url`/v2/c/rooms/${options.roomId}/text-metadata`,
|
|
@@ -2598,8 +2495,10 @@ function createApiClient({
|
|
|
2598
2495
|
// Room text editor
|
|
2599
2496
|
createTextMention,
|
|
2600
2497
|
deleteTextMention,
|
|
2601
|
-
|
|
2498
|
+
fetchStorageHistoryVersion,
|
|
2499
|
+
fetchYjsHistoryVersion,
|
|
2602
2500
|
createVersionHistorySnapshot,
|
|
2501
|
+
deleteHistoryVersion,
|
|
2603
2502
|
reportTextEditor,
|
|
2604
2503
|
listHistoryVersions,
|
|
2605
2504
|
listHistoryVersionsSince,
|
|
@@ -2607,10 +2506,6 @@ function createApiClient({
|
|
|
2607
2506
|
getAttachmentUrl,
|
|
2608
2507
|
uploadAttachment,
|
|
2609
2508
|
getOrCreateAttachmentUrlsStore,
|
|
2610
|
-
// Room storage files
|
|
2611
|
-
getFileUrl,
|
|
2612
|
-
uploadFile,
|
|
2613
|
-
getOrCreateFileUrlsStore,
|
|
2614
2509
|
// Room storage
|
|
2615
2510
|
streamStorage,
|
|
2616
2511
|
// Notifications
|
|
@@ -5942,15 +5837,13 @@ var OpCode = Object.freeze({
|
|
|
5942
5837
|
DELETE_CRDT: 5,
|
|
5943
5838
|
DELETE_OBJECT_KEY: 6,
|
|
5944
5839
|
CREATE_MAP: 7,
|
|
5945
|
-
CREATE_REGISTER: 8
|
|
5946
|
-
// 9 and 10 are reserved for the parallel LiveText work.
|
|
5947
|
-
CREATE_FILE: 11
|
|
5840
|
+
CREATE_REGISTER: 8
|
|
5948
5841
|
});
|
|
5949
5842
|
function isIgnoredOp(op) {
|
|
5950
5843
|
return op.type === OpCode.DELETE_CRDT && op.id === "ACK";
|
|
5951
5844
|
}
|
|
5952
5845
|
function isCreateOp(op) {
|
|
5953
|
-
return op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_REGISTER || op.type === OpCode.
|
|
5846
|
+
return op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_REGISTER || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_LIST;
|
|
5954
5847
|
}
|
|
5955
5848
|
|
|
5956
5849
|
// src/protocol/StorageNode.ts
|
|
@@ -5958,9 +5851,7 @@ var CrdtType = Object.freeze({
|
|
|
5958
5851
|
OBJECT: 0,
|
|
5959
5852
|
LIST: 1,
|
|
5960
5853
|
MAP: 2,
|
|
5961
|
-
REGISTER: 3
|
|
5962
|
-
// 4 is reserved for the parallel LiveText work.
|
|
5963
|
-
FILE: 5
|
|
5854
|
+
REGISTER: 3
|
|
5964
5855
|
});
|
|
5965
5856
|
function isRootStorageNode(node) {
|
|
5966
5857
|
return node[0] === "root";
|
|
@@ -5977,9 +5868,6 @@ function isMapStorageNode(node) {
|
|
|
5977
5868
|
function isRegisterStorageNode(node) {
|
|
5978
5869
|
return node[1].type === CrdtType.REGISTER;
|
|
5979
5870
|
}
|
|
5980
|
-
function isFileStorageNode(node) {
|
|
5981
|
-
return node[1].type === CrdtType.FILE;
|
|
5982
|
-
}
|
|
5983
5871
|
function isCompactRootNode(node) {
|
|
5984
5872
|
return node[0] === "root";
|
|
5985
5873
|
}
|
|
@@ -6002,9 +5890,6 @@ function* compactNodesToNodeStream(compactNodes) {
|
|
|
6002
5890
|
case CrdtType.REGISTER:
|
|
6003
5891
|
yield [cnode[0], { type: CrdtType.REGISTER, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
|
|
6004
5892
|
break;
|
|
6005
|
-
case CrdtType.FILE:
|
|
6006
|
-
yield [cnode[0], { type: CrdtType.FILE, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
|
|
6007
|
-
break;
|
|
6008
5893
|
default:
|
|
6009
5894
|
}
|
|
6010
5895
|
}
|
|
@@ -6033,10 +5918,6 @@ function* nodeStreamToCompactNodes(nodes) {
|
|
|
6033
5918
|
const id = node[0];
|
|
6034
5919
|
const crdt = node[1];
|
|
6035
5920
|
yield [id, CrdtType.REGISTER, crdt.parentId, crdt.parentKey, crdt.data];
|
|
6036
|
-
} else if (isFileStorageNode(node)) {
|
|
6037
|
-
const id = node[0];
|
|
6038
|
-
const crdt = node[1];
|
|
6039
|
-
yield [id, CrdtType.FILE, crdt.parentId, crdt.parentKey, crdt.data];
|
|
6040
5921
|
} else {
|
|
6041
5922
|
}
|
|
6042
5923
|
}
|
|
@@ -6321,7 +6202,7 @@ ${parentKey}`;
|
|
|
6321
6202
|
};
|
|
6322
6203
|
|
|
6323
6204
|
// src/crdts/AbstractCrdt.ts
|
|
6324
|
-
function createManagedPool(
|
|
6205
|
+
function createManagedPool(options) {
|
|
6325
6206
|
const {
|
|
6326
6207
|
getCurrentConnectionId,
|
|
6327
6208
|
onDispatch,
|
|
@@ -6332,7 +6213,6 @@ function createManagedPool(roomId, options) {
|
|
|
6332
6213
|
let opClock = 0;
|
|
6333
6214
|
const nodes = /* @__PURE__ */ new Map();
|
|
6334
6215
|
return {
|
|
6335
|
-
roomId,
|
|
6336
6216
|
nodes,
|
|
6337
6217
|
getNode: (id) => nodes.get(id),
|
|
6338
6218
|
addNode: (id, node) => void nodes.set(id, node),
|
|
@@ -6397,9 +6277,6 @@ var AbstractCrdt = class {
|
|
|
6397
6277
|
get _pool() {
|
|
6398
6278
|
return this.#pool;
|
|
6399
6279
|
}
|
|
6400
|
-
get roomId() {
|
|
6401
|
-
return this.#pool ? this.#pool.roomId : null;
|
|
6402
|
-
}
|
|
6403
6280
|
/** @internal */
|
|
6404
6281
|
get _id() {
|
|
6405
6282
|
return this.#id;
|
|
@@ -6549,91 +6426,6 @@ var AbstractCrdt = class {
|
|
|
6549
6426
|
}
|
|
6550
6427
|
};
|
|
6551
6428
|
|
|
6552
|
-
// src/crdts/LiveFile.ts
|
|
6553
|
-
var LiveFile = class _LiveFile extends AbstractCrdt {
|
|
6554
|
-
#data;
|
|
6555
|
-
constructor(data) {
|
|
6556
|
-
super();
|
|
6557
|
-
this.#data = Object.freeze({ ...data });
|
|
6558
|
-
}
|
|
6559
|
-
get data() {
|
|
6560
|
-
return this.#data;
|
|
6561
|
-
}
|
|
6562
|
-
get id() {
|
|
6563
|
-
return this.#data.id;
|
|
6564
|
-
}
|
|
6565
|
-
get name() {
|
|
6566
|
-
return this.#data.name;
|
|
6567
|
-
}
|
|
6568
|
-
get size() {
|
|
6569
|
-
return this.#data.size;
|
|
6570
|
-
}
|
|
6571
|
-
get mimeType() {
|
|
6572
|
-
return this.#data.mimeType;
|
|
6573
|
-
}
|
|
6574
|
-
/** @internal */
|
|
6575
|
-
static _deserialize([id, item], _parentToChildren, pool) {
|
|
6576
|
-
const file = new _LiveFile(item.data);
|
|
6577
|
-
file._attach(id, pool);
|
|
6578
|
-
return file;
|
|
6579
|
-
}
|
|
6580
|
-
/** @internal */
|
|
6581
|
-
_toOps(parentId, parentKey) {
|
|
6582
|
-
if (this._id === void 0) {
|
|
6583
|
-
throw new Error("Cannot serialize LiveFile if parent is missing");
|
|
6584
|
-
}
|
|
6585
|
-
return [
|
|
6586
|
-
{
|
|
6587
|
-
type: OpCode.CREATE_FILE,
|
|
6588
|
-
id: this._id,
|
|
6589
|
-
parentId,
|
|
6590
|
-
parentKey,
|
|
6591
|
-
data: this.#data
|
|
6592
|
-
}
|
|
6593
|
-
];
|
|
6594
|
-
}
|
|
6595
|
-
/** @internal */
|
|
6596
|
-
_serialize() {
|
|
6597
|
-
if (this.parent.type !== "HasParent") {
|
|
6598
|
-
throw new Error("Cannot serialize LiveFile if parent is missing");
|
|
6599
|
-
}
|
|
6600
|
-
return {
|
|
6601
|
-
type: CrdtType.FILE,
|
|
6602
|
-
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
6603
|
-
parentKey: this.parent.key,
|
|
6604
|
-
data: this.#data
|
|
6605
|
-
};
|
|
6606
|
-
}
|
|
6607
|
-
/** @internal */
|
|
6608
|
-
_attachChild(_op) {
|
|
6609
|
-
throw new Error("Method not implemented.");
|
|
6610
|
-
}
|
|
6611
|
-
/** @internal */
|
|
6612
|
-
_detachChild(_crdt) {
|
|
6613
|
-
throw new Error("Method not implemented.");
|
|
6614
|
-
}
|
|
6615
|
-
/** @internal */
|
|
6616
|
-
_apply(op, isLocal) {
|
|
6617
|
-
return super._apply(op, isLocal);
|
|
6618
|
-
}
|
|
6619
|
-
/** @internal */
|
|
6620
|
-
_toTreeNode(key) {
|
|
6621
|
-
return {
|
|
6622
|
-
type: "Json",
|
|
6623
|
-
id: this._id ?? nanoid(),
|
|
6624
|
-
key,
|
|
6625
|
-
payload: this.#data
|
|
6626
|
-
};
|
|
6627
|
-
}
|
|
6628
|
-
/** @internal */
|
|
6629
|
-
_toJSON() {
|
|
6630
|
-
return this.#data;
|
|
6631
|
-
}
|
|
6632
|
-
clone() {
|
|
6633
|
-
return new _LiveFile(this.#data);
|
|
6634
|
-
}
|
|
6635
|
-
};
|
|
6636
|
-
|
|
6637
6429
|
// src/crdts/LiveRegister.ts
|
|
6638
6430
|
var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
6639
6431
|
#data;
|
|
@@ -8990,8 +8782,6 @@ function creationOpToLiveNode(op) {
|
|
|
8990
8782
|
}
|
|
8991
8783
|
function creationOpToLson(op) {
|
|
8992
8784
|
switch (op.type) {
|
|
8993
|
-
case OpCode.CREATE_FILE:
|
|
8994
|
-
return new LiveFile(op.data);
|
|
8995
8785
|
case OpCode.CREATE_REGISTER:
|
|
8996
8786
|
return op.data;
|
|
8997
8787
|
case OpCode.CREATE_OBJECT:
|
|
@@ -9013,6 +8803,16 @@ function isSameNodeOrChildOf(node, parent) {
|
|
|
9013
8803
|
}
|
|
9014
8804
|
return false;
|
|
9015
8805
|
}
|
|
8806
|
+
function liveObjectFromNodeStream(nodes) {
|
|
8807
|
+
const pool = createManagedPool({
|
|
8808
|
+
getCurrentConnectionId: () => {
|
|
8809
|
+
throw new Error(
|
|
8810
|
+
"Cannot mutate a historic storage version: it is a read-only snapshot"
|
|
8811
|
+
);
|
|
8812
|
+
}
|
|
8813
|
+
});
|
|
8814
|
+
return LiveObject._fromItems(nodes, pool);
|
|
8815
|
+
}
|
|
9016
8816
|
function deserialize(node, parentToChildren, pool) {
|
|
9017
8817
|
if (isObjectStorageNode(node)) {
|
|
9018
8818
|
return LiveObject._deserialize(node, parentToChildren, pool);
|
|
@@ -9022,8 +8822,6 @@ function deserialize(node, parentToChildren, pool) {
|
|
|
9022
8822
|
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
9023
8823
|
} else if (isRegisterStorageNode(node)) {
|
|
9024
8824
|
return LiveRegister._deserialize(node, parentToChildren, pool);
|
|
9025
|
-
} else if (isFileStorageNode(node)) {
|
|
9026
|
-
return LiveFile._deserialize(node, parentToChildren, pool);
|
|
9027
8825
|
} else {
|
|
9028
8826
|
throw new Error("Unexpected CRDT type");
|
|
9029
8827
|
}
|
|
@@ -9037,14 +8835,12 @@ function deserializeToLson(node, parentToChildren, pool) {
|
|
|
9037
8835
|
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
9038
8836
|
} else if (isRegisterStorageNode(node)) {
|
|
9039
8837
|
return node[1].data;
|
|
9040
|
-
} else if (isFileStorageNode(node)) {
|
|
9041
|
-
return LiveFile._deserialize(node, parentToChildren, pool);
|
|
9042
8838
|
} else {
|
|
9043
8839
|
throw new Error("Unexpected CRDT type");
|
|
9044
8840
|
}
|
|
9045
8841
|
}
|
|
9046
8842
|
function isLiveStructure(value) {
|
|
9047
|
-
return isLiveList(value) || isLiveMap(value) || isLiveObject(value)
|
|
8843
|
+
return isLiveList(value) || isLiveMap(value) || isLiveObject(value);
|
|
9048
8844
|
}
|
|
9049
8845
|
function isLiveNode(value) {
|
|
9050
8846
|
return isLiveStructure(value) || isLiveRegister(value);
|
|
@@ -9058,9 +8854,6 @@ function isLiveMap(value) {
|
|
|
9058
8854
|
function isLiveObject(value) {
|
|
9059
8855
|
return value instanceof LiveObject;
|
|
9060
8856
|
}
|
|
9061
|
-
function isLiveFile(value) {
|
|
9062
|
-
return value instanceof LiveFile;
|
|
9063
|
-
}
|
|
9064
8857
|
function isLiveRegister(value) {
|
|
9065
8858
|
return value instanceof LiveRegister;
|
|
9066
8859
|
}
|
|
@@ -9070,14 +8863,14 @@ function cloneLson(value) {
|
|
|
9070
8863
|
function liveNodeToLson(obj) {
|
|
9071
8864
|
if (obj instanceof LiveRegister) {
|
|
9072
8865
|
return obj.data;
|
|
9073
|
-
} else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject
|
|
8866
|
+
} else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject) {
|
|
9074
8867
|
return obj;
|
|
9075
8868
|
} else {
|
|
9076
8869
|
return assertNever(obj, "Unknown AbstractCrdt");
|
|
9077
8870
|
}
|
|
9078
8871
|
}
|
|
9079
8872
|
function lsonToLiveNode(value) {
|
|
9080
|
-
if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList
|
|
8873
|
+
if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList) {
|
|
9081
8874
|
return value;
|
|
9082
8875
|
} else {
|
|
9083
8876
|
return new LiveRegister(value);
|
|
@@ -9094,8 +8887,6 @@ function dumpPool(pool) {
|
|
|
9094
8887
|
value = "<LiveList>";
|
|
9095
8888
|
} else if (node instanceof LiveMap) {
|
|
9096
8889
|
value = "<LiveMap>";
|
|
9097
|
-
} else if (node instanceof LiveFile) {
|
|
9098
|
-
value = stringifyOrLog(node.data);
|
|
9099
8890
|
} else {
|
|
9100
8891
|
value = "<LiveObject>";
|
|
9101
8892
|
}
|
|
@@ -9146,6 +8937,61 @@ function diffNodeMap(prev, next) {
|
|
|
9146
8937
|
ops.push({ type: OpCode.DELETE_CRDT, id });
|
|
9147
8938
|
}
|
|
9148
8939
|
});
|
|
8940
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
8941
|
+
function emitCreate(id, crdt) {
|
|
8942
|
+
if (emitted.has(id)) {
|
|
8943
|
+
return;
|
|
8944
|
+
}
|
|
8945
|
+
emitted.add(id);
|
|
8946
|
+
const parentId = crdt.parentId;
|
|
8947
|
+
if (parentId !== void 0 && !prev.has(parentId)) {
|
|
8948
|
+
const parentCrdt = next.get(parentId);
|
|
8949
|
+
if (parentCrdt !== void 0) {
|
|
8950
|
+
emitCreate(parentId, parentCrdt);
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
switch (crdt.type) {
|
|
8954
|
+
case CrdtType.REGISTER:
|
|
8955
|
+
ops.push({
|
|
8956
|
+
type: OpCode.CREATE_REGISTER,
|
|
8957
|
+
id,
|
|
8958
|
+
parentId: crdt.parentId,
|
|
8959
|
+
parentKey: crdt.parentKey,
|
|
8960
|
+
data: crdt.data
|
|
8961
|
+
});
|
|
8962
|
+
break;
|
|
8963
|
+
case CrdtType.LIST:
|
|
8964
|
+
ops.push({
|
|
8965
|
+
type: OpCode.CREATE_LIST,
|
|
8966
|
+
id,
|
|
8967
|
+
parentId: crdt.parentId,
|
|
8968
|
+
parentKey: crdt.parentKey
|
|
8969
|
+
});
|
|
8970
|
+
break;
|
|
8971
|
+
case CrdtType.OBJECT:
|
|
8972
|
+
if (crdt.parentId === void 0 || crdt.parentKey === void 0) {
|
|
8973
|
+
throw new Error(
|
|
8974
|
+
"Internal error. Cannot serialize storage root into an operation"
|
|
8975
|
+
);
|
|
8976
|
+
}
|
|
8977
|
+
ops.push({
|
|
8978
|
+
type: OpCode.CREATE_OBJECT,
|
|
8979
|
+
id,
|
|
8980
|
+
parentId: crdt.parentId,
|
|
8981
|
+
parentKey: crdt.parentKey,
|
|
8982
|
+
data: crdt.data
|
|
8983
|
+
});
|
|
8984
|
+
break;
|
|
8985
|
+
case CrdtType.MAP:
|
|
8986
|
+
ops.push({
|
|
8987
|
+
type: OpCode.CREATE_MAP,
|
|
8988
|
+
id,
|
|
8989
|
+
parentId: crdt.parentId,
|
|
8990
|
+
parentKey: crdt.parentKey
|
|
8991
|
+
});
|
|
8992
|
+
break;
|
|
8993
|
+
}
|
|
8994
|
+
}
|
|
9149
8995
|
next.forEach((crdt, id) => {
|
|
9150
8996
|
const currentCrdt = prev.get(id);
|
|
9151
8997
|
if (currentCrdt) {
|
|
@@ -9182,56 +9028,7 @@ function diffNodeMap(prev, next) {
|
|
|
9182
9028
|
});
|
|
9183
9029
|
}
|
|
9184
9030
|
} else {
|
|
9185
|
-
|
|
9186
|
-
case CrdtType.REGISTER:
|
|
9187
|
-
ops.push({
|
|
9188
|
-
type: OpCode.CREATE_REGISTER,
|
|
9189
|
-
id,
|
|
9190
|
-
parentId: crdt.parentId,
|
|
9191
|
-
parentKey: crdt.parentKey,
|
|
9192
|
-
data: crdt.data
|
|
9193
|
-
});
|
|
9194
|
-
break;
|
|
9195
|
-
case CrdtType.FILE:
|
|
9196
|
-
ops.push({
|
|
9197
|
-
type: OpCode.CREATE_FILE,
|
|
9198
|
-
id,
|
|
9199
|
-
parentId: crdt.parentId,
|
|
9200
|
-
parentKey: crdt.parentKey,
|
|
9201
|
-
data: crdt.data
|
|
9202
|
-
});
|
|
9203
|
-
break;
|
|
9204
|
-
case CrdtType.LIST:
|
|
9205
|
-
ops.push({
|
|
9206
|
-
type: OpCode.CREATE_LIST,
|
|
9207
|
-
id,
|
|
9208
|
-
parentId: crdt.parentId,
|
|
9209
|
-
parentKey: crdt.parentKey
|
|
9210
|
-
});
|
|
9211
|
-
break;
|
|
9212
|
-
case CrdtType.OBJECT:
|
|
9213
|
-
if (crdt.parentId === void 0 || crdt.parentKey === void 0) {
|
|
9214
|
-
throw new Error(
|
|
9215
|
-
"Internal error. Cannot serialize storage root into an operation"
|
|
9216
|
-
);
|
|
9217
|
-
}
|
|
9218
|
-
ops.push({
|
|
9219
|
-
type: OpCode.CREATE_OBJECT,
|
|
9220
|
-
id,
|
|
9221
|
-
parentId: crdt.parentId,
|
|
9222
|
-
parentKey: crdt.parentKey,
|
|
9223
|
-
data: crdt.data
|
|
9224
|
-
});
|
|
9225
|
-
break;
|
|
9226
|
-
case CrdtType.MAP:
|
|
9227
|
-
ops.push({
|
|
9228
|
-
type: OpCode.CREATE_MAP,
|
|
9229
|
-
id,
|
|
9230
|
-
parentId: crdt.parentId,
|
|
9231
|
-
parentKey: crdt.parentKey
|
|
9232
|
-
});
|
|
9233
|
-
break;
|
|
9234
|
-
}
|
|
9031
|
+
emitCreate(id, crdt);
|
|
9235
9032
|
}
|
|
9236
9033
|
});
|
|
9237
9034
|
return ops;
|
|
@@ -10098,9 +9895,6 @@ function defaultMessageFromContext(context) {
|
|
|
10098
9895
|
|
|
10099
9896
|
// src/room.ts
|
|
10100
9897
|
var FEEDS_TIMEOUT = 5e3;
|
|
10101
|
-
function getLiveFileId(file) {
|
|
10102
|
-
return typeof file === "string" ? file : file.id;
|
|
10103
|
-
}
|
|
10104
9898
|
function connectionAccessFromScopes(scopes) {
|
|
10105
9899
|
const roomPermissions = normalizeRoomPermissions(scopes);
|
|
10106
9900
|
const matrix = permissionMatrixFromScopes(roomPermissions);
|
|
@@ -10222,7 +10016,7 @@ function createRoom(options, config) {
|
|
|
10222
10016
|
yjsProvider: void 0,
|
|
10223
10017
|
yjsProviderDidChange: makeEventSource(),
|
|
10224
10018
|
// Storage
|
|
10225
|
-
pool: createManagedPool(
|
|
10019
|
+
pool: createManagedPool({
|
|
10226
10020
|
getCurrentConnectionId,
|
|
10227
10021
|
onDispatch,
|
|
10228
10022
|
isStorageWritable,
|
|
@@ -10385,12 +10179,18 @@ function createRoom(options, config) {
|
|
|
10385
10179
|
signal: options2.signal
|
|
10386
10180
|
});
|
|
10387
10181
|
}
|
|
10388
|
-
async function
|
|
10389
|
-
return httpClient.
|
|
10182
|
+
async function fetchStorageHistoryVersion(versionId) {
|
|
10183
|
+
return httpClient.fetchStorageHistoryVersion({ roomId, versionId });
|
|
10184
|
+
}
|
|
10185
|
+
async function fetchYjsHistoryVersion(versionId) {
|
|
10186
|
+
return httpClient.fetchYjsHistoryVersion({ roomId, versionId });
|
|
10390
10187
|
}
|
|
10391
10188
|
async function createVersionHistorySnapshot() {
|
|
10392
10189
|
return httpClient.createVersionHistorySnapshot({ roomId });
|
|
10393
10190
|
}
|
|
10191
|
+
async function deleteHistoryVersion(versionId) {
|
|
10192
|
+
return httpClient.deleteHistoryVersion({ roomId, versionId });
|
|
10193
|
+
}
|
|
10394
10194
|
async function executeContextualPrompt(options2) {
|
|
10395
10195
|
return httpClient.executeContextualPrompt({
|
|
10396
10196
|
roomId,
|
|
@@ -10440,17 +10240,19 @@ function createRoom(options, config) {
|
|
|
10440
10240
|
self,
|
|
10441
10241
|
(me) => me !== null ? userToTreeNode("Me", me) : null
|
|
10442
10242
|
);
|
|
10243
|
+
function diffCurrentStorageAgainst(target) {
|
|
10244
|
+
const current = /* @__PURE__ */ new Map();
|
|
10245
|
+
for (const [id, crdt] of context.pool.nodes) {
|
|
10246
|
+
current.set(id, crdt._serialize());
|
|
10247
|
+
}
|
|
10248
|
+
return diffNodeMap(current, target);
|
|
10249
|
+
}
|
|
10443
10250
|
function createOrUpdateRootFromMessage(nodes) {
|
|
10444
10251
|
if (nodes.size === 0) {
|
|
10445
10252
|
throw new Error("Internal error: cannot load storage without items");
|
|
10446
10253
|
}
|
|
10447
10254
|
if (context.root !== void 0) {
|
|
10448
|
-
const
|
|
10449
|
-
for (const [id, crdt] of context.pool.nodes) {
|
|
10450
|
-
currentItems.set(id, crdt._serialize());
|
|
10451
|
-
}
|
|
10452
|
-
const ops = diffNodeMap(currentItems, nodes);
|
|
10453
|
-
const result = applyRemoteOps(ops);
|
|
10255
|
+
const result = applyRemoteOps(diffCurrentStorageAgainst(nodes));
|
|
10454
10256
|
notify(result.updates);
|
|
10455
10257
|
} else {
|
|
10456
10258
|
context.root = LiveObject._fromItems(
|
|
@@ -10475,6 +10277,28 @@ function createRoom(options, config) {
|
|
|
10475
10277
|
}
|
|
10476
10278
|
});
|
|
10477
10279
|
}
|
|
10280
|
+
function reconcileStorageWithNodes(nodes) {
|
|
10281
|
+
if (context.root === void 0) {
|
|
10282
|
+
throw new Error("Cannot reconcile storage before it is loaded");
|
|
10283
|
+
}
|
|
10284
|
+
const ops = diffCurrentStorageAgainst(
|
|
10285
|
+
new Map(nodes)
|
|
10286
|
+
);
|
|
10287
|
+
if (ops.length === 0) {
|
|
10288
|
+
return;
|
|
10289
|
+
}
|
|
10290
|
+
const result = applyLocalOps(ops);
|
|
10291
|
+
if (result.reverse.length > 0) {
|
|
10292
|
+
addToUndoStack(result.reverse);
|
|
10293
|
+
}
|
|
10294
|
+
context.redoStack.length = 0;
|
|
10295
|
+
for (const op of result.opsToEmit) {
|
|
10296
|
+
context.buffer.storageOperations.push(op);
|
|
10297
|
+
}
|
|
10298
|
+
notify(result.updates);
|
|
10299
|
+
onHistoryChange();
|
|
10300
|
+
flushNowOrSoon();
|
|
10301
|
+
}
|
|
10478
10302
|
function _addToRealUndoStack(frames) {
|
|
10479
10303
|
if (context.undoStack.length >= 50) {
|
|
10480
10304
|
context.undoStack.shift();
|
|
@@ -10590,7 +10414,7 @@ function createRoom(options, config) {
|
|
|
10590
10414
|
);
|
|
10591
10415
|
output.reverse.pushLeft(applyOpResult.reverse);
|
|
10592
10416
|
}
|
|
10593
|
-
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT
|
|
10417
|
+
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT) {
|
|
10594
10418
|
createdNodeIds.add(op.id);
|
|
10595
10419
|
}
|
|
10596
10420
|
}
|
|
@@ -10634,7 +10458,6 @@ function createRoom(options, config) {
|
|
|
10634
10458
|
case OpCode.CREATE_OBJECT:
|
|
10635
10459
|
case OpCode.CREATE_LIST:
|
|
10636
10460
|
case OpCode.CREATE_MAP:
|
|
10637
|
-
case OpCode.CREATE_FILE:
|
|
10638
10461
|
case OpCode.CREATE_REGISTER: {
|
|
10639
10462
|
if (op.parentId === void 0) {
|
|
10640
10463
|
return { modified: false };
|
|
@@ -10645,6 +10468,10 @@ function createRoom(options, config) {
|
|
|
10645
10468
|
}
|
|
10646
10469
|
return parentNode._attachChild(op, source);
|
|
10647
10470
|
}
|
|
10471
|
+
// Unknown op codes can be received when older and newer clients are
|
|
10472
|
+
// both present in a same room. Older clients simply ignore them.
|
|
10473
|
+
default:
|
|
10474
|
+
return { modified: false };
|
|
10648
10475
|
}
|
|
10649
10476
|
}
|
|
10650
10477
|
function updatePresence(patch, options2) {
|
|
@@ -11738,17 +11565,6 @@ function createRoom(options, config) {
|
|
|
11738
11565
|
function getAttachmentUrl(attachmentId) {
|
|
11739
11566
|
return httpClient.getAttachmentUrl({ roomId, attachmentId });
|
|
11740
11567
|
}
|
|
11741
|
-
async function uploadFile(file, options2 = {}) {
|
|
11742
|
-
const data = await httpClient.uploadFile({
|
|
11743
|
-
roomId,
|
|
11744
|
-
file,
|
|
11745
|
-
signal: options2.signal
|
|
11746
|
-
});
|
|
11747
|
-
return new LiveFile(data);
|
|
11748
|
-
}
|
|
11749
|
-
function getFileUrl(file) {
|
|
11750
|
-
return httpClient.getFileUrl({ roomId, fileId: getLiveFileId(file) });
|
|
11751
|
-
}
|
|
11752
11568
|
function getSubscriptionSettings(options2) {
|
|
11753
11569
|
return httpClient.getSubscriptionSettings({
|
|
11754
11570
|
roomId,
|
|
@@ -11807,9 +11623,16 @@ function createRoom(options, config) {
|
|
|
11807
11623
|
// List versions of the document since the specified date
|
|
11808
11624
|
listHistoryVersionsSince,
|
|
11809
11625
|
// get a specific version
|
|
11810
|
-
|
|
11626
|
+
fetchStorageHistoryVersion,
|
|
11627
|
+
fetchYjsHistoryVersion,
|
|
11628
|
+
// reconstruct a storage version's nodes into a read-only LiveObject tree
|
|
11629
|
+
liveObjectFromNodeStream,
|
|
11630
|
+
// restore live storage to match a version's nodes
|
|
11631
|
+
reconcileStorageWithNodes,
|
|
11811
11632
|
// create a version
|
|
11812
11633
|
createVersionHistorySnapshot,
|
|
11634
|
+
// delete a version
|
|
11635
|
+
deleteHistoryVersion,
|
|
11813
11636
|
// execute a contextual prompt
|
|
11814
11637
|
executeContextualPrompt,
|
|
11815
11638
|
// Support for the Liveblocks browser extension
|
|
@@ -11822,8 +11645,7 @@ function createRoom(options, config) {
|
|
|
11822
11645
|
rawSend: (data) => managedSocket.send(data),
|
|
11823
11646
|
incomingMessage: (data) => handleServerMessage(new MessageEvent("message", { data }))
|
|
11824
11647
|
},
|
|
11825
|
-
attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
|
|
11826
|
-
fileUrlsStore: httpClient.getOrCreateFileUrlsStore(roomId)
|
|
11648
|
+
attachmentUrlsStore: httpClient.getOrCreateAttachmentUrlsStore(roomId)
|
|
11827
11649
|
},
|
|
11828
11650
|
id: roomId,
|
|
11829
11651
|
subscribe: makeClassicSubscribeFn(
|
|
@@ -11921,8 +11743,6 @@ ${dumpPool(
|
|
|
11921
11743
|
prepareAttachment,
|
|
11922
11744
|
uploadAttachment,
|
|
11923
11745
|
getAttachmentUrl,
|
|
11924
|
-
uploadFile,
|
|
11925
|
-
getFileUrl,
|
|
11926
11746
|
// Notifications
|
|
11927
11747
|
getNotificationSettings: getSubscriptionSettings,
|
|
11928
11748
|
getSubscriptionSettings,
|
|
@@ -12808,11 +12628,6 @@ function toPlainLson(lson) {
|
|
|
12808
12628
|
liveblocksType: "LiveList",
|
|
12809
12629
|
data: [...lson].map((item) => toPlainLson(item))
|
|
12810
12630
|
};
|
|
12811
|
-
} else if (lson instanceof LiveFile) {
|
|
12812
|
-
return {
|
|
12813
|
-
liveblocksType: "LiveFile",
|
|
12814
|
-
data: lson.data
|
|
12815
|
-
};
|
|
12816
12631
|
} else {
|
|
12817
12632
|
return lson;
|
|
12818
12633
|
}
|
|
@@ -12991,7 +12806,6 @@ export {
|
|
|
12991
12806
|
DerivedSignal,
|
|
12992
12807
|
FeedRequestErrorCode,
|
|
12993
12808
|
HttpError,
|
|
12994
|
-
LiveFile,
|
|
12995
12809
|
LiveList,
|
|
12996
12810
|
LiveMap,
|
|
12997
12811
|
LiveObject,
|
|
@@ -13031,7 +12845,6 @@ export {
|
|
|
13031
12845
|
createInboxNotificationId,
|
|
13032
12846
|
createManagedPool,
|
|
13033
12847
|
createNotificationSettings,
|
|
13034
|
-
createStorageFileId,
|
|
13035
12848
|
createThreadId,
|
|
13036
12849
|
deepLiveify,
|
|
13037
12850
|
defineAiTool,
|
|
@@ -13051,7 +12864,6 @@ export {
|
|
|
13051
12864
|
isCommentBodyLink,
|
|
13052
12865
|
isCommentBodyMention,
|
|
13053
12866
|
isCommentBodyText,
|
|
13054
|
-
isFileStorageNode,
|
|
13055
12867
|
isJsonArray,
|
|
13056
12868
|
isJsonObject,
|
|
13057
12869
|
isJsonScalar,
|