@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.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-file1";
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
- return uploadRoomFile({
2005
- file: attachment.file,
2006
- signal: options.signal,
2007
- abortErrorMessage: `Upload of attachment ${attachment.id} was aborted.`,
2008
- uploadSingle: async () => httpClient.putBlob(
2009
- url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.name)}`,
2010
- await authManager.getAuthValue({
2011
- roomId,
2012
- resource: "comments",
2013
- access: "write"
2014
- }),
2015
- attachment.file,
2016
- { fileSize: attachment.size },
2017
- { signal: options.signal }
2018
- ),
2019
- createMultipartUpload: async () => httpClient.post(
2020
- url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.name)}`,
2021
- await authManager.getAuthValue({
2022
- roomId,
2023
- resource: "comments",
2024
- access: "write"
2025
- }),
2026
- void 0,
2027
- { signal: options.signal },
2028
- { fileSize: attachment.size }
2029
- ),
2030
- uploadMultipartPart: async (uploadId, partNumber, part) => httpClient.putBlob(
2031
- url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/${String(partNumber)}`,
2032
- await authManager.getAuthValue({
2033
- roomId,
2034
- resource: "comments",
2035
- access: "write"
2036
- }),
2037
- part,
2038
- void 0,
2039
- { signal: options.signal }
2040
- ),
2041
- completeMultipartUpload: async (uploadId, parts) => httpClient.post(
2042
- url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/complete`,
2043
- await authManager.getAuthValue({
2044
- roomId,
2045
- resource: "comments",
2046
- access: "write"
2047
- }),
2048
- { parts },
2049
- { signal: options.signal }
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: "storage",
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 getYjsHistoryVersion(options) {
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
- getYjsHistoryVersion,
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.CREATE_FILE || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_LIST;
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(roomId, options) {
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) || isLiveFile(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 || obj instanceof LiveFile) {
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 || value instanceof LiveFile) {
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
- switch (crdt.type) {
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(roomId, {
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 getYjsHistoryVersion(versionId) {
10389
- return httpClient.getYjsHistoryVersion({ roomId, versionId });
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 currentItems = /* @__PURE__ */ new Map();
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 || op.type === OpCode.CREATE_FILE) {
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
- getYjsHistoryVersion,
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,