@liveblocks/core 3.20.0-pre1 → 3.20.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 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.20.0-pre1";
9
+ var PKG_VERSION = "3.20.0";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -701,6 +701,20 @@ var SortedList = class _SortedList {
701
701
  get length() {
702
702
  return this.#data.length;
703
703
  }
704
+ /**
705
+ * Whether the given value is present, by identity. O(log n) plus the length
706
+ * of any run of items that share its sort key (normally 1). Bisects on the
707
+ * value's own key, so it only finds values sitting at their sorted position,
708
+ * which is true for any item currently in the list.
709
+ */
710
+ includes(value) {
711
+ for (let i = bisectRight(this.#data, value, this.#lt) - 1; i >= 0 && !this.#lt(this.#data[i], value); i--) {
712
+ if (this.#data[i] === value) {
713
+ return true;
714
+ }
715
+ }
716
+ return false;
717
+ }
704
718
  *filter(predicate) {
705
719
  for (const item of this.#data) {
706
720
  if (predicate(item)) {
@@ -1556,7 +1570,6 @@ function isUrl(string) {
1556
1570
  function createApiClient({
1557
1571
  baseUrl,
1558
1572
  authManager,
1559
- currentUserId,
1560
1573
  fetchPolyfill
1561
1574
  }) {
1562
1575
  const httpClient = new HttpClient(baseUrl, fetchPolyfill);
@@ -1564,8 +1577,9 @@ function createApiClient({
1564
1577
  const result = await httpClient.get(
1565
1578
  url`/v2/c/rooms/${options.roomId}/threads/delta`,
1566
1579
  await authManager.getAuthValue({
1567
- requestedScope: "comments:read",
1568
- roomId: options.roomId
1580
+ roomId: options.roomId,
1581
+ resource: "comments",
1582
+ access: "read"
1569
1583
  }),
1570
1584
  {
1571
1585
  since: options.since.toISOString()
@@ -1603,8 +1617,9 @@ function createApiClient({
1603
1617
  const result = await httpClient.get(
1604
1618
  url`/v2/c/rooms/${options.roomId}/threads`,
1605
1619
  await authManager.getAuthValue({
1606
- requestedScope: "comments:read",
1607
- roomId: options.roomId
1620
+ roomId: options.roomId,
1621
+ resource: "comments",
1622
+ access: "read"
1608
1623
  }),
1609
1624
  {
1610
1625
  cursor: options.cursor,
@@ -1648,8 +1663,9 @@ function createApiClient({
1648
1663
  const result = await httpClient.get(
1649
1664
  url`/v2/c/rooms/${options.roomId}/threads/comments/search`,
1650
1665
  await authManager.getAuthValue({
1651
- requestedScope: "comments:read",
1652
- roomId: options.roomId
1666
+ roomId: options.roomId,
1667
+ resource: "comments",
1668
+ access: "read"
1653
1669
  }),
1654
1670
  {
1655
1671
  text: options.query.text,
@@ -1670,8 +1686,9 @@ function createApiClient({
1670
1686
  const thread = await httpClient.post(
1671
1687
  url`/v2/c/rooms/${options.roomId}/threads`,
1672
1688
  await authManager.getAuthValue({
1673
- requestedScope: "comments:read",
1674
- roomId: options.roomId
1689
+ roomId: options.roomId,
1690
+ resource: "comments",
1691
+ access: "write"
1675
1692
  }),
1676
1693
  {
1677
1694
  id: threadId,
@@ -1690,8 +1707,9 @@ function createApiClient({
1690
1707
  await httpClient.delete(
1691
1708
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}`,
1692
1709
  await authManager.getAuthValue({
1693
- requestedScope: "comments:read",
1694
- roomId: options.roomId
1710
+ roomId: options.roomId,
1711
+ resource: "comments",
1712
+ access: "write"
1695
1713
  })
1696
1714
  );
1697
1715
  }
@@ -1699,8 +1717,9 @@ function createApiClient({
1699
1717
  const response = await httpClient.rawGet(
1700
1718
  url`/v2/c/rooms/${options.roomId}/thread-with-notification/${options.threadId}`,
1701
1719
  await authManager.getAuthValue({
1702
- requestedScope: "comments:read",
1703
- roomId: options.roomId
1720
+ roomId: options.roomId,
1721
+ resource: "comments",
1722
+ access: "read"
1704
1723
  })
1705
1724
  );
1706
1725
  if (response.ok) {
@@ -1726,8 +1745,9 @@ function createApiClient({
1726
1745
  return await httpClient.post(
1727
1746
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/metadata`,
1728
1747
  await authManager.getAuthValue({
1729
- requestedScope: "comments:read",
1730
- roomId: options.roomId
1748
+ roomId: options.roomId,
1749
+ resource: "comments",
1750
+ access: "write"
1731
1751
  }),
1732
1752
  options.metadata
1733
1753
  );
@@ -1736,8 +1756,9 @@ function createApiClient({
1736
1756
  return await httpClient.post(
1737
1757
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/metadata`,
1738
1758
  await authManager.getAuthValue({
1739
- requestedScope: "comments:read",
1740
- roomId: options.roomId
1759
+ roomId: options.roomId,
1760
+ resource: "comments",
1761
+ access: "write"
1741
1762
  }),
1742
1763
  options.metadata
1743
1764
  );
@@ -1747,8 +1768,9 @@ function createApiClient({
1747
1768
  const comment = await httpClient.post(
1748
1769
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments`,
1749
1770
  await authManager.getAuthValue({
1750
- requestedScope: "comments:read",
1751
- roomId: options.roomId
1771
+ roomId: options.roomId,
1772
+ resource: "comments",
1773
+ access: "write"
1752
1774
  }),
1753
1775
  {
1754
1776
  id: commentId,
@@ -1763,8 +1785,9 @@ function createApiClient({
1763
1785
  const comment = await httpClient.post(
1764
1786
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}`,
1765
1787
  await authManager.getAuthValue({
1766
- requestedScope: "comments:read",
1767
- roomId: options.roomId
1788
+ roomId: options.roomId,
1789
+ resource: "comments",
1790
+ access: "write"
1768
1791
  }),
1769
1792
  {
1770
1793
  body: options.body,
@@ -1778,8 +1801,9 @@ function createApiClient({
1778
1801
  await httpClient.delete(
1779
1802
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}`,
1780
1803
  await authManager.getAuthValue({
1781
- requestedScope: "comments:read",
1782
- roomId: options.roomId
1804
+ roomId: options.roomId,
1805
+ resource: "comments",
1806
+ access: "write"
1783
1807
  })
1784
1808
  );
1785
1809
  }
@@ -1787,8 +1811,9 @@ function createApiClient({
1787
1811
  const reaction = await httpClient.post(
1788
1812
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/reactions`,
1789
1813
  await authManager.getAuthValue({
1790
- requestedScope: "comments:read",
1791
- roomId: options.roomId
1814
+ roomId: options.roomId,
1815
+ resource: "comments",
1816
+ access: "write"
1792
1817
  }),
1793
1818
  { emoji: options.emoji }
1794
1819
  );
@@ -1798,8 +1823,9 @@ function createApiClient({
1798
1823
  await httpClient.delete(
1799
1824
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/reactions/${options.emoji}`,
1800
1825
  await authManager.getAuthValue({
1801
- requestedScope: "comments:read",
1802
- roomId: options.roomId
1826
+ roomId: options.roomId,
1827
+ resource: "comments",
1828
+ access: "write"
1803
1829
  })
1804
1830
  );
1805
1831
  }
@@ -1807,8 +1833,9 @@ function createApiClient({
1807
1833
  await httpClient.post(
1808
1834
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/mark-as-resolved`,
1809
1835
  await authManager.getAuthValue({
1810
- requestedScope: "comments:read",
1811
- roomId: options.roomId
1836
+ roomId: options.roomId,
1837
+ resource: "comments",
1838
+ access: "write"
1812
1839
  })
1813
1840
  );
1814
1841
  }
@@ -1816,8 +1843,9 @@ function createApiClient({
1816
1843
  await httpClient.post(
1817
1844
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/mark-as-unresolved`,
1818
1845
  await authManager.getAuthValue({
1819
- requestedScope: "comments:read",
1820
- roomId: options.roomId
1846
+ roomId: options.roomId,
1847
+ resource: "comments",
1848
+ access: "write"
1821
1849
  })
1822
1850
  );
1823
1851
  }
@@ -1825,8 +1853,9 @@ function createApiClient({
1825
1853
  const subscription = await httpClient.post(
1826
1854
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/subscribe`,
1827
1855
  await authManager.getAuthValue({
1828
- requestedScope: "comments:read",
1829
- roomId: options.roomId
1856
+ roomId: options.roomId,
1857
+ resource: "comments",
1858
+ access: "read"
1830
1859
  })
1831
1860
  );
1832
1861
  return convertToSubscriptionData(subscription);
@@ -1835,8 +1864,9 @@ function createApiClient({
1835
1864
  await httpClient.post(
1836
1865
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/unsubscribe`,
1837
1866
  await authManager.getAuthValue({
1838
- requestedScope: "comments:read",
1839
- roomId: options.roomId
1867
+ roomId: options.roomId,
1868
+ resource: "comments",
1869
+ access: "read"
1840
1870
  })
1841
1871
  );
1842
1872
  }
@@ -1892,8 +1922,9 @@ function createApiClient({
1892
1922
  async () => httpClient.putBlob(
1893
1923
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.name)}`,
1894
1924
  await authManager.getAuthValue({
1895
- requestedScope: "comments:read",
1896
- roomId
1925
+ roomId,
1926
+ resource: "comments",
1927
+ access: "write"
1897
1928
  }),
1898
1929
  attachment.file,
1899
1930
  { fileSize: attachment.size },
@@ -1910,8 +1941,9 @@ function createApiClient({
1910
1941
  async () => httpClient.post(
1911
1942
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.name)}`,
1912
1943
  await authManager.getAuthValue({
1913
- requestedScope: "comments:read",
1914
- roomId
1944
+ roomId,
1945
+ resource: "comments",
1946
+ access: "write"
1915
1947
  }),
1916
1948
  void 0,
1917
1949
  { signal: abortSignal },
@@ -1936,8 +1968,9 @@ function createApiClient({
1936
1968
  async () => httpClient.putBlob(
1937
1969
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${createMultiPartUpload.uploadId}/${String(partNumber)}`,
1938
1970
  await authManager.getAuthValue({
1939
- requestedScope: "comments:read",
1940
- roomId
1971
+ roomId,
1972
+ resource: "comments",
1973
+ access: "write"
1941
1974
  }),
1942
1975
  part,
1943
1976
  void 0,
@@ -1960,8 +1993,9 @@ function createApiClient({
1960
1993
  return httpClient.post(
1961
1994
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/complete`,
1962
1995
  await authManager.getAuthValue({
1963
- requestedScope: "comments:read",
1964
- roomId
1996
+ roomId,
1997
+ resource: "comments",
1998
+ access: "write"
1965
1999
  }),
1966
2000
  { parts: sortedUploadedParts },
1967
2001
  { signal: abortSignal }
@@ -1972,8 +2006,9 @@ function createApiClient({
1972
2006
  await httpClient.rawDelete(
1973
2007
  url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
1974
2008
  await authManager.getAuthValue({
1975
- requestedScope: "comments:read",
1976
- roomId
2009
+ roomId,
2010
+ resource: "comments",
2011
+ access: "write"
1977
2012
  })
1978
2013
  );
1979
2014
  } catch (e8) {
@@ -1990,8 +2025,9 @@ function createApiClient({
1990
2025
  const { urls } = await httpClient.post(
1991
2026
  url`/v2/c/rooms/${roomId}/attachments/presigned-urls`,
1992
2027
  await authManager.getAuthValue({
1993
- requestedScope: "comments:read",
1994
- roomId
2028
+ roomId,
2029
+ resource: "comments",
2030
+ access: "read"
1995
2031
  }),
1996
2032
  { attachmentIds }
1997
2033
  );
@@ -2010,109 +2046,13 @@ function createApiClient({
2010
2046
  const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).batch;
2011
2047
  return batch2.get(options.attachmentId);
2012
2048
  }
2013
- async function uploadChatAttachment(options) {
2014
- const { chatId, attachment, signal } = options;
2015
- const userId = currentUserId.get();
2016
- if (userId === void 0) {
2017
- throw new Error("Attachment upload requires an authenticated user.");
2018
- }
2019
- const ATTACHMENT_PART_SIZE = 5 * 1024 * 1024;
2020
- if (options.attachment.file.size <= ATTACHMENT_PART_SIZE) {
2021
- await httpClient.putBlob(
2022
- url`/v2/c/chats/${chatId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.file.name)}`,
2023
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2024
- attachment.file,
2025
- { fileSize: attachment.file.size },
2026
- { signal }
2027
- );
2028
- } else {
2029
- const multipartUpload = await httpClient.post(
2030
- url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.file.name)}`,
2031
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2032
- void 0,
2033
- { signal },
2034
- { fileSize: attachment.file.size }
2035
- );
2036
- try {
2037
- const uploadedParts = [];
2038
- const parts = [];
2039
- let start = 0;
2040
- while (start < attachment.file.size) {
2041
- const end = Math.min(
2042
- start + ATTACHMENT_PART_SIZE,
2043
- attachment.file.size
2044
- );
2045
- parts.push({
2046
- number: parts.length + 1,
2047
- part: attachment.file.slice(start, end)
2048
- });
2049
- start = end;
2050
- }
2051
- uploadedParts.push(
2052
- ...await Promise.all(
2053
- parts.map(async ({ number, part }) => {
2054
- return await httpClient.putBlob(
2055
- url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}/${String(number)}`,
2056
- await authManager.getAuthValue({
2057
- requestedScope: "comments:read"
2058
- }),
2059
- part,
2060
- void 0,
2061
- { signal }
2062
- );
2063
- })
2064
- )
2065
- );
2066
- await httpClient.post(
2067
- url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}/complete`,
2068
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2069
- { parts: uploadedParts.sort((a, b) => a.number - b.number) },
2070
- { signal }
2071
- );
2072
- } catch (err) {
2073
- try {
2074
- await httpClient.delete(
2075
- url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}`,
2076
- await authManager.getAuthValue({ requestedScope: "comments:read" })
2077
- );
2078
- } catch (e9) {
2079
- }
2080
- throw err;
2081
- }
2082
- }
2083
- }
2084
- const attachmentUrlsBatchStoresByChat = new DefaultMap((chatId) => {
2085
- const batch2 = new Batch(
2086
- async (batchedAttachmentIds) => {
2087
- const attachmentIds = batchedAttachmentIds.flat();
2088
- const { urls } = await httpClient.post(
2089
- url`/v2/c/chats/${chatId}/attachments/presigned-urls`,
2090
- await authManager.getAuthValue({
2091
- requestedScope: "comments:read"
2092
- }),
2093
- { attachmentIds }
2094
- );
2095
- return urls.map(
2096
- (url2) => _nullishCoalesce(url2, () => ( new Error("There was an error while getting this attachment's URL")))
2097
- );
2098
- },
2099
- { delay: 50 }
2100
- );
2101
- return createBatchStore(batch2);
2102
- });
2103
- function getOrCreateChatAttachmentUrlsStore(chatId) {
2104
- return attachmentUrlsBatchStoresByChat.getOrCreate(chatId);
2105
- }
2106
- function getChatAttachmentUrl(options) {
2107
- const batch2 = getOrCreateChatAttachmentUrlsStore(options.chatId).batch;
2108
- return batch2.get(options.attachmentId);
2109
- }
2110
2049
  async function getSubscriptionSettings(options) {
2111
2050
  return httpClient.get(
2112
2051
  url`/v2/c/rooms/${options.roomId}/subscription-settings`,
2113
2052
  await authManager.getAuthValue({
2114
- requestedScope: "comments:read",
2115
- roomId: options.roomId
2053
+ roomId: options.roomId,
2054
+ resource: "comments",
2055
+ access: "read"
2116
2056
  }),
2117
2057
  void 0,
2118
2058
  {
@@ -2124,8 +2064,9 @@ function createApiClient({
2124
2064
  return httpClient.post(
2125
2065
  url`/v2/c/rooms/${options.roomId}/subscription-settings`,
2126
2066
  await authManager.getAuthValue({
2127
- requestedScope: "comments:read",
2128
- roomId: options.roomId
2067
+ roomId: options.roomId,
2068
+ resource: "comments",
2069
+ access: "read"
2129
2070
  }),
2130
2071
  options.settings
2131
2072
  );
@@ -2137,8 +2078,9 @@ function createApiClient({
2137
2078
  await httpClient.post(
2138
2079
  url`/v2/c/rooms/${roomId}/inbox-notifications/read`,
2139
2080
  await authManager.getAuthValue({
2140
- requestedScope: "comments:read",
2141
- roomId
2081
+ roomId,
2082
+ resource: "comments",
2083
+ access: "read"
2142
2084
  }),
2143
2085
  { inboxNotificationIds }
2144
2086
  );
@@ -2158,8 +2100,9 @@ function createApiClient({
2158
2100
  await httpClient.rawPost(
2159
2101
  url`/v2/c/rooms/${options.roomId}/text-mentions`,
2160
2102
  await authManager.getAuthValue({
2161
- requestedScope: "comments:read",
2162
- roomId: options.roomId
2103
+ roomId: options.roomId,
2104
+ resource: "storage",
2105
+ access: "write"
2163
2106
  }),
2164
2107
  {
2165
2108
  userId: options.mention.kind === "user" ? options.mention.id : void 0,
@@ -2173,8 +2116,9 @@ function createApiClient({
2173
2116
  await httpClient.rawDelete(
2174
2117
  url`/v2/c/rooms/${options.roomId}/text-mentions/${options.mentionId}`,
2175
2118
  await authManager.getAuthValue({
2176
- requestedScope: "comments:read",
2177
- roomId: options.roomId
2119
+ roomId: options.roomId,
2120
+ resource: "storage",
2121
+ access: "write"
2178
2122
  })
2179
2123
  );
2180
2124
  }
@@ -2182,8 +2126,9 @@ function createApiClient({
2182
2126
  return httpClient.rawGet(
2183
2127
  url`/v2/c/rooms/${options.roomId}/y-version/${options.versionId}`,
2184
2128
  await authManager.getAuthValue({
2185
- requestedScope: "comments:read",
2186
- roomId: options.roomId
2129
+ roomId: options.roomId,
2130
+ resource: "storage",
2131
+ access: "read"
2187
2132
  })
2188
2133
  );
2189
2134
  }
@@ -2191,8 +2136,9 @@ function createApiClient({
2191
2136
  await httpClient.rawPost(
2192
2137
  url`/v2/c/rooms/${options.roomId}/version`,
2193
2138
  await authManager.getAuthValue({
2194
- requestedScope: "comments:read",
2195
- roomId: options.roomId
2139
+ roomId: options.roomId,
2140
+ resource: "storage",
2141
+ access: "write"
2196
2142
  })
2197
2143
  );
2198
2144
  }
@@ -2200,8 +2146,9 @@ function createApiClient({
2200
2146
  await httpClient.rawPost(
2201
2147
  url`/v2/c/rooms/${options.roomId}/text-metadata`,
2202
2148
  await authManager.getAuthValue({
2203
- requestedScope: "comments:read",
2204
- roomId: options.roomId
2149
+ roomId: options.roomId,
2150
+ resource: "storage",
2151
+ access: "read"
2205
2152
  }),
2206
2153
  {
2207
2154
  type: options.type,
@@ -2213,8 +2160,9 @@ function createApiClient({
2213
2160
  const result = await httpClient.post(
2214
2161
  url`/v2/c/rooms/${options.roomId}/ai/contextual-prompt`,
2215
2162
  await authManager.getAuthValue({
2216
- requestedScope: "room:read",
2217
- roomId: options.roomId
2163
+ roomId: options.roomId,
2164
+ resource: "storage",
2165
+ access: "read"
2218
2166
  }),
2219
2167
  {
2220
2168
  prompt: options.prompt,
@@ -2236,8 +2184,9 @@ function createApiClient({
2236
2184
  const result = await httpClient.get(
2237
2185
  url`/v2/c/rooms/${options.roomId}/versions`,
2238
2186
  await authManager.getAuthValue({
2239
- requestedScope: "comments:read",
2240
- roomId: options.roomId
2187
+ roomId: options.roomId,
2188
+ resource: "storage",
2189
+ access: "read"
2241
2190
  })
2242
2191
  );
2243
2192
  return {
@@ -2254,8 +2203,9 @@ function createApiClient({
2254
2203
  const result = await httpClient.get(
2255
2204
  url`/v2/c/rooms/${options.roomId}/versions/delta`,
2256
2205
  await authManager.getAuthValue({
2257
- requestedScope: "comments:read",
2258
- roomId: options.roomId
2206
+ roomId: options.roomId,
2207
+ resource: "storage",
2208
+ access: "read"
2259
2209
  }),
2260
2210
  { since: options.since.toISOString() },
2261
2211
  { signal: options.signal }
@@ -2274,8 +2224,9 @@ function createApiClient({
2274
2224
  const result = await httpClient.rawGet(
2275
2225
  url`/v2/c/rooms/${options.roomId}/storage`,
2276
2226
  await authManager.getAuthValue({
2277
- requestedScope: "room:read",
2278
- roomId: options.roomId
2227
+ roomId: options.roomId,
2228
+ resource: "storage",
2229
+ access: "read"
2279
2230
  })
2280
2231
  );
2281
2232
  return await result.json();
@@ -2288,7 +2239,7 @@ function createApiClient({
2288
2239
  }
2289
2240
  const json = await httpClient.get(
2290
2241
  url`/v2/c/inbox-notifications`,
2291
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2242
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2292
2243
  {
2293
2244
  cursor: _optionalChain([options, 'optionalAccess', _22 => _22.cursor]),
2294
2245
  limit: PAGE_SIZE,
@@ -2314,7 +2265,7 @@ function createApiClient({
2314
2265
  }
2315
2266
  const json = await httpClient.get(
2316
2267
  url`/v2/c/inbox-notifications/delta`,
2317
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2268
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2318
2269
  { since: options.since.toISOString(), query },
2319
2270
  { signal: options.signal }
2320
2271
  );
@@ -2343,7 +2294,7 @@ function createApiClient({
2343
2294
  }
2344
2295
  const { count } = await httpClient.get(
2345
2296
  url`/v2/c/inbox-notifications/count`,
2346
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2297
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2347
2298
  { query },
2348
2299
  { signal: _optionalChain([options, 'optionalAccess', _25 => _25.signal]) }
2349
2300
  );
@@ -2352,7 +2303,7 @@ function createApiClient({
2352
2303
  async function markAllInboxNotificationsAsRead() {
2353
2304
  await httpClient.post(
2354
2305
  url`/v2/c/inbox-notifications/read`,
2355
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2306
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2356
2307
  {
2357
2308
  inboxNotificationIds: "all"
2358
2309
  }
@@ -2361,7 +2312,7 @@ function createApiClient({
2361
2312
  async function markInboxNotificationsAsRead(inboxNotificationIds) {
2362
2313
  await httpClient.post(
2363
2314
  url`/v2/c/inbox-notifications/read`,
2364
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2315
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2365
2316
  {
2366
2317
  inboxNotificationIds
2367
2318
  }
@@ -2381,19 +2332,19 @@ function createApiClient({
2381
2332
  async function deleteAllInboxNotifications() {
2382
2333
  await httpClient.delete(
2383
2334
  url`/v2/c/inbox-notifications`,
2384
- await authManager.getAuthValue({ requestedScope: "comments:read" })
2335
+ await authManager.getAuthValue({ resource: "personal", access: "write" })
2385
2336
  );
2386
2337
  }
2387
2338
  async function deleteInboxNotification(inboxNotificationId) {
2388
2339
  await httpClient.delete(
2389
2340
  url`/v2/c/inbox-notifications/${inboxNotificationId}`,
2390
- await authManager.getAuthValue({ requestedScope: "comments:read" })
2341
+ await authManager.getAuthValue({ resource: "personal", access: "write" })
2391
2342
  );
2392
2343
  }
2393
2344
  async function getNotificationSettings(options) {
2394
2345
  return httpClient.get(
2395
2346
  url`/v2/c/notification-settings`,
2396
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2347
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2397
2348
  void 0,
2398
2349
  { signal: _optionalChain([options, 'optionalAccess', _26 => _26.signal]) }
2399
2350
  );
@@ -2401,7 +2352,7 @@ function createApiClient({
2401
2352
  async function updateNotificationSettings(settings) {
2402
2353
  return httpClient.post(
2403
2354
  url`/v2/c/notification-settings`,
2404
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2355
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2405
2356
  settings
2406
2357
  );
2407
2358
  }
@@ -2413,7 +2364,7 @@ function createApiClient({
2413
2364
  const PAGE_SIZE = 50;
2414
2365
  const json = await httpClient.get(
2415
2366
  url`/v2/c/threads`,
2416
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2367
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2417
2368
  {
2418
2369
  cursor: _optionalChain([options, 'optionalAccess', _28 => _28.cursor]),
2419
2370
  query,
@@ -2434,7 +2385,7 @@ function createApiClient({
2434
2385
  async function getUserThreadsSince_experimental(options) {
2435
2386
  const json = await httpClient.get(
2436
2387
  url`/v2/c/threads/delta`,
2437
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2388
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2438
2389
  { since: options.since.toISOString() },
2439
2390
  { signal: options.signal }
2440
2391
  );
@@ -2463,7 +2414,8 @@ function createApiClient({
2463
2414
  const { groups: plainGroups } = await httpClient.post(
2464
2415
  url`/v2/c/groups/find`,
2465
2416
  await authManager.getAuthValue({
2466
- requestedScope: "comments:read"
2417
+ resource: "personal",
2418
+ access: "write"
2467
2419
  }),
2468
2420
  { groupIds }
2469
2421
  );
@@ -2482,7 +2434,7 @@ function createApiClient({
2482
2434
  async function getUrlMetadata(_url) {
2483
2435
  const { metadata } = await httpClient.get(
2484
2436
  url`/v2/c/urls/metadata`,
2485
- await authManager.getAuthValue({ requestedScope: "comments:read" }),
2437
+ await authManager.getAuthValue({ resource: "personal", access: "write" }),
2486
2438
  { url: _url }
2487
2439
  );
2488
2440
  return metadata;
@@ -2522,10 +2474,6 @@ function createApiClient({
2522
2474
  getAttachmentUrl,
2523
2475
  uploadAttachment,
2524
2476
  getOrCreateAttachmentUrlsStore,
2525
- // User attachments
2526
- uploadChatAttachment,
2527
- getOrCreateChatAttachmentUrlsStore,
2528
- getChatAttachmentUrl,
2529
2477
  // Room storage
2530
2478
  streamStorage,
2531
2479
  // Notifications
@@ -2631,7 +2579,7 @@ var HttpClient = class {
2631
2579
  let body;
2632
2580
  try {
2633
2581
  body = await response.json();
2634
- } catch (e10) {
2582
+ } catch (e9) {
2635
2583
  body = {};
2636
2584
  }
2637
2585
  return body;
@@ -3831,7 +3779,7 @@ var ManagedSocket = class {
3831
3779
  getStatus() {
3832
3780
  try {
3833
3781
  return toNewConnectionStatus(this.#machine);
3834
- } catch (e11) {
3782
+ } catch (e10) {
3835
3783
  return "initial";
3836
3784
  }
3837
3785
  }
@@ -5219,22 +5167,327 @@ function createReceivingToolInvocation(invocationId, name, partialArgsText = "")
5219
5167
  };
5220
5168
  }
5221
5169
 
5222
- // src/protocol/AuthToken.ts
5223
- var Permission = /* @__PURE__ */ ((Permission2) => {
5224
- Permission2["Read"] = "room:read";
5225
- Permission2["Write"] = "room:write";
5226
- Permission2["PresenceWrite"] = "room:presence:write";
5227
- Permission2["CommentsWrite"] = "comments:write";
5228
- Permission2["CommentsRead"] = "comments:read";
5229
- Permission2["FeedsWrite"] = "feeds:write";
5230
- return Permission2;
5231
- })(Permission || {});
5232
- function canWriteStorage(scopes) {
5233
- return scopes.includes("room:write" /* Write */);
5234
- }
5235
- function canComment(scopes) {
5236
- return scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:write" /* Write */);
5170
+ // src/permissions.ts
5171
+ var Permission = {
5172
+ /**
5173
+ * Default permission for a room.
5174
+ */
5175
+ Read: "*:read",
5176
+ Write: "*:write",
5177
+ /**
5178
+ * Legacy aliases for default room permissions.
5179
+ */
5180
+ RoomWrite: "room:write",
5181
+ RoomRead: "room:read",
5182
+ /**
5183
+ * Storage
5184
+ */
5185
+ StorageRead: "storage:read",
5186
+ StorageWrite: "storage:write",
5187
+ StorageNone: "storage:none",
5188
+ /**
5189
+ * Comments
5190
+ */
5191
+ CommentsWrite: "comments:write",
5192
+ CommentsRead: "comments:read",
5193
+ CommentsNone: "comments:none",
5194
+ /**
5195
+ * Feeds
5196
+ */
5197
+ FeedsRead: "feeds:read",
5198
+ FeedsWrite: "feeds:write",
5199
+ FeedsNone: "feeds:none",
5200
+ /**
5201
+ * Legacy
5202
+ */
5203
+ LegacyRoomPresenceWrite: "room:presence:write"
5204
+ };
5205
+ var ACCESS_LEVELS = ["none", "read", "write"];
5206
+ var basePermissionScopes = /* @__PURE__ */ new Set([
5207
+ Permission.Read,
5208
+ Permission.Write,
5209
+ Permission.RoomRead,
5210
+ Permission.RoomWrite
5211
+ ]);
5212
+ var ACCESS_LEVEL_RANKS = {
5213
+ none: 0,
5214
+ read: 1,
5215
+ write: 2
5216
+ };
5217
+ var PERMISSIONS_BY_RESOURCE = {
5218
+ room: {
5219
+ read: [Permission.Read, Permission.RoomRead],
5220
+ write: [Permission.Write, Permission.RoomWrite]
5221
+ },
5222
+ personal: {
5223
+ write: []
5224
+ },
5225
+ storage: {
5226
+ write: [Permission.StorageWrite],
5227
+ read: [Permission.StorageRead],
5228
+ none: [Permission.StorageNone]
5229
+ },
5230
+ comments: {
5231
+ write: [Permission.CommentsWrite],
5232
+ read: [Permission.CommentsRead],
5233
+ none: [Permission.CommentsNone]
5234
+ },
5235
+ feeds: {
5236
+ write: [Permission.FeedsWrite],
5237
+ read: [Permission.FeedsRead],
5238
+ none: [Permission.FeedsNone]
5239
+ }
5240
+ };
5241
+ var NO_PERMISSION_MATRIX = {
5242
+ room: "none",
5243
+ storage: "none",
5244
+ comments: "none",
5245
+ feeds: "none",
5246
+ personal: "none"
5247
+ };
5248
+ var BASE_PERMISSION_RESOURCE = "room";
5249
+ var ROOM_PERMISSION_RESOURCES = [
5250
+ "storage",
5251
+ "comments",
5252
+ "feeds"
5253
+ ];
5254
+ var VALID_PERMISSIONS = new Set(Object.values(Permission));
5255
+ function isPermission(permission) {
5256
+ return VALID_PERMISSIONS.has(permission);
5237
5257
  }
5258
+ function resolveResourceAccess(scopes, resource) {
5259
+ const permissions = PERMISSIONS_BY_RESOURCE[resource];
5260
+ let resourceAccess;
5261
+ for (const access of ACCESS_LEVELS) {
5262
+ const scopedPermissions = permissions[access];
5263
+ if (scopedPermissions !== void 0 && scopedPermissions.some((permission) => scopes.includes(permission))) {
5264
+ resourceAccess = access;
5265
+ }
5266
+ }
5267
+ return resourceAccess;
5268
+ }
5269
+ function permissionMatrixFromResolvedScopes(resolved) {
5270
+ if (!resolved.hasDefaultPermission) {
5271
+ return { ...NO_PERMISSION_MATRIX };
5272
+ }
5273
+ const matrix = {
5274
+ ...NO_PERMISSION_MATRIX,
5275
+ [BASE_PERMISSION_RESOURCE]: resolved.baseAccess,
5276
+ personal: "write"
5277
+ };
5278
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5279
+ matrix[resource] = _nullishCoalesce(resolved.matrix[resource], () => ( resolved.baseAccess));
5280
+ }
5281
+ return matrix;
5282
+ }
5283
+ function permissionMatrixFromScopes(scopes) {
5284
+ return permissionMatrixFromResolvedScopes(resolvePermissionScopes(scopes));
5285
+ }
5286
+ function resolvePermissionScopes(scopes) {
5287
+ const hasDefaultPermission = scopes.includes(Permission.Write) || scopes.includes(Permission.Read) || scopes.includes(Permission.RoomWrite) || scopes.includes(Permission.RoomRead);
5288
+ const baseAccess = scopes.includes(Permission.Write) || scopes.includes(Permission.RoomWrite) ? "write" : scopes.includes(Permission.Read) || scopes.includes(Permission.RoomRead) ? "read" : "none";
5289
+ const matrix = {};
5290
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5291
+ const access = resolveResourceAccess(scopes, resource);
5292
+ if (access !== void 0) {
5293
+ matrix[resource] = access;
5294
+ }
5295
+ }
5296
+ return { hasDefaultPermission, baseAccess, matrix };
5297
+ }
5298
+ function hasPermissionAccess(matrix, resource, requiredAccess) {
5299
+ const access = _nullishCoalesce(matrix[resource], () => ( "none"));
5300
+ return ACCESS_LEVEL_RANKS[access] >= ACCESS_LEVEL_RANKS[requiredAccess];
5301
+ }
5302
+ function resolveRoomPermissionMatrix(permissions, roomId) {
5303
+ const matchedPermissions = permissions.filter(
5304
+ (entry) => roomPatternMatches(entry.pattern, roomId)
5305
+ );
5306
+ if (matchedPermissions.length === 0) {
5307
+ return void 0;
5308
+ }
5309
+ let hasDefaultPermission = false;
5310
+ let baseAccess = "none";
5311
+ const explicitMatrix = {};
5312
+ const explicitSpecificity = {};
5313
+ for (const entry of matchedPermissions) {
5314
+ const resolved = resolvePermissionScopes(entry.scopes);
5315
+ const specificity = roomPatternSpecificity(entry.pattern);
5316
+ if (resolved.hasDefaultPermission) {
5317
+ hasDefaultPermission = true;
5318
+ baseAccess = strongestAccess(baseAccess, resolved.baseAccess);
5319
+ }
5320
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5321
+ const access = resolved.matrix[resource];
5322
+ if (access !== void 0) {
5323
+ const currentSpecificity = _nullishCoalesce(explicitSpecificity[resource], () => ( -1));
5324
+ if (specificity > currentSpecificity) {
5325
+ explicitMatrix[resource] = access;
5326
+ explicitSpecificity[resource] = specificity;
5327
+ } else if (specificity === currentSpecificity) {
5328
+ explicitMatrix[resource] = strongestAccess(
5329
+ _nullishCoalesce(explicitMatrix[resource], () => ( "none")),
5330
+ access
5331
+ );
5332
+ }
5333
+ }
5334
+ }
5335
+ }
5336
+ return permissionMatrixFromResolvedScopes({
5337
+ hasDefaultPermission,
5338
+ baseAccess,
5339
+ matrix: explicitMatrix
5340
+ });
5341
+ }
5342
+ function normalizeRoomPermissions(permissions) {
5343
+ if (!Array.isArray(permissions)) {
5344
+ throw new Error("Permission list must be an array");
5345
+ }
5346
+ const result = [];
5347
+ for (const permission of permissions) {
5348
+ if (!isPermission(permission)) {
5349
+ throw new Error(`Not a valid permission: ${permission}`);
5350
+ }
5351
+ result.push(permission);
5352
+ }
5353
+ return result;
5354
+ }
5355
+ function normalizeRoomAccesses(accesses) {
5356
+ if (accesses === void 0) {
5357
+ return void 0;
5358
+ }
5359
+ return Object.fromEntries(
5360
+ Object.entries(accesses).map(([id, permissions]) => [
5361
+ id,
5362
+ normalizeRoomPermissions(permissions)
5363
+ ])
5364
+ );
5365
+ }
5366
+ function normalizeUpdateRoomAccesses(accesses) {
5367
+ if (accesses === void 0) {
5368
+ return void 0;
5369
+ }
5370
+ return Object.fromEntries(
5371
+ Object.entries(accesses).map(([id, permissions]) => [
5372
+ id,
5373
+ permissions === null ? null : normalizeRoomPermissions(permissions)
5374
+ ])
5375
+ );
5376
+ }
5377
+ function permissionMatrixToScopes(matrix) {
5378
+ const scopes = [];
5379
+ const baseAccess = matrix.room;
5380
+ if (baseAccess !== "none") {
5381
+ scopes.push(permissionForAccessLevel(BASE_PERMISSION_RESOURCE, baseAccess));
5382
+ }
5383
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5384
+ const access = matrix[resource];
5385
+ if (access !== baseAccess) {
5386
+ scopes.push(permissionForAccessLevel(resource, access));
5387
+ }
5388
+ }
5389
+ return scopes;
5390
+ }
5391
+ function mergeRoomPermissionScopes({
5392
+ defaultAccesses,
5393
+ groupsAccesses,
5394
+ userAccesses
5395
+ }) {
5396
+ const sources = [
5397
+ resolvePermissionScopes(defaultAccesses),
5398
+ mergeResolvedScopesByHighestAccess(
5399
+ groupsAccesses.map(resolvePermissionScopes)
5400
+ ),
5401
+ resolvePermissionScopes(userAccesses)
5402
+ ];
5403
+ const merged = {
5404
+ hasDefaultPermission: false,
5405
+ baseAccess: "none",
5406
+ matrix: {}
5407
+ };
5408
+ for (const source of sources) {
5409
+ if (source.hasDefaultPermission) {
5410
+ merged.hasDefaultPermission = true;
5411
+ merged.baseAccess = source.baseAccess;
5412
+ }
5413
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5414
+ const access = source.matrix[resource];
5415
+ if (access !== void 0) {
5416
+ merged.matrix[resource] = access;
5417
+ }
5418
+ }
5419
+ }
5420
+ return permissionMatrixToScopes(permissionMatrixFromResolvedScopes(merged));
5421
+ }
5422
+ function mergeResolvedScopesByHighestAccess(sources) {
5423
+ const merged = {
5424
+ hasDefaultPermission: false,
5425
+ baseAccess: "none",
5426
+ matrix: {}
5427
+ };
5428
+ for (const source of sources) {
5429
+ if (source.hasDefaultPermission) {
5430
+ merged.hasDefaultPermission = true;
5431
+ merged.baseAccess = strongestAccess(merged.baseAccess, source.baseAccess);
5432
+ }
5433
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5434
+ const access = source.matrix[resource];
5435
+ if (access !== void 0) {
5436
+ merged.matrix[resource] = strongestAccess(
5437
+ _nullishCoalesce(merged.matrix[resource], () => ( "none")),
5438
+ access
5439
+ );
5440
+ }
5441
+ }
5442
+ }
5443
+ return merged;
5444
+ }
5445
+ function permissionForAccessLevel(resource, access, field = resource) {
5446
+ const levels = PERMISSIONS_BY_RESOURCE[resource];
5447
+ const permissions = levels[access];
5448
+ if (permissions === void 0 || permissions.length === 0) {
5449
+ throw new Error(
5450
+ `Invalid permission level for ${field}: ${_nullishCoalesce(JSON.stringify(access), () => ( String(access)))}`
5451
+ );
5452
+ }
5453
+ return permissions[0];
5454
+ }
5455
+ function strongestAccess(left, right) {
5456
+ return ACCESS_LEVEL_RANKS[right] > ACCESS_LEVEL_RANKS[left] ? right : left;
5457
+ }
5458
+ function roomPatternMatches(pattern, roomId) {
5459
+ if (pattern.includes("*")) {
5460
+ return roomId.startsWith(pattern.replace("*", ""));
5461
+ }
5462
+ return pattern === roomId;
5463
+ }
5464
+ function roomPatternSpecificity(pattern) {
5465
+ return pattern.replace("*", "").length;
5466
+ }
5467
+ function validatePermissionsSet(scopes) {
5468
+ const unknownScopes = scopes.filter((scope) => !VALID_PERMISSIONS.has(scope));
5469
+ if (unknownScopes.length > 0) {
5470
+ return `Unknown permission scope(s): ${unknownScopes.join(", ")}`;
5471
+ }
5472
+ const baseScopes = scopes.filter((scope) => basePermissionScopes.has(scope));
5473
+ if (baseScopes.length !== 1) {
5474
+ return `Permissions must include exactly one of ${Permission.Read}, ${Permission.Write} (or the legacy aliases ${Permission.RoomRead}, ${Permission.RoomWrite}), got ${baseScopes.length === 0 ? "none" : baseScopes.join(", ")}`;
5475
+ }
5476
+ const seenFeatures = /* @__PURE__ */ new Set();
5477
+ for (const scope of scopes) {
5478
+ if (basePermissionScopes.has(scope) || scope === Permission.LegacyRoomPresenceWrite) {
5479
+ continue;
5480
+ }
5481
+ const feature = scope.slice(0, scope.indexOf(":"));
5482
+ if (seenFeatures.has(feature)) {
5483
+ return `Permissions can include at most one scope per feature, got multiple "${feature}" scopes`;
5484
+ }
5485
+ seenFeatures.add(feature);
5486
+ }
5487
+ return true;
5488
+ }
5489
+
5490
+ // src/protocol/AuthToken.ts
5238
5491
  function isValidAuthTokenPayload(data) {
5239
5492
  return isPlainObject(data) && (data.k === "acc" /* ACCESS_TOKEN */ || data.k === "id" /* ID_TOKEN */);
5240
5493
  }
@@ -5273,47 +5526,22 @@ function createAuthManager(authOptions, onAuthenticate) {
5273
5526
  const authentication = prepareAuthentication(authOptions);
5274
5527
  const seenTokens = /* @__PURE__ */ new Set();
5275
5528
  const tokens = [];
5276
- const expiryTimes = [];
5277
5529
  const requestPromises = /* @__PURE__ */ new Map();
5278
5530
  function reset() {
5279
5531
  seenTokens.clear();
5280
5532
  tokens.length = 0;
5281
- expiryTimes.length = 0;
5282
5533
  requestPromises.clear();
5283
5534
  }
5284
- function hasCorrespondingScopes(requestedScope, scopes) {
5285
- if (requestedScope === "comments:read") {
5286
- return scopes.includes("comments:read" /* CommentsRead */) || scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
5287
- } else if (requestedScope === "room:read") {
5288
- return scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
5289
- }
5290
- return false;
5291
- }
5292
5535
  function getCachedToken(requestOptions) {
5293
5536
  const now2 = Math.ceil(Date.now() / 1e3);
5294
5537
  for (let i = tokens.length - 1; i >= 0; i--) {
5295
- const token = tokens[i];
5296
- const expiresAt = expiryTimes[i];
5297
- if (expiresAt <= now2) {
5538
+ const cachedToken = tokens[i];
5539
+ if (cachedToken.expiresAt <= now2) {
5298
5540
  tokens.splice(i, 1);
5299
- expiryTimes.splice(i, 1);
5300
5541
  continue;
5301
5542
  }
5302
- if (token.parsed.k === "id" /* ID_TOKEN */) {
5303
- return token;
5304
- } else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
5305
- if (!requestOptions.roomId && Object.entries(token.parsed.perms).length === 0) {
5306
- return token;
5307
- }
5308
- for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
5309
- if (!requestOptions.roomId) {
5310
- if (resource.includes("*") && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
5311
- return token;
5312
- }
5313
- } else if (resource.includes("*") && requestOptions.roomId.startsWith(resource.replace("*", "")) || requestOptions.roomId === resource && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
5314
- return token;
5315
- }
5316
- }
5543
+ if (cachedTokenSatisfiesRequest(cachedToken, requestOptions)) {
5544
+ return cachedToken.token;
5317
5545
  }
5318
5546
  }
5319
5547
  return void 0;
@@ -5331,11 +5559,15 @@ function createAuthManager(authOptions, onAuthenticate) {
5331
5559
  });
5332
5560
  const parsed = parseAuthToken(response.token);
5333
5561
  if (seenTokens.has(parsed.raw)) {
5562
+ const cachedToken = getCachedToken(options);
5563
+ if (_optionalChain([cachedToken, 'optionalAccess', _109 => _109.raw]) === parsed.raw) {
5564
+ return cachedToken;
5565
+ }
5334
5566
  throw new StopRetrying(
5335
5567
  "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported."
5336
5568
  );
5337
5569
  }
5338
- _optionalChain([onAuthenticate, 'optionalCall', _109 => _109(parsed.parsed)]);
5570
+ _optionalChain([onAuthenticate, 'optionalCall', _110 => _110(parsed.parsed)]);
5339
5571
  return parsed;
5340
5572
  }
5341
5573
  if (authentication.type === "custom") {
@@ -5343,7 +5575,7 @@ function createAuthManager(authOptions, onAuthenticate) {
5343
5575
  if (response && typeof response === "object") {
5344
5576
  if (typeof response.token === "string") {
5345
5577
  const parsed = parseAuthToken(response.token);
5346
- _optionalChain([onAuthenticate, 'optionalCall', _110 => _110(parsed.parsed)]);
5578
+ _optionalChain([onAuthenticate, 'optionalCall', _111 => _111(parsed.parsed)]);
5347
5579
  return parsed;
5348
5580
  } else if (typeof response.error === "string") {
5349
5581
  const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
@@ -5371,11 +5603,12 @@ function createAuthManager(authOptions, onAuthenticate) {
5371
5603
  return { type: "secret", token: cachedToken };
5372
5604
  }
5373
5605
  let currentPromise;
5374
- if (requestOptions.roomId) {
5375
- currentPromise = requestPromises.get(requestOptions.roomId);
5606
+ const requestKey = getAuthRequestKey(requestOptions);
5607
+ if (requestKey !== void 0) {
5608
+ currentPromise = requestPromises.get(requestKey);
5376
5609
  if (currentPromise === void 0) {
5377
5610
  currentPromise = makeAuthRequest(requestOptions);
5378
- requestPromises.set(requestOptions.roomId, currentPromise);
5611
+ requestPromises.set(requestKey, currentPromise);
5379
5612
  }
5380
5613
  } else {
5381
5614
  currentPromise = requestPromises.get("liveblocks-user-token");
@@ -5389,12 +5622,12 @@ function createAuthManager(authOptions, onAuthenticate) {
5389
5622
  const BUFFER = 30;
5390
5623
  const expiresAt = Math.floor(Date.now() / 1e3) + (token.parsed.exp - token.parsed.iat) - BUFFER;
5391
5624
  seenTokens.add(token.raw);
5392
- tokens.push(token);
5393
- expiryTimes.push(expiresAt);
5625
+ const cachedToken2 = makeCachedToken(token, expiresAt);
5626
+ tokens.push(cachedToken2);
5394
5627
  return { type: "secret", token };
5395
5628
  } finally {
5396
- if (requestOptions.roomId) {
5397
- requestPromises.delete(requestOptions.roomId);
5629
+ if (requestKey !== void 0) {
5630
+ requestPromises.delete(requestKey);
5398
5631
  } else {
5399
5632
  requestPromises.delete("liveblocks-user-token");
5400
5633
  }
@@ -5405,6 +5638,43 @@ function createAuthManager(authOptions, onAuthenticate) {
5405
5638
  getAuthValue
5406
5639
  };
5407
5640
  }
5641
+ function getAuthRequestKey(request) {
5642
+ if (request.roomId === void 0) {
5643
+ return void 0;
5644
+ }
5645
+ return `${request.roomId}:${request.resource}:${request.access}`;
5646
+ }
5647
+ function makeCachedToken(token, expiresAt) {
5648
+ if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
5649
+ return {
5650
+ token,
5651
+ expiresAt,
5652
+ permissions: Object.entries(token.parsed.perms).map(
5653
+ ([pattern, scopes]) => ({
5654
+ pattern,
5655
+ scopes: normalizeRoomPermissions(scopes)
5656
+ })
5657
+ )
5658
+ };
5659
+ }
5660
+ return { token, expiresAt };
5661
+ }
5662
+ function cachedTokenSatisfiesRequest(cachedToken, request) {
5663
+ if (cachedToken.token.parsed.k === "id" /* ID_TOKEN */) {
5664
+ return true;
5665
+ }
5666
+ if (request.resource === "personal") {
5667
+ return true;
5668
+ }
5669
+ if (request.roomId === void 0) {
5670
+ return false;
5671
+ }
5672
+ const matrix = resolveRoomPermissionMatrix(
5673
+ _nullishCoalesce(cachedToken.permissions, () => ( [])),
5674
+ request.roomId
5675
+ );
5676
+ return matrix !== void 0 && hasPermissionAccess(matrix, request.resource, request.access);
5677
+ }
5408
5678
  function prepareAuthentication(authOptions) {
5409
5679
  const { publicApiKey, authEndpoint } = authOptions;
5410
5680
  if (authEndpoint !== void 0 && publicApiKey !== void 0) {
@@ -5502,6 +5772,9 @@ var OpCode = Object.freeze({
5502
5772
  function isIgnoredOp(op) {
5503
5773
  return op.type === OpCode.DELETE_CRDT && op.id === "ACK";
5504
5774
  }
5775
+ function isCreateOp(op) {
5776
+ return op.type === OpCode.CREATE_OBJECT || op.type === OpCode.CREATE_REGISTER || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_LIST;
5777
+ }
5505
5778
 
5506
5779
  // src/protocol/StorageNode.ts
5507
5780
  var CrdtType = Object.freeze({
@@ -5759,12 +6032,112 @@ function asPos(str) {
5759
6032
  return isPos(str) ? str : convertToPos(str);
5760
6033
  }
5761
6034
 
6035
+ // src/crdts/UnacknowledgedOps.ts
6036
+ var UnacknowledgedOps = class {
6037
+ // opId -> op
6038
+ #byOpId = /* @__PURE__ */ new Map();
6039
+ // position -> (opId -> Create op)
6040
+ #createOpsByPosition = /* @__PURE__ */ new Map();
6041
+ // parentId -> (opId -> Create op)
6042
+ #createOpsByParent = /* @__PURE__ */ new Map();
6043
+ // opIds of pending ops that were in flight when a connection died, so the
6044
+ // server may already have processed them. See isPossiblyStored().
6045
+ #possiblyStoredOpIds = /* @__PURE__ */ new Set();
6046
+ #posKey(parentId, parentKey) {
6047
+ return `${parentId}
6048
+ ${parentKey}`;
6049
+ }
6050
+ get size() {
6051
+ return this.#byOpId.size;
6052
+ }
6053
+ /**
6054
+ * Mark the given Op as still unacknowledged.
6055
+ */
6056
+ add(op) {
6057
+ this.#byOpId.set(op.opId, op);
6058
+ if (isCreateOp(op)) {
6059
+ const posKey = this.#posKey(op.parentId, op.parentKey);
6060
+ let atPosition = this.#createOpsByPosition.get(posKey);
6061
+ if (atPosition === void 0) {
6062
+ atPosition = /* @__PURE__ */ new Map();
6063
+ this.#createOpsByPosition.set(posKey, atPosition);
6064
+ }
6065
+ atPosition.set(op.opId, op);
6066
+ let inParent = this.#createOpsByParent.get(op.parentId);
6067
+ if (inParent === void 0) {
6068
+ inParent = /* @__PURE__ */ new Map();
6069
+ this.#createOpsByParent.set(op.parentId, inParent);
6070
+ }
6071
+ inParent.set(op.opId, op);
6072
+ }
6073
+ }
6074
+ /**
6075
+ * Drop the op with the given opId from the set, because the server has
6076
+ * acknowledged it (confirmed our own op, or signalled it was seen but
6077
+ * ignored).
6078
+ */
6079
+ delete(opId) {
6080
+ const op = this.#byOpId.get(opId);
6081
+ if (op === void 0) {
6082
+ return;
6083
+ }
6084
+ this.#byOpId.delete(opId);
6085
+ this.#possiblyStoredOpIds.delete(opId);
6086
+ if (isCreateOp(op)) {
6087
+ const posKey = this.#posKey(op.parentId, op.parentKey);
6088
+ const atPosition = this.#createOpsByPosition.get(posKey);
6089
+ _optionalChain([atPosition, 'optionalAccess', _112 => _112.delete, 'call', _113 => _113(opId)]);
6090
+ if (atPosition !== void 0 && atPosition.size === 0) {
6091
+ this.#createOpsByPosition.delete(posKey);
6092
+ }
6093
+ const inParent = this.#createOpsByParent.get(op.parentId);
6094
+ _optionalChain([inParent, 'optionalAccess', _114 => _114.delete, 'call', _115 => _115(opId)]);
6095
+ if (inParent !== void 0 && inParent.size === 0) {
6096
+ this.#createOpsByParent.delete(op.parentId);
6097
+ }
6098
+ }
6099
+ }
6100
+ /**
6101
+ * The still-unacknowledged Create ops with the given `parentId` and
6102
+ * `parentKey` (targeting one exact position), in dispatch order. O(1) lookup.
6103
+ * Empty if none.
6104
+ */
6105
+ getByParentIdAndKey(parentId, parentKey) {
6106
+ return _nullishCoalesce(_optionalChain([this, 'access', _116 => _116.#createOpsByPosition, 'access', _117 => _117.get, 'call', _118 => _118(this.#posKey(parentId, parentKey)), 'optionalAccess', _119 => _119.values, 'call', _120 => _120()]), () => ( []));
6107
+ }
6108
+ /**
6109
+ * The still-unacknowledged Create ops with the given `parentId` (across all
6110
+ * positions), in dispatch order. O(1) lookup. Empty if none.
6111
+ */
6112
+ getByParentId(parentId) {
6113
+ return _nullishCoalesce(_optionalChain([this, 'access', _121 => _121.#createOpsByParent, 'access', _122 => _122.get, 'call', _123 => _123(parentId), 'optionalAccess', _124 => _124.values, 'call', _125 => _125()]), () => ( []));
6114
+ }
6115
+ /** All still-unacknowledged ops, in dispatch order. */
6116
+ values() {
6117
+ return this.#byOpId.values();
6118
+ }
6119
+ isPossiblyStored(opId) {
6120
+ return this.#possiblyStoredOpIds.has(opId);
6121
+ }
6122
+ /**
6123
+ * Mark every currently pending op as possibly stored on the server. Called
6124
+ * when the connection dies: all of these ops were in flight, and their
6125
+ * (possibly lost) acks would have been the only way to know their fate.
6126
+ */
6127
+ markAllAsPossiblyStored() {
6128
+ for (const opId of this.#byOpId.keys()) {
6129
+ this.#possiblyStoredOpIds.add(opId);
6130
+ }
6131
+ }
6132
+ };
6133
+
5762
6134
  // src/crdts/AbstractCrdt.ts
5763
6135
  function createManagedPool(roomId, options) {
5764
6136
  const {
5765
6137
  getCurrentConnectionId,
5766
6138
  onDispatch,
5767
- isStorageWritable = () => true
6139
+ isStorageWritable = () => true,
6140
+ unacknowledgedOps = new UnacknowledgedOps()
5768
6141
  } = options;
5769
6142
  let clock = 0;
5770
6143
  let opClock = 0;
@@ -5778,7 +6151,7 @@ function createManagedPool(roomId, options) {
5778
6151
  generateId: () => `${getCurrentConnectionId()}:${clock++}`,
5779
6152
  generateOpId: () => `${getCurrentConnectionId()}:${opClock++}`,
5780
6153
  dispatch(ops, reverse, storageUpdates) {
5781
- _optionalChain([onDispatch, 'optionalCall', _111 => _111(ops, reverse, storageUpdates)]);
6154
+ _optionalChain([onDispatch, 'optionalCall', _126 => _126(ops, reverse, storageUpdates)]);
5782
6155
  },
5783
6156
  assertStorageIsWritable: () => {
5784
6157
  if (!isStorageWritable()) {
@@ -5786,7 +6159,8 @@ function createManagedPool(roomId, options) {
5786
6159
  "Cannot write to storage with a read only user, please ensure the user has write permissions"
5787
6160
  );
5788
6161
  }
5789
- }
6162
+ },
6163
+ unacknowledgedOps
5790
6164
  };
5791
6165
  }
5792
6166
  function crdtAsLiveNode(value) {
@@ -6068,11 +6442,9 @@ function childNodeLt(a, b) {
6068
6442
  var LiveList = class _LiveList extends AbstractCrdt {
6069
6443
  #items;
6070
6444
  #implicitlyDeletedItems;
6071
- #unacknowledgedSets;
6072
6445
  constructor(items) {
6073
6446
  super();
6074
6447
  this.#implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
6075
- this.#unacknowledgedSets = /* @__PURE__ */ new Map();
6076
6448
  const nodes = [];
6077
6449
  let lastPos;
6078
6450
  for (const item of items) {
@@ -6102,12 +6474,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
6102
6474
  }
6103
6475
  /**
6104
6476
  * @internal
6105
- * This function assumes that the resulting ops will be sent to the server if they have an 'opId'
6106
- * so we mutate _unacknowledgedSets to avoid potential flickering
6107
- * https://github.com/liveblocks/liveblocks/pull/1177
6477
+ * Serializes this list (and its children) into Create ops. Each child's
6478
+ * create is tagged with the "set" intent (in the loop below) so that a list
6479
+ * created and immediately mutated doesn't transiently re-show its initial
6480
+ * items (flicker, https://github.com/liveblocks/liveblocks/pull/1177).
6108
6481
  *
6109
- * This is quite unintuitive and should disappear as soon as
6110
- * we introduce an explicit LiveList.Set operation
6482
+ * This is quite unintuitive and should disappear as soon as we introduce an
6483
+ * explicit LiveList.Set operation.
6111
6484
  */
6112
6485
  _toOps(parentId, parentKey) {
6113
6486
  if (this._id === void 0) {
@@ -6123,7 +6496,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6123
6496
  ops.push(op);
6124
6497
  for (const item of this.#items) {
6125
6498
  const parentKey2 = item._getParentKeyOrThrow();
6126
- const childOps = addIntentToOpTree(
6499
+ const childOps = addIntentToRootOp(
6127
6500
  item._toOps(this._id, parentKey2),
6128
6501
  "set"
6129
6502
  );
@@ -6167,6 +6540,28 @@ var LiveList = class _LiveList extends AbstractCrdt {
6167
6540
  (item) => item._getParentKeyOrThrow() === position
6168
6541
  );
6169
6542
  }
6543
+ /**
6544
+ * The opId of this list's still-unacknowledged "set" op at the given position,
6545
+ * or undefined if none. Derived from the room's unacknowledgedOps (the single
6546
+ * source of truth) rather than tracked in a per-instance map. The pool's
6547
+ * position index already scopes to this list's (parentId, position); the last
6548
+ * match wins, matching the original last-write-wins map semantics.
6549
+ */
6550
+ #unacknowledgedSetOpIdAt(position) {
6551
+ if (this._pool === void 0 || this._id === void 0) {
6552
+ return void 0;
6553
+ }
6554
+ let opId;
6555
+ for (const op of this._pool.unacknowledgedOps.getByParentIdAndKey(
6556
+ this._id,
6557
+ position
6558
+ )) {
6559
+ if (op.intent === "set") {
6560
+ opId = op.opId;
6561
+ }
6562
+ }
6563
+ return opId;
6564
+ }
6170
6565
  /** @internal */
6171
6566
  _attach(id, pool) {
6172
6567
  super._attach(id, pool);
@@ -6247,13 +6642,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
6247
6642
  if (deletedDelta) {
6248
6643
  delta.push(deletedDelta);
6249
6644
  }
6250
- const unacknowledgedOpId = this.#unacknowledgedSets.get(op.parentKey);
6251
- if (unacknowledgedOpId !== void 0) {
6252
- if (unacknowledgedOpId !== op.opId) {
6253
- return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
6254
- } else {
6255
- this.#unacknowledgedSets.delete(op.parentKey);
6256
- }
6645
+ const unacknowledgedOpId = this.#unacknowledgedSetOpIdAt(op.parentKey);
6646
+ if (unacknowledgedOpId !== void 0 && unacknowledgedOpId !== op.opId) {
6647
+ return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
6257
6648
  }
6258
6649
  const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey);
6259
6650
  const existingItem = this.#items.find((item) => item._id === op.id);
@@ -6344,11 +6735,92 @@ var LiveList = class _LiveList extends AbstractCrdt {
6344
6735
  this.#shiftItemPosition(existingItemIndex, key);
6345
6736
  }
6346
6737
  const { newItem, newIndex } = this.#createAttachItemAndSort(op, key);
6738
+ const bumpDeltas = this.#bumpUnackedPushesAbove(key);
6347
6739
  return {
6348
- modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
6740
+ modified: makeUpdate(this, [
6741
+ insertDelta(newIndex, newItem),
6742
+ ...bumpDeltas
6743
+ ]),
6349
6744
  reverse: []
6350
6745
  };
6351
6746
  }
6747
+ /**
6748
+ * This list's own still-unacknowledged pushed items (their `intent: "push"`
6749
+ * Create op is still pending in the room's unacknowledgedOps). Derived from
6750
+ * the single source of truth, so an item drops out the instant its op is
6751
+ * acked, with no per-instance membership to leak. Yielded in push order.
6752
+ *
6753
+ * Excludes ops that may already be stored on the server (they were in
6754
+ * flight when a connection died, so their fate is unknown): the bump
6755
+ * prediction assumes the server has not processed the op yet, which is only
6756
+ * guaranteed for ops sent on the current connection. For these excluded
6757
+ * ops, the server's (re-)ack states the authoritative position; predicting
6758
+ * locally could produce a wrong position that no ack would correct.
6759
+ *
6760
+ * Restricted to items currently in `#items`: a pushed node whose op is still
6761
+ * pending may have been pulled out of the list (e.g. implicitly deleted by a
6762
+ * remote set, or removed by an undo) while still living in the pool, and such
6763
+ * a node must not be repositioned.
6764
+ */
6765
+ *#unackedPushNodes() {
6766
+ if (this._pool === void 0 || this._id === void 0) {
6767
+ return;
6768
+ }
6769
+ for (const op of this._pool.unacknowledgedOps.getByParentId(this._id)) {
6770
+ if (op.intent !== "push") {
6771
+ continue;
6772
+ }
6773
+ if (this._pool.unacknowledgedOps.isPossiblyStored(op.opId)) {
6774
+ continue;
6775
+ }
6776
+ const node = this._pool.getNode(op.id);
6777
+ if (node !== void 0 && this.#items.includes(node)) {
6778
+ yield node;
6779
+ }
6780
+ }
6781
+ }
6782
+ /**
6783
+ * Optimistic no-flip for pushed items. When a remote op lands at or below my
6784
+ * still-unacked pushed items, those items must end up *after* it: FIFO plus
6785
+ * the room's serial processing guarantee the remote was processed first, so
6786
+ * my unacked pushes belong behind it. Re-chain the whole unacked-push block,
6787
+ * in push order, to sit after the highest confirmed sibling, so it keeps
6788
+ * rendering as a contiguous tail instead of getting interleaved. Local-only;
6789
+ * the real acks overwrite these keys with the (identical) server keys.
6790
+ */
6791
+ #bumpUnackedPushesAbove(remoteKey) {
6792
+ const pending = new Set(this.#unackedPushNodes());
6793
+ if (pending.size === 0) {
6794
+ return [];
6795
+ }
6796
+ let minPending;
6797
+ for (const node of pending) {
6798
+ const pos = node._parentPos;
6799
+ if (minPending === void 0 || pos < minPending) {
6800
+ minPending = pos;
6801
+ }
6802
+ }
6803
+ if (remoteKey < nn(minPending)) {
6804
+ return [];
6805
+ }
6806
+ let base;
6807
+ for (const item of this.#items) {
6808
+ if (!pending.has(item)) {
6809
+ base = item._parentPos;
6810
+ }
6811
+ }
6812
+ const deltas = [];
6813
+ for (const node of pending) {
6814
+ const previousIndex = this.#items.findIndex((item) => item === node);
6815
+ base = makePosition(base);
6816
+ this.#updateItemPosition(node, base);
6817
+ const index = this.#items.findIndex((item) => item === node);
6818
+ if (index !== previousIndex) {
6819
+ deltas.push(moveDelta(previousIndex, index, node));
6820
+ }
6821
+ }
6822
+ return deltas;
6823
+ }
6352
6824
  #applyInsertAck(op) {
6353
6825
  const existingItem = this.#items.find((item) => item._id === op.id);
6354
6826
  const key = asPos(op.parentKey);
@@ -6403,7 +6875,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6403
6875
  #applyInsertUndoRedo(op) {
6404
6876
  const { id, parentKey: key } = op;
6405
6877
  const child = creationOpToLiveNode(op);
6406
- if (_optionalChain([this, 'access', _112 => _112._pool, 'optionalAccess', _113 => _113.getNode, 'call', _114 => _114(id)]) !== void 0) {
6878
+ if (_optionalChain([this, 'access', _127 => _127._pool, 'optionalAccess', _128 => _128.getNode, 'call', _129 => _129(id)]) !== void 0) {
6407
6879
  return { modified: false };
6408
6880
  }
6409
6881
  child._attach(id, nn(this._pool));
@@ -6411,8 +6883,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
6411
6883
  const existingItemIndex = this._indexOfPosition(key);
6412
6884
  let newKey = key;
6413
6885
  if (existingItemIndex !== -1) {
6414
- const before2 = _optionalChain([this, 'access', _115 => _115.#items, 'access', _116 => _116.at, 'call', _117 => _117(existingItemIndex), 'optionalAccess', _118 => _118._parentPos]);
6415
- const after2 = _optionalChain([this, 'access', _119 => _119.#items, 'access', _120 => _120.at, 'call', _121 => _121(existingItemIndex + 1), 'optionalAccess', _122 => _122._parentPos]);
6886
+ const before2 = _optionalChain([this, 'access', _130 => _130.#items, 'access', _131 => _131.at, 'call', _132 => _132(existingItemIndex), 'optionalAccess', _133 => _133._parentPos]);
6887
+ const after2 = _optionalChain([this, 'access', _134 => _134.#items, 'access', _135 => _135.at, 'call', _136 => _136(existingItemIndex + 1), 'optionalAccess', _137 => _137._parentPos]);
6416
6888
  newKey = makePosition(before2, after2);
6417
6889
  child._setParentLink(this, newKey);
6418
6890
  }
@@ -6426,10 +6898,9 @@ var LiveList = class _LiveList extends AbstractCrdt {
6426
6898
  #applySetUndoRedo(op) {
6427
6899
  const { id, parentKey: key } = op;
6428
6900
  const child = creationOpToLiveNode(op);
6429
- if (_optionalChain([this, 'access', _123 => _123._pool, 'optionalAccess', _124 => _124.getNode, 'call', _125 => _125(id)]) !== void 0) {
6901
+ if (_optionalChain([this, 'access', _138 => _138._pool, 'optionalAccess', _139 => _139.getNode, 'call', _140 => _140(id)]) !== void 0) {
6430
6902
  return { modified: false };
6431
6903
  }
6432
- this.#unacknowledgedSets.set(key, nn(op.opId));
6433
6904
  const indexOfItemWithSameKey = this._indexOfPosition(key);
6434
6905
  child._attach(id, nn(this._pool));
6435
6906
  child._setParentLink(this, key);
@@ -6439,7 +6910,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6439
6910
  existingItem._detach();
6440
6911
  this.#items.remove(existingItem);
6441
6912
  this.#items.add(child);
6442
- const reverse = addIntentToOpTree(
6913
+ const reverse = addIntentToRootOp(
6443
6914
  existingItem._toOps(nn(this._id), key),
6444
6915
  "set",
6445
6916
  op.id
@@ -6548,7 +7019,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6548
7019
  } else {
6549
7020
  this.#updateItemPositionAt(
6550
7021
  existingItemIndex,
6551
- makePosition(newKey, _optionalChain([this, 'access', _126 => _126.#items, 'access', _127 => _127.at, 'call', _128 => _128(existingItemIndex + 1), 'optionalAccess', _129 => _129._parentPos]))
7022
+ makePosition(newKey, _optionalChain([this, 'access', _141 => _141.#items, 'access', _142 => _142.at, 'call', _143 => _143(existingItemIndex + 1), 'optionalAccess', _144 => _144._parentPos]))
6552
7023
  );
6553
7024
  const previousIndex = this.#items.findIndex((item) => item === child);
6554
7025
  this.#updateItemPosition(child, newKey);
@@ -6575,7 +7046,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6575
7046
  this,
6576
7047
  makePosition(
6577
7048
  newKey,
6578
- _optionalChain([this, 'access', _130 => _130.#items, 'access', _131 => _131.at, 'call', _132 => _132(existingItemIndex + 1), 'optionalAccess', _133 => _133._parentPos])
7049
+ _optionalChain([this, 'access', _145 => _145.#items, 'access', _146 => _146.at, 'call', _147 => _147(existingItemIndex + 1), 'optionalAccess', _148 => _148._parentPos])
6579
7050
  )
6580
7051
  );
6581
7052
  this.#items.reposition(existingItem);
@@ -6599,7 +7070,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6599
7070
  existingItemIndex,
6600
7071
  makePosition(
6601
7072
  newKey,
6602
- _optionalChain([this, 'access', _134 => _134.#items, 'access', _135 => _135.at, 'call', _136 => _136(existingItemIndex + 1), 'optionalAccess', _137 => _137._parentPos])
7073
+ _optionalChain([this, 'access', _149 => _149.#items, 'access', _150 => _150.at, 'call', _151 => _151(existingItemIndex + 1), 'optionalAccess', _152 => _152._parentPos])
6603
7074
  )
6604
7075
  );
6605
7076
  }
@@ -6627,7 +7098,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6627
7098
  if (existingItemIndex !== -1) {
6628
7099
  actualNewKey = makePosition(
6629
7100
  newKey,
6630
- _optionalChain([this, 'access', _138 => _138.#items, 'access', _139 => _139.at, 'call', _140 => _140(existingItemIndex + 1), 'optionalAccess', _141 => _141._parentPos])
7101
+ _optionalChain([this, 'access', _153 => _153.#items, 'access', _154 => _154.at, 'call', _155 => _155(existingItemIndex + 1), 'optionalAccess', _156 => _156._parentPos])
6631
7102
  );
6632
7103
  }
6633
7104
  this.#updateItemPosition(child, actualNewKey);
@@ -6701,14 +7172,14 @@ var LiveList = class _LiveList extends AbstractCrdt {
6701
7172
  * instead of resolving its position against the client's stale view.
6702
7173
  */
6703
7174
  #injectAt(element, index, intent) {
6704
- _optionalChain([this, 'access', _142 => _142._pool, 'optionalAccess', _143 => _143.assertStorageIsWritable, 'call', _144 => _144()]);
7175
+ _optionalChain([this, 'access', _157 => _157._pool, 'optionalAccess', _158 => _158.assertStorageIsWritable, 'call', _159 => _159()]);
6705
7176
  if (index < 0 || index > this.#items.length) {
6706
7177
  throw new Error(
6707
7178
  `Cannot insert list item at index "${index}". index should be between 0 and ${this.#items.length}`
6708
7179
  );
6709
7180
  }
6710
- const before2 = _optionalChain([this, 'access', _145 => _145.#items, 'access', _146 => _146.at, 'call', _147 => _147(index - 1), 'optionalAccess', _148 => _148._parentPos]);
6711
- const after2 = _optionalChain([this, 'access', _149 => _149.#items, 'access', _150 => _150.at, 'call', _151 => _151(index), 'optionalAccess', _152 => _152._parentPos]);
7181
+ const before2 = _optionalChain([this, 'access', _160 => _160.#items, 'access', _161 => _161.at, 'call', _162 => _162(index - 1), 'optionalAccess', _163 => _163._parentPos]);
7182
+ const after2 = _optionalChain([this, 'access', _164 => _164.#items, 'access', _165 => _165.at, 'call', _166 => _166(index), 'optionalAccess', _167 => _167._parentPos]);
6712
7183
  const position = makePosition(before2, after2);
6713
7184
  const value = lsonToLiveNode(element);
6714
7185
  value._setParentLink(this, position);
@@ -6718,7 +7189,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6718
7189
  value._attach(id, this._pool);
6719
7190
  const ops = value._toOpsWithOpId(this._id, position, this._pool);
6720
7191
  this._pool.dispatch(
6721
- intent === "push" ? addIntentToOpTree(ops, "push") : ops,
7192
+ intent === "push" ? addIntentToRootOp(ops, "push") : ops,
6722
7193
  [{ type: OpCode.DELETE_CRDT, id }],
6723
7194
  /* @__PURE__ */ new Map([
6724
7195
  [this._id, makeUpdate(this, [insertDelta(index, value)])]
@@ -6732,7 +7203,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6732
7203
  * @param targetIndex The index where the element should be after moving.
6733
7204
  */
6734
7205
  move(index, targetIndex) {
6735
- _optionalChain([this, 'access', _153 => _153._pool, 'optionalAccess', _154 => _154.assertStorageIsWritable, 'call', _155 => _155()]);
7206
+ _optionalChain([this, 'access', _168 => _168._pool, 'optionalAccess', _169 => _169.assertStorageIsWritable, 'call', _170 => _170()]);
6736
7207
  if (targetIndex < 0) {
6737
7208
  throw new Error("targetIndex cannot be less than 0");
6738
7209
  }
@@ -6750,11 +7221,11 @@ var LiveList = class _LiveList extends AbstractCrdt {
6750
7221
  let beforePosition = null;
6751
7222
  let afterPosition = null;
6752
7223
  if (index < targetIndex) {
6753
- afterPosition = targetIndex === this.#items.length - 1 ? void 0 : _optionalChain([this, 'access', _156 => _156.#items, 'access', _157 => _157.at, 'call', _158 => _158(targetIndex + 1), 'optionalAccess', _159 => _159._parentPos]);
7224
+ afterPosition = targetIndex === this.#items.length - 1 ? void 0 : _optionalChain([this, 'access', _171 => _171.#items, 'access', _172 => _172.at, 'call', _173 => _173(targetIndex + 1), 'optionalAccess', _174 => _174._parentPos]);
6754
7225
  beforePosition = this.#items.at(targetIndex)._parentPos;
6755
7226
  } else {
6756
7227
  afterPosition = this.#items.at(targetIndex)._parentPos;
6757
- beforePosition = targetIndex === 0 ? void 0 : _optionalChain([this, 'access', _160 => _160.#items, 'access', _161 => _161.at, 'call', _162 => _162(targetIndex - 1), 'optionalAccess', _163 => _163._parentPos]);
7228
+ beforePosition = targetIndex === 0 ? void 0 : _optionalChain([this, 'access', _175 => _175.#items, 'access', _176 => _176.at, 'call', _177 => _177(targetIndex - 1), 'optionalAccess', _178 => _178._parentPos]);
6758
7229
  }
6759
7230
  const position = makePosition(beforePosition, afterPosition);
6760
7231
  const item = this.#items.at(index);
@@ -6789,7 +7260,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6789
7260
  * @param index The index of the element to delete
6790
7261
  */
6791
7262
  delete(index) {
6792
- _optionalChain([this, 'access', _164 => _164._pool, 'optionalAccess', _165 => _165.assertStorageIsWritable, 'call', _166 => _166()]);
7263
+ _optionalChain([this, 'access', _179 => _179._pool, 'optionalAccess', _180 => _180.assertStorageIsWritable, 'call', _181 => _181()]);
6793
7264
  if (index < 0 || index >= this.#items.length) {
6794
7265
  throw new Error(
6795
7266
  `Cannot delete list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
@@ -6822,7 +7293,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6822
7293
  }
6823
7294
  }
6824
7295
  clear() {
6825
- _optionalChain([this, 'access', _167 => _167._pool, 'optionalAccess', _168 => _168.assertStorageIsWritable, 'call', _169 => _169()]);
7296
+ _optionalChain([this, 'access', _182 => _182._pool, 'optionalAccess', _183 => _183.assertStorageIsWritable, 'call', _184 => _184()]);
6826
7297
  if (this._pool) {
6827
7298
  const ops = [];
6828
7299
  const reverseOps = [];
@@ -6856,7 +7327,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
6856
7327
  }
6857
7328
  }
6858
7329
  set(index, item) {
6859
- _optionalChain([this, 'access', _170 => _170._pool, 'optionalAccess', _171 => _171.assertStorageIsWritable, 'call', _172 => _172()]);
7330
+ _optionalChain([this, 'access', _185 => _185._pool, 'optionalAccess', _186 => _186.assertStorageIsWritable, 'call', _187 => _187()]);
6860
7331
  if (index < 0 || index >= this.#items.length) {
6861
7332
  throw new Error(
6862
7333
  `Cannot set list item at index "${index}". index should be between 0 and ${this.#items.length - 1}`
@@ -6876,13 +7347,12 @@ var LiveList = class _LiveList extends AbstractCrdt {
6876
7347
  value._attach(id, this._pool);
6877
7348
  const storageUpdates = /* @__PURE__ */ new Map();
6878
7349
  storageUpdates.set(this._id, makeUpdate(this, [setDelta(index, value)]));
6879
- const ops = addIntentToOpTree(
7350
+ const ops = addIntentToRootOp(
6880
7351
  value._toOpsWithOpId(this._id, position, this._pool),
6881
7352
  "set",
6882
7353
  existingId
6883
7354
  );
6884
- this.#unacknowledgedSets.set(position, nn(ops[0].opId));
6885
- const reverseOps = addIntentToOpTree(
7355
+ const reverseOps = addIntentToRootOp(
6886
7356
  existingItem._toOps(this._id, position),
6887
7357
  "set",
6888
7358
  id
@@ -7016,7 +7486,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
7016
7486
  #shiftItemPosition(index, key) {
7017
7487
  const shiftedPosition = makePosition(
7018
7488
  key,
7019
- this.#items.length > index + 1 ? _optionalChain([this, 'access', _173 => _173.#items, 'access', _174 => _174.at, 'call', _175 => _175(index + 1), 'optionalAccess', _176 => _176._parentPos]) : void 0
7489
+ this.#items.length > index + 1 ? _optionalChain([this, 'access', _188 => _188.#items, 'access', _189 => _189.at, 'call', _190 => _190(index + 1), 'optionalAccess', _191 => _191._parentPos]) : void 0
7020
7490
  );
7021
7491
  this.#updateItemPositionAt(index, shiftedPosition);
7022
7492
  }
@@ -7085,7 +7555,7 @@ function moveDelta(previousIndex, index, item) {
7085
7555
  previousIndex
7086
7556
  };
7087
7557
  }
7088
- function addIntentToOpTree(ops, intent, deletedId) {
7558
+ function addIntentToRootOp(ops, intent, deletedId) {
7089
7559
  return ops.map((op, index) => {
7090
7560
  if (index === 0) {
7091
7561
  const firstOp = op;
@@ -7265,7 +7735,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
7265
7735
  * @param value The value of the element to add. Should be serializable to JSON.
7266
7736
  */
7267
7737
  set(key, value) {
7268
- _optionalChain([this, 'access', _177 => _177._pool, 'optionalAccess', _178 => _178.assertStorageIsWritable, 'call', _179 => _179()]);
7738
+ _optionalChain([this, 'access', _192 => _192._pool, 'optionalAccess', _193 => _193.assertStorageIsWritable, 'call', _194 => _194()]);
7269
7739
  const oldValue = this.#map.get(key);
7270
7740
  if (oldValue) {
7271
7741
  oldValue._detach();
@@ -7311,7 +7781,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
7311
7781
  * @returns true if an element existed and has been removed, or false if the element does not exist.
7312
7782
  */
7313
7783
  delete(key) {
7314
- _optionalChain([this, 'access', _180 => _180._pool, 'optionalAccess', _181 => _181.assertStorageIsWritable, 'call', _182 => _182()]);
7784
+ _optionalChain([this, 'access', _195 => _195._pool, 'optionalAccess', _196 => _196.assertStorageIsWritable, 'call', _197 => _197()]);
7315
7785
  const item = this.#map.get(key);
7316
7786
  if (item === void 0) {
7317
7787
  return false;
@@ -7741,6 +8211,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
7741
8211
  const id = nn(this._id);
7742
8212
  const parentKey = nn(child._parentKey);
7743
8213
  const reverse = child._toOps(id, parentKey);
8214
+ const deletedItem = liveNodeToLson(child);
7744
8215
  for (const [key, value] of this.#synced) {
7745
8216
  if (value === child) {
7746
8217
  this.#synced.delete(key);
@@ -7752,7 +8223,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
7752
8223
  node: this,
7753
8224
  type: "LiveObject",
7754
8225
  updates: {
7755
- [parentKey]: { type: "delete" }
8226
+ [parentKey]: { type: "delete", deletedItem }
7756
8227
  }
7757
8228
  };
7758
8229
  return { modified: storageUpdate, reverse };
@@ -7922,20 +8393,20 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
7922
8393
  * Caveat: this method will not add changes to the undo/redo stack.
7923
8394
  */
7924
8395
  setLocal(key, value) {
7925
- _optionalChain([this, 'access', _183 => _183._pool, 'optionalAccess', _184 => _184.assertStorageIsWritable, 'call', _185 => _185()]);
8396
+ _optionalChain([this, 'access', _198 => _198._pool, 'optionalAccess', _199 => _199.assertStorageIsWritable, 'call', _200 => _200()]);
7926
8397
  const deleteResult = this.#prepareDelete(key);
7927
8398
  this.#local.set(key, value);
7928
8399
  this.invalidate();
7929
8400
  if (this._pool !== void 0 && this._id !== void 0) {
7930
- const ops = _nullishCoalesce(_optionalChain([deleteResult, 'optionalAccess', _186 => _186[0]]), () => ( []));
7931
- const reverse = _nullishCoalesce(_optionalChain([deleteResult, 'optionalAccess', _187 => _187[1]]), () => ( []));
7932
- const storageUpdates = _nullishCoalesce(_optionalChain([deleteResult, 'optionalAccess', _188 => _188[2]]), () => ( /* @__PURE__ */ new Map()));
8401
+ const ops = _nullishCoalesce(_optionalChain([deleteResult, 'optionalAccess', _201 => _201[0]]), () => ( []));
8402
+ const reverse = _nullishCoalesce(_optionalChain([deleteResult, 'optionalAccess', _202 => _202[1]]), () => ( []));
8403
+ const storageUpdates = _nullishCoalesce(_optionalChain([deleteResult, 'optionalAccess', _203 => _203[2]]), () => ( /* @__PURE__ */ new Map()));
7933
8404
  const existing = storageUpdates.get(this._id);
7934
8405
  storageUpdates.set(this._id, {
7935
8406
  node: this,
7936
8407
  type: "LiveObject",
7937
8408
  updates: {
7938
- ..._optionalChain([existing, 'optionalAccess', _189 => _189.updates]),
8409
+ ..._optionalChain([existing, 'optionalAccess', _204 => _204.updates]),
7939
8410
  [key]: { type: "update" }
7940
8411
  }
7941
8412
  });
@@ -7955,7 +8426,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
7955
8426
  * #synced or pool/id are unavailable. Does NOT dispatch.
7956
8427
  */
7957
8428
  #prepareDelete(key) {
7958
- _optionalChain([this, 'access', _190 => _190._pool, 'optionalAccess', _191 => _191.assertStorageIsWritable, 'call', _192 => _192()]);
8429
+ _optionalChain([this, 'access', _205 => _205._pool, 'optionalAccess', _206 => _206.assertStorageIsWritable, 'call', _207 => _207()]);
7959
8430
  const k = key;
7960
8431
  if (this.#local.has(k) && !this.#synced.has(k)) {
7961
8432
  const oldValue2 = this.#local.get(k);
@@ -8031,7 +8502,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8031
8502
  const result = this.#prepareDelete(key);
8032
8503
  if (result) {
8033
8504
  const [ops, reverse, storageUpdates] = result;
8034
- _optionalChain([this, 'access', _193 => _193._pool, 'optionalAccess', _194 => _194.dispatch, 'call', _195 => _195(ops, reverse, storageUpdates)]);
8505
+ _optionalChain([this, 'access', _208 => _208._pool, 'optionalAccess', _209 => _209.dispatch, 'call', _210 => _210(ops, reverse, storageUpdates)]);
8035
8506
  }
8036
8507
  }
8037
8508
  /**
@@ -8039,7 +8510,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8039
8510
  * @param patch The object used to overrides properties
8040
8511
  */
8041
8512
  update(patch) {
8042
- _optionalChain([this, 'access', _196 => _196._pool, 'optionalAccess', _197 => _197.assertStorageIsWritable, 'call', _198 => _198()]);
8513
+ _optionalChain([this, 'access', _211 => _211._pool, 'optionalAccess', _212 => _212.assertStorageIsWritable, 'call', _213 => _213()]);
8043
8514
  if (_LiveObject.detectLargeObjects) {
8044
8515
  const data = {};
8045
8516
  for (const [key, value] of this.#synced) {
@@ -8329,23 +8800,93 @@ function lsonToLiveNode(value) {
8329
8800
  return new LiveRegister(value);
8330
8801
  }
8331
8802
  }
8332
- function getTreesDiffOperations(currentItems, newItems) {
8803
+ function dumpPool(pool) {
8804
+ const rows = Array.from(pool.nodes.values(), (node) => {
8805
+ const parent = node.parent;
8806
+ const parentId = parent.type === "HasParent" ? _nullishCoalesce(parent.node._id, () => ( "?")) : parent.type === "Orphaned" ? "<orphaned>" : "-";
8807
+ let value;
8808
+ if (node instanceof LiveRegister) {
8809
+ value = stringifyOrLog(node.data);
8810
+ } else if (node instanceof LiveList) {
8811
+ value = "<LiveList>";
8812
+ } else if (node instanceof LiveMap) {
8813
+ value = "<LiveMap>";
8814
+ } else {
8815
+ value = "<LiveObject>";
8816
+ }
8817
+ return { id: nn(node._id), parentId, key: _nullishCoalesce(node._parentKey, () => ( "")), value };
8818
+ });
8819
+ rows.sort((a, b) => {
8820
+ if (a.parentId !== b.parentId) return a.parentId < b.parentId ? -1 : 1;
8821
+ if (a.key !== b.key) return a.key < b.key ? -1 : 1;
8822
+ return 0;
8823
+ });
8824
+ return rows.map(
8825
+ (r) => ` ${r.id} parent=${r.parentId} key=${r.key || "\u2014"} ${r.value}`
8826
+ ).join("\n");
8827
+ }
8828
+ function isJsonEq(a, b) {
8829
+ if (a === b) {
8830
+ return true;
8831
+ }
8832
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
8833
+ return false;
8834
+ }
8835
+ if (Array.isArray(a) || Array.isArray(b)) {
8836
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
8837
+ return false;
8838
+ }
8839
+ for (let i = 0; i < a.length; i++) {
8840
+ if (!isJsonEq(a[i], b[i])) {
8841
+ return false;
8842
+ }
8843
+ }
8844
+ return true;
8845
+ }
8846
+ const aKeys = Object.keys(a);
8847
+ if (aKeys.length !== Object.keys(b).length) {
8848
+ return false;
8849
+ }
8850
+ for (const key of aKeys) {
8851
+ if (!isJsonEq(a[key], b[key])) {
8852
+ return false;
8853
+ }
8854
+ }
8855
+ return true;
8856
+ }
8857
+ function diffNodeMap(prev, next) {
8333
8858
  const ops = [];
8334
- currentItems.forEach((_, id) => {
8335
- if (!newItems.get(id)) {
8859
+ prev.forEach((_, id) => {
8860
+ if (!next.get(id)) {
8336
8861
  ops.push({ type: OpCode.DELETE_CRDT, id });
8337
8862
  }
8338
8863
  });
8339
- newItems.forEach((crdt, id) => {
8340
- const currentCrdt = currentItems.get(id);
8864
+ next.forEach((crdt, id) => {
8865
+ const currentCrdt = prev.get(id);
8341
8866
  if (currentCrdt) {
8342
8867
  if (crdt.type === CrdtType.OBJECT) {
8343
- if (currentCrdt.type !== CrdtType.OBJECT || stringifyOrLog(crdt.data) !== stringifyOrLog(currentCrdt.data)) {
8344
- ops.push({
8345
- type: OpCode.UPDATE_OBJECT,
8346
- id,
8347
- data: crdt.data
8348
- });
8868
+ if (currentCrdt.type !== CrdtType.OBJECT) {
8869
+ ops.push({ type: OpCode.UPDATE_OBJECT, id, data: crdt.data });
8870
+ } else {
8871
+ const changed = /* @__PURE__ */ new Map();
8872
+ for (const key of Object.keys(crdt.data)) {
8873
+ const value = crdt.data[key];
8874
+ if (value !== void 0 && !isJsonEq(value, currentCrdt.data[key])) {
8875
+ changed.set(key, value);
8876
+ }
8877
+ }
8878
+ if (changed.size > 0) {
8879
+ ops.push({
8880
+ type: OpCode.UPDATE_OBJECT,
8881
+ id,
8882
+ data: Object.fromEntries(changed)
8883
+ });
8884
+ }
8885
+ for (const key of Object.keys(currentCrdt.data)) {
8886
+ if (!(key in crdt.data)) {
8887
+ ops.push({ type: OpCode.DELETE_OBJECT_KEY, id, key });
8888
+ }
8889
+ }
8349
8890
  }
8350
8891
  }
8351
8892
  if (crdt.parentKey !== currentCrdt.parentKey) {
@@ -8456,7 +8997,7 @@ function sendToPanel(message, options) {
8456
8997
  ...message,
8457
8998
  source: "liveblocks-devtools-client"
8458
8999
  };
8459
- if (!(_optionalChain([options, 'optionalAccess', _199 => _199.force]) || _bridgeActive)) {
9000
+ if (!(_optionalChain([options, 'optionalAccess', _214 => _214.force]) || _bridgeActive)) {
8460
9001
  return;
8461
9002
  }
8462
9003
  window.postMessage(fullMsg, "*");
@@ -8464,7 +9005,7 @@ function sendToPanel(message, options) {
8464
9005
  var eventSource = makeEventSource();
8465
9006
  if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
8466
9007
  window.addEventListener("message", (event) => {
8467
- if (event.source === window && _optionalChain([event, 'access', _200 => _200.data, 'optionalAccess', _201 => _201.source]) === "liveblocks-devtools-panel") {
9008
+ if (event.source === window && _optionalChain([event, 'access', _215 => _215.data, 'optionalAccess', _216 => _216.source]) === "liveblocks-devtools-panel") {
8468
9009
  eventSource.notify(event.data);
8469
9010
  } else {
8470
9011
  }
@@ -8568,7 +9109,7 @@ function partialSyncConnection(room) {
8568
9109
  });
8569
9110
  }
8570
9111
  function partialSyncStorage(room) {
8571
- const root = room.getStorageSnapshot();
9112
+ const root = room.getStorageOrNull();
8572
9113
  if (root) {
8573
9114
  sendToPanel({
8574
9115
  msg: "room::sync::partial",
@@ -8598,7 +9139,7 @@ function partialSyncOthers(room) {
8598
9139
  }
8599
9140
  }
8600
9141
  function fullSync(room) {
8601
- const root = room.getStorageSnapshot();
9142
+ const root = room.getStorageOrNull();
8602
9143
  const me = room[kInternal].getSelf_forDevTools();
8603
9144
  const others = room[kInternal].getOthers_forDevTools();
8604
9145
  room.fetchYDoc("");
@@ -8606,7 +9147,7 @@ function fullSync(room) {
8606
9147
  msg: "room::sync::full",
8607
9148
  roomId: room.id,
8608
9149
  status: room.getStatus(),
8609
- storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _202 => _202.toTreeNode, 'call', _203 => _203("root"), 'access', _204 => _204.payload]), () => ( null)),
9150
+ storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _217 => _217.toTreeNode, 'call', _218 => _218("root"), 'access', _219 => _219.payload]), () => ( null)),
8610
9151
  me,
8611
9152
  others
8612
9153
  });
@@ -9023,15 +9564,15 @@ var ClientMsgCode = Object.freeze({
9023
9564
 
9024
9565
  // src/refs/ManagedOthers.ts
9025
9566
  function makeUser(conn, presence) {
9026
- const { connectionId, id, info } = conn;
9027
- const canWrite = canWriteStorage(conn.scopes);
9567
+ const { connectionId, id, info, access } = conn;
9568
+ const { canWrite, canComment } = access;
9028
9569
  return freeze(
9029
9570
  compactObject({
9030
9571
  connectionId,
9031
9572
  id,
9032
9573
  info,
9033
9574
  canWrite,
9034
- canComment: canComment(conn.scopes),
9575
+ canComment,
9035
9576
  isReadOnly: !canWrite,
9036
9577
  // Deprecated, kept for backward-compatibility
9037
9578
  presence
@@ -9102,7 +9643,7 @@ var ManagedOthers = class {
9102
9643
  * Records a known connection. This records the connection ID and the
9103
9644
  * associated metadata.
9104
9645
  */
9105
- setConnection(connectionId, metaUserId, metaUserInfo, scopes) {
9646
+ setConnection(connectionId, metaUserId, metaUserInfo, access) {
9106
9647
  this.#internal.mutate((state) => {
9107
9648
  state.connections.set(
9108
9649
  connectionId,
@@ -9110,7 +9651,7 @@ var ManagedOthers = class {
9110
9651
  connectionId,
9111
9652
  id: metaUserId,
9112
9653
  info: metaUserInfo,
9113
- scopes
9654
+ access
9114
9655
  })
9115
9656
  );
9116
9657
  if (!state.presences.has(connectionId)) {
@@ -9263,6 +9804,14 @@ function defaultMessageFromContext(context) {
9263
9804
 
9264
9805
  // src/room.ts
9265
9806
  var FEEDS_TIMEOUT = 5e3;
9807
+ function connectionAccessFromScopes(scopes) {
9808
+ const roomPermissions = normalizeRoomPermissions(scopes);
9809
+ const matrix = permissionMatrixFromScopes(roomPermissions);
9810
+ return {
9811
+ canWrite: hasPermissionAccess(matrix, "storage", "write"),
9812
+ canComment: hasPermissionAccess(matrix, "comments", "write")
9813
+ };
9814
+ }
9266
9815
  function makeIdFactory(connectionId) {
9267
9816
  let count = 0;
9268
9817
  return () => `${connectionId}:${count++}`;
@@ -9285,15 +9834,15 @@ function installBackgroundTabSpy() {
9285
9834
  const doc = typeof document !== "undefined" ? document : void 0;
9286
9835
  const inBackgroundSince = { current: null };
9287
9836
  function onVisibilityChange() {
9288
- if (_optionalChain([doc, 'optionalAccess', _205 => _205.visibilityState]) === "hidden") {
9837
+ if (_optionalChain([doc, 'optionalAccess', _220 => _220.visibilityState]) === "hidden") {
9289
9838
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
9290
9839
  } else {
9291
9840
  inBackgroundSince.current = null;
9292
9841
  }
9293
9842
  }
9294
- _optionalChain([doc, 'optionalAccess', _206 => _206.addEventListener, 'call', _207 => _207("visibilitychange", onVisibilityChange)]);
9843
+ _optionalChain([doc, 'optionalAccess', _221 => _221.addEventListener, 'call', _222 => _222("visibilitychange", onVisibilityChange)]);
9295
9844
  const unsub = () => {
9296
- _optionalChain([doc, 'optionalAccess', _208 => _208.removeEventListener, 'call', _209 => _209("visibilitychange", onVisibilityChange)]);
9845
+ _optionalChain([doc, 'optionalAccess', _223 => _223.removeEventListener, 'call', _224 => _224("visibilitychange", onVisibilityChange)]);
9297
9846
  };
9298
9847
  return [inBackgroundSince, unsub];
9299
9848
  }
@@ -9338,6 +9887,7 @@ function createRoom(options, config) {
9338
9887
  delegates,
9339
9888
  config.enableDebugLogging
9340
9889
  );
9890
+ const unacknowledgedOps = new UnacknowledgedOps();
9341
9891
  const context = {
9342
9892
  buffer: {
9343
9893
  flushTimerID: void 0,
@@ -9365,14 +9915,15 @@ function createRoom(options, config) {
9365
9915
  pool: createManagedPool(roomId, {
9366
9916
  getCurrentConnectionId,
9367
9917
  onDispatch,
9368
- isStorageWritable
9918
+ isStorageWritable,
9919
+ unacknowledgedOps
9369
9920
  }),
9370
9921
  root: void 0,
9371
9922
  undoStack: [],
9372
9923
  redoStack: [],
9373
9924
  pausedHistory: null,
9374
9925
  activeBatch: null,
9375
- unacknowledgedOps: /* @__PURE__ */ new Map()
9926
+ unacknowledgedOps
9376
9927
  };
9377
9928
  const nodeMapBuffer = makeNodeMapBuffer();
9378
9929
  const stopwatch = config.enableDebugLogging ? makeStopWatch() : void 0;
@@ -9433,12 +9984,13 @@ function createRoom(options, config) {
9433
9984
  )
9434
9985
  };
9435
9986
  if (_getStorage$ !== null) {
9436
- refreshStorage({ flush: false });
9987
+ refreshStorage();
9437
9988
  }
9438
9989
  flushNowOrSoon();
9439
9990
  }
9440
9991
  function onDidDisconnect() {
9441
9992
  clearTimeout(context.buffer.flushTimerID);
9993
+ context.unacknowledgedOps.markAllAsPossiblyStored();
9442
9994
  }
9443
9995
  managedSocket.events.onMessage.subscribe(handleServerMessage);
9444
9996
  managedSocket.events.statusDidChange.subscribe(onStatusDidChange);
@@ -9484,8 +10036,8 @@ function createRoom(options, config) {
9484
10036
  }
9485
10037
  }
9486
10038
  function isStorageWritable() {
9487
- const scopes = _optionalChain([context, 'access', _210 => _210.dynamicSessionInfoSig, 'access', _211 => _211.get, 'call', _212 => _212(), 'optionalAccess', _213 => _213.scopes]);
9488
- return scopes !== void 0 ? canWriteStorage(scopes) : true;
10039
+ const permissionMatrix = _optionalChain([context, 'access', _225 => _225.dynamicSessionInfoSig, 'access', _226 => _226.get, 'call', _227 => _227(), 'optionalAccess', _228 => _228.permissionMatrix]);
10040
+ return permissionMatrix !== void 0 ? hasPermissionAccess(permissionMatrix, "storage", "write") : true;
9489
10041
  }
9490
10042
  const eventHub = {
9491
10043
  status: makeEventSource(),
@@ -9546,14 +10098,22 @@ function createRoom(options, config) {
9546
10098
  if (staticSession === null || dynamicSession === null) {
9547
10099
  return null;
9548
10100
  } else {
9549
- const canWrite = canWriteStorage(dynamicSession.scopes);
10101
+ const canWrite = hasPermissionAccess(
10102
+ dynamicSession.permissionMatrix,
10103
+ "storage",
10104
+ "write"
10105
+ );
9550
10106
  return {
9551
10107
  connectionId: dynamicSession.actor,
9552
10108
  id: staticSession.userId,
9553
10109
  info: staticSession.userInfo,
9554
10110
  presence: myPresence,
9555
10111
  canWrite,
9556
- canComment: canComment(dynamicSession.scopes)
10112
+ canComment: hasPermissionAccess(
10113
+ dynamicSession.permissionMatrix,
10114
+ "comments",
10115
+ "write"
10116
+ )
9557
10117
  };
9558
10118
  }
9559
10119
  }
@@ -9579,7 +10139,7 @@ function createRoom(options, config) {
9579
10139
  for (const [id, crdt] of context.pool.nodes) {
9580
10140
  currentItems.set(id, crdt._serialize());
9581
10141
  }
9582
- const ops = getTreesDiffOperations(currentItems, nodes);
10142
+ const ops = diffNodeMap(currentItems, nodes);
9583
10143
  const result = applyRemoteOps(ops);
9584
10144
  notify(result.updates);
9585
10145
  } else {
@@ -9588,7 +10148,7 @@ function createRoom(options, config) {
9588
10148
  context.pool
9589
10149
  );
9590
10150
  }
9591
- const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _214 => _214.get, 'call', _215 => _215(), 'optionalAccess', _216 => _216.canWrite]), () => ( true));
10151
+ const canWrite = _nullishCoalesce(_optionalChain([self, 'access', _229 => _229.get, 'call', _230 => _230(), 'optionalAccess', _231 => _231.canWrite]), () => ( true));
9592
10152
  const root = context.root;
9593
10153
  disableHistory(() => {
9594
10154
  for (const key in context.initialStorage) {
@@ -9793,7 +10353,7 @@ function createRoom(options, config) {
9793
10353
  }
9794
10354
  context.myPresence.patch(patch);
9795
10355
  if (context.activeBatch) {
9796
- if (_optionalChain([options2, 'optionalAccess', _217 => _217.addToHistory])) {
10356
+ if (_optionalChain([options2, 'optionalAccess', _232 => _232.addToHistory])) {
9797
10357
  context.activeBatch.reverseOps.pushLeft({
9798
10358
  type: "presence",
9799
10359
  data: oldValues
@@ -9802,7 +10362,7 @@ function createRoom(options, config) {
9802
10362
  context.activeBatch.updates.presence = true;
9803
10363
  } else {
9804
10364
  flushNowOrSoon();
9805
- if (_optionalChain([options2, 'optionalAccess', _218 => _218.addToHistory])) {
10365
+ if (_optionalChain([options2, 'optionalAccess', _233 => _233.addToHistory])) {
9806
10366
  addToUndoStack([{ type: "presence", data: oldValues }]);
9807
10367
  }
9808
10368
  notify({ presence: true });
@@ -9842,7 +10402,9 @@ function createRoom(options, config) {
9842
10402
  context.dynamicSessionInfoSig.set({
9843
10403
  actor: message.actor,
9844
10404
  nonce: message.nonce,
9845
- scopes: message.scopes,
10405
+ permissionMatrix: permissionMatrixFromScopes(
10406
+ normalizeRoomPermissions(message.scopes)
10407
+ ),
9846
10408
  meta: message.meta
9847
10409
  });
9848
10410
  context.idFactory = makeIdFactory(message.actor);
@@ -9863,7 +10425,7 @@ function createRoom(options, config) {
9863
10425
  connectionId,
9864
10426
  user.id,
9865
10427
  user.info,
9866
- user.scopes
10428
+ connectionAccessFromScopes(user.scopes)
9867
10429
  );
9868
10430
  }
9869
10431
  return { type: "reset" };
@@ -9883,7 +10445,7 @@ function createRoom(options, config) {
9883
10445
  message.actor,
9884
10446
  message.id,
9885
10447
  message.info,
9886
- message.scopes
10448
+ connectionAccessFromScopes(message.scopes)
9887
10449
  );
9888
10450
  context.buffer.messages.push({
9889
10451
  type: ClientMsgCode.UPDATE_PRESENCE,
@@ -9911,12 +10473,11 @@ function createRoom(options, config) {
9911
10473
  }
9912
10474
  }
9913
10475
  function applyAndSendOfflineOps(unackedOps) {
9914
- if (unackedOps.size === 0) {
10476
+ if (unackedOps.length === 0) {
9915
10477
  return;
9916
10478
  }
9917
10479
  const messages = [];
9918
- const inOps = Array.from(unackedOps.values());
9919
- const result = applyLocalOps(inOps);
10480
+ const result = applyLocalOps(unackedOps);
9920
10481
  messages.push({
9921
10482
  type: ClientMsgCode.UPDATE_STORAGE,
9922
10483
  ops: result.opsToEmit
@@ -9980,11 +10541,11 @@ function createRoom(options, config) {
9980
10541
  break;
9981
10542
  }
9982
10543
  case ServerMsgCode.STORAGE_CHUNK:
9983
- _optionalChain([stopwatch, 'optionalAccess', _219 => _219.lap, 'call', _220 => _220()]);
10544
+ _optionalChain([stopwatch, 'optionalAccess', _234 => _234.lap, 'call', _235 => _235()]);
9984
10545
  nodeMapBuffer.append(compactNodesToNodeStream(message.nodes));
9985
10546
  break;
9986
10547
  case ServerMsgCode.STORAGE_STREAM_END: {
9987
- const timing = _optionalChain([stopwatch, 'optionalAccess', _221 => _221.stop, 'call', _222 => _222()]);
10548
+ const timing = _optionalChain([stopwatch, 'optionalAccess', _236 => _236.stop, 'call', _237 => _237()]);
9988
10549
  if (timing) {
9989
10550
  const ms = (v) => `${v.toFixed(1)}ms`;
9990
10551
  const rest = timing.laps.slice(1);
@@ -10119,11 +10680,11 @@ function createRoom(options, config) {
10119
10680
  } else if (pendingFeedsRequests.has(requestId)) {
10120
10681
  const pending = pendingFeedsRequests.get(requestId);
10121
10682
  pendingFeedsRequests.delete(requestId);
10122
- _optionalChain([pending, 'optionalAccess', _223 => _223.reject, 'call', _224 => _224(err)]);
10683
+ _optionalChain([pending, 'optionalAccess', _238 => _238.reject, 'call', _239 => _239(err)]);
10123
10684
  } else if (pendingFeedMessagesRequests.has(requestId)) {
10124
10685
  const pending = pendingFeedMessagesRequests.get(requestId);
10125
10686
  pendingFeedMessagesRequests.delete(requestId);
10126
- _optionalChain([pending, 'optionalAccess', _225 => _225.reject, 'call', _226 => _226(err)]);
10687
+ _optionalChain([pending, 'optionalAccess', _240 => _240.reject, 'call', _241 => _241(err)]);
10127
10688
  }
10128
10689
  eventHub.feeds.notify(message);
10129
10690
  break;
@@ -10140,7 +10701,7 @@ function createRoom(options, config) {
10140
10701
  const storageOps = context.buffer.storageOperations;
10141
10702
  if (storageOps.length > 0) {
10142
10703
  for (const op of storageOps) {
10143
- context.unacknowledgedOps.set(op.opId, op);
10704
+ context.unacknowledgedOps.add(op);
10144
10705
  }
10145
10706
  notifyStorageStatus();
10146
10707
  }
@@ -10277,10 +10838,10 @@ function createRoom(options, config) {
10277
10838
  timeoutId,
10278
10839
  kind,
10279
10840
  feedId,
10280
- messageId: _optionalChain([options2, 'optionalAccess', _227 => _227.messageId]),
10281
- expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _228 => _228.expectedClientMessageId])
10841
+ messageId: _optionalChain([options2, 'optionalAccess', _242 => _242.messageId]),
10842
+ expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _243 => _243.expectedClientMessageId])
10282
10843
  });
10283
- if (kind === "add-message" && _optionalChain([options2, 'optionalAccess', _229 => _229.expectedClientMessageId]) === void 0) {
10844
+ if (kind === "add-message" && _optionalChain([options2, 'optionalAccess', _244 => _244.expectedClientMessageId]) === void 0) {
10284
10845
  const q = _nullishCoalesce(pendingAddMessageFifoByFeed.get(feedId), () => ( []));
10285
10846
  q.push(requestId);
10286
10847
  pendingAddMessageFifoByFeed.set(feedId, q);
@@ -10331,10 +10892,10 @@ function createRoom(options, config) {
10331
10892
  }
10332
10893
  if (!matched) {
10333
10894
  const q = pendingAddMessageFifoByFeed.get(message.feedId);
10334
- const headId = _optionalChain([q, 'optionalAccess', _230 => _230[0]]);
10895
+ const headId = _optionalChain([q, 'optionalAccess', _245 => _245[0]]);
10335
10896
  if (headId !== void 0) {
10336
10897
  const pending = pendingFeedMutations.get(headId);
10337
- if (_optionalChain([pending, 'optionalAccess', _231 => _231.kind]) === "add-message" && pending.expectedClientMessageId === void 0) {
10898
+ if (_optionalChain([pending, 'optionalAccess', _246 => _246.kind]) === "add-message" && pending.expectedClientMessageId === void 0) {
10338
10899
  settleFeedMutation(headId, "ok");
10339
10900
  }
10340
10901
  }
@@ -10367,36 +10928,25 @@ function createRoom(options, config) {
10367
10928
  }
10368
10929
  }
10369
10930
  function processInitialStorage(nodes) {
10370
- const unacknowledgedOps = new Map(context.unacknowledgedOps);
10931
+ const unacknowledgedOps2 = [...context.unacknowledgedOps.values()];
10371
10932
  createOrUpdateRootFromMessage(nodes);
10372
- applyAndSendOfflineOps(unacknowledgedOps);
10373
- _optionalChain([_resolveStoragePromise, 'optionalCall', _232 => _232()]);
10933
+ applyAndSendOfflineOps(unacknowledgedOps2);
10934
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _247 => _247()]);
10374
10935
  notifyStorageStatus();
10375
10936
  eventHub.storageDidLoad.notify();
10376
10937
  }
10377
- async function streamStorage() {
10378
- if (!managedSocket.authValue) return;
10379
- const nodes = new Map(
10380
- await httpClient.streamStorage({ roomId })
10381
- );
10382
- processInitialStorage(nodes);
10383
- }
10384
- function refreshStorage(options2) {
10938
+ function refreshStorage() {
10385
10939
  const messages = context.buffer.messages;
10386
- if (config.unstable_streamData) {
10387
- void streamStorage();
10388
- } else if (!messages.some((msg) => msg.type === ClientMsgCode.FETCH_STORAGE)) {
10940
+ if (!messages.some((msg) => msg.type === ClientMsgCode.FETCH_STORAGE)) {
10389
10941
  messages.push({ type: ClientMsgCode.FETCH_STORAGE });
10390
10942
  nodeMapBuffer.take();
10391
- _optionalChain([stopwatch, 'optionalAccess', _233 => _233.start, 'call', _234 => _234()]);
10392
- }
10393
- if (options2.flush) {
10394
- flushNowOrSoon();
10943
+ _optionalChain([stopwatch, 'optionalAccess', _248 => _248.start, 'call', _249 => _249()]);
10395
10944
  }
10396
10945
  }
10397
10946
  function startLoadingStorage() {
10398
10947
  if (_getStorage$ === null) {
10399
- refreshStorage({ flush: true });
10948
+ refreshStorage();
10949
+ flushNowOrSoon();
10400
10950
  _getStorage$ = new Promise((resolve) => {
10401
10951
  _resolveStoragePromise = resolve;
10402
10952
  });
@@ -10404,7 +10954,7 @@ function createRoom(options, config) {
10404
10954
  }
10405
10955
  return _getStorage$;
10406
10956
  }
10407
- function getStorageSnapshot() {
10957
+ function getStorageOrNull() {
10408
10958
  const root = context.root;
10409
10959
  if (root !== void 0) {
10410
10960
  return root;
@@ -10444,10 +10994,10 @@ function createRoom(options, config) {
10444
10994
  const message = {
10445
10995
  type: ClientMsgCode.FETCH_FEEDS,
10446
10996
  requestId,
10447
- cursor: _optionalChain([options2, 'optionalAccess', _235 => _235.cursor]),
10448
- since: _optionalChain([options2, 'optionalAccess', _236 => _236.since]),
10449
- limit: _optionalChain([options2, 'optionalAccess', _237 => _237.limit]),
10450
- metadata: _optionalChain([options2, 'optionalAccess', _238 => _238.metadata])
10997
+ cursor: _optionalChain([options2, 'optionalAccess', _250 => _250.cursor]),
10998
+ since: _optionalChain([options2, 'optionalAccess', _251 => _251.since]),
10999
+ limit: _optionalChain([options2, 'optionalAccess', _252 => _252.limit]),
11000
+ metadata: _optionalChain([options2, 'optionalAccess', _253 => _253.metadata])
10451
11001
  };
10452
11002
  context.buffer.messages.push(message);
10453
11003
  flushNowOrSoon();
@@ -10467,9 +11017,9 @@ function createRoom(options, config) {
10467
11017
  type: ClientMsgCode.FETCH_FEED_MESSAGES,
10468
11018
  requestId,
10469
11019
  feedId,
10470
- cursor: _optionalChain([options2, 'optionalAccess', _239 => _239.cursor]),
10471
- since: _optionalChain([options2, 'optionalAccess', _240 => _240.since]),
10472
- limit: _optionalChain([options2, 'optionalAccess', _241 => _241.limit])
11020
+ cursor: _optionalChain([options2, 'optionalAccess', _254 => _254.cursor]),
11021
+ since: _optionalChain([options2, 'optionalAccess', _255 => _255.since]),
11022
+ limit: _optionalChain([options2, 'optionalAccess', _256 => _256.limit])
10473
11023
  };
10474
11024
  context.buffer.messages.push(message);
10475
11025
  flushNowOrSoon();
@@ -10488,8 +11038,8 @@ function createRoom(options, config) {
10488
11038
  type: ClientMsgCode.ADD_FEED,
10489
11039
  requestId,
10490
11040
  feedId,
10491
- metadata: _optionalChain([options2, 'optionalAccess', _242 => _242.metadata]),
10492
- createdAt: _optionalChain([options2, 'optionalAccess', _243 => _243.createdAt])
11041
+ metadata: _optionalChain([options2, 'optionalAccess', _257 => _257.metadata]),
11042
+ createdAt: _optionalChain([options2, 'optionalAccess', _258 => _258.createdAt])
10493
11043
  };
10494
11044
  context.buffer.messages.push(message);
10495
11045
  flushNowOrSoon();
@@ -10523,15 +11073,15 @@ function createRoom(options, config) {
10523
11073
  function addFeedMessage(feedId, data, options2) {
10524
11074
  const requestId = nanoid();
10525
11075
  const promise = registerFeedMutation(requestId, "add-message", feedId, {
10526
- expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _244 => _244.id])
11076
+ expectedClientMessageId: _optionalChain([options2, 'optionalAccess', _259 => _259.id])
10527
11077
  });
10528
11078
  const message = {
10529
11079
  type: ClientMsgCode.ADD_FEED_MESSAGE,
10530
11080
  requestId,
10531
11081
  feedId,
10532
11082
  data,
10533
- id: _optionalChain([options2, 'optionalAccess', _245 => _245.id]),
10534
- createdAt: _optionalChain([options2, 'optionalAccess', _246 => _246.createdAt])
11083
+ id: _optionalChain([options2, 'optionalAccess', _260 => _260.id]),
11084
+ createdAt: _optionalChain([options2, 'optionalAccess', _261 => _261.createdAt])
10535
11085
  };
10536
11086
  context.buffer.messages.push(message);
10537
11087
  flushNowOrSoon();
@@ -10548,7 +11098,7 @@ function createRoom(options, config) {
10548
11098
  feedId,
10549
11099
  messageId,
10550
11100
  data,
10551
- updatedAt: _optionalChain([options2, 'optionalAccess', _247 => _247.updatedAt])
11101
+ updatedAt: _optionalChain([options2, 'optionalAccess', _262 => _262.updatedAt])
10552
11102
  };
10553
11103
  context.buffer.messages.push(message);
10554
11104
  flushNowOrSoon();
@@ -10718,7 +11268,7 @@ function createRoom(options, config) {
10718
11268
  }
10719
11269
  }
10720
11270
  function isStorageReady() {
10721
- return getStorageSnapshot() !== null;
11271
+ return getStorageOrNull() !== null;
10722
11272
  }
10723
11273
  async function waitUntilStorageReady() {
10724
11274
  while (!isStorageReady()) {
@@ -10755,8 +11305,8 @@ function createRoom(options, config) {
10755
11305
  async function getThreads(options2) {
10756
11306
  return httpClient.getThreads({
10757
11307
  roomId,
10758
- query: _optionalChain([options2, 'optionalAccess', _248 => _248.query]),
10759
- cursor: _optionalChain([options2, 'optionalAccess', _249 => _249.cursor])
11308
+ query: _optionalChain([options2, 'optionalAccess', _263 => _263.query]),
11309
+ cursor: _optionalChain([options2, 'optionalAccess', _264 => _264.cursor])
10760
11310
  });
10761
11311
  }
10762
11312
  async function getThread(threadId) {
@@ -10878,7 +11428,7 @@ function createRoom(options, config) {
10878
11428
  function getSubscriptionSettings(options2) {
10879
11429
  return httpClient.getSubscriptionSettings({
10880
11430
  roomId,
10881
- signal: _optionalChain([options2, 'optionalAccess', _250 => _250.signal])
11431
+ signal: _optionalChain([options2, 'optionalAccess', _265 => _265.signal])
10882
11432
  });
10883
11433
  }
10884
11434
  function updateSubscriptionSettings(settings) {
@@ -10900,7 +11450,7 @@ function createRoom(options, config) {
10900
11450
  {
10901
11451
  [kInternal]: {
10902
11452
  get presenceBuffer() {
10903
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _251 => _251.buffer, 'access', _252 => _252.presenceUpdates, 'optionalAccess', _253 => _253.data]), () => ( null)));
11453
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _266 => _266.buffer, 'access', _267 => _267.presenceUpdates, 'optionalAccess', _268 => _268.data]), () => ( null)));
10904
11454
  },
10905
11455
  // prettier-ignore
10906
11456
  get undoStack() {
@@ -10915,9 +11465,9 @@ function createRoom(options, config) {
10915
11465
  return context.yjsProvider;
10916
11466
  },
10917
11467
  setYjsProvider(newProvider) {
10918
- _optionalChain([context, 'access', _254 => _254.yjsProvider, 'optionalAccess', _255 => _255.off, 'call', _256 => _256("status", yjsStatusDidChange)]);
11468
+ _optionalChain([context, 'access', _269 => _269.yjsProvider, 'optionalAccess', _270 => _270.off, 'call', _271 => _271("status", yjsStatusDidChange)]);
10919
11469
  context.yjsProvider = newProvider;
10920
- _optionalChain([newProvider, 'optionalAccess', _257 => _257.on, 'call', _258 => _258("status", yjsStatusDidChange)]);
11470
+ _optionalChain([newProvider, 'optionalAccess', _272 => _272.on, 'call', _273 => _273("status", yjsStatusDidChange)]);
10921
11471
  context.yjsProviderDidChange.notify();
10922
11472
  },
10923
11473
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
@@ -10958,6 +11508,13 @@ function createRoom(options, config) {
10958
11508
  connect: () => managedSocket.connect(),
10959
11509
  reconnect: () => managedSocket.reconnect(),
10960
11510
  disconnect: () => managedSocket.disconnect(),
11511
+ _dump: () => {
11512
+ const n = context.pool.nodes.size;
11513
+ return `Room "${roomId}" (${n} node${n === 1 ? "" : "s"}):
11514
+ ${dumpPool(
11515
+ context.pool
11516
+ )}`;
11517
+ },
10961
11518
  destroy: () => {
10962
11519
  pendingFeedsRequests.forEach(
10963
11520
  (request) => request.reject(new Error("Room destroyed"))
@@ -10970,7 +11527,7 @@ function createRoom(options, config) {
10970
11527
  source.dispose();
10971
11528
  }
10972
11529
  eventHub.roomWillDestroy.notify();
10973
- _optionalChain([context, 'access', _259 => _259.yjsProvider, 'optionalAccess', _260 => _260.off, 'call', _261 => _261("status", yjsStatusDidChange)]);
11530
+ _optionalChain([context, 'access', _274 => _274.yjsProvider, 'optionalAccess', _275 => _275.off, 'call', _276 => _276("status", yjsStatusDidChange)]);
10974
11531
  syncSourceForStorage.destroy();
10975
11532
  syncSourceForYjs.destroy();
10976
11533
  uninstallBgTabSpy();
@@ -11003,7 +11560,9 @@ function createRoom(options, config) {
11003
11560
  updateFeedMessage,
11004
11561
  deleteFeedMessage,
11005
11562
  getStorage,
11006
- getStorageSnapshot,
11563
+ getStorageOrNull,
11564
+ getStorageSnapshot: getStorageOrNull,
11565
+ // Deprecated alias, will be removed in the future
11007
11566
  getStorageStatus,
11008
11567
  isPresenceReady,
11009
11568
  isStorageReady,
@@ -11130,7 +11689,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
11130
11689
  }
11131
11690
  if (isLiveNode(first)) {
11132
11691
  const node = first;
11133
- if (_optionalChain([options, 'optionalAccess', _262 => _262.isDeep])) {
11692
+ if (_optionalChain([options, 'optionalAccess', _277 => _277.isDeep])) {
11134
11693
  const storageCallback = second;
11135
11694
  return subscribeToLiveStructureDeeply(node, storageCallback);
11136
11695
  } else {
@@ -11149,7 +11708,11 @@ function isRoomEventName(value) {
11149
11708
  }
11150
11709
  function makeAuthDelegateForRoom(roomId, authManager) {
11151
11710
  return async () => {
11152
- return authManager.getAuthValue({ requestedScope: "room:read", roomId });
11711
+ return authManager.getAuthValue({
11712
+ roomId,
11713
+ resource: "room",
11714
+ access: "read"
11715
+ });
11153
11716
  };
11154
11717
  }
11155
11718
  function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
@@ -11198,7 +11761,7 @@ function getBaseUrl(baseUrl) {
11198
11761
  function isLocalhost(url2) {
11199
11762
  try {
11200
11763
  return new URL(url2).hostname === "localhost";
11201
- } catch (e12) {
11764
+ } catch (e11) {
11202
11765
  return false;
11203
11766
  }
11204
11767
  }
@@ -11216,12 +11779,11 @@ function createClient(options) {
11216
11779
  const authManager = createAuthManager(options, (token) => {
11217
11780
  currentUserId.set(() => token.uid);
11218
11781
  });
11219
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _263 => _263.polyfills, 'optionalAccess', _264 => _264.fetch]) || /* istanbul ignore next */
11220
- _optionalChain([globalThis, 'access', _265 => _265.fetch, 'optionalAccess', _266 => _266.bind, 'call', _267 => _267(globalThis)]);
11782
+ const fetchPolyfill = _optionalChain([clientOptions, 'access', _278 => _278.polyfills, 'optionalAccess', _279 => _279.fetch]) || /* istanbul ignore next */
11783
+ _optionalChain([globalThis, 'access', _280 => _280.fetch, 'optionalAccess', _281 => _281.bind, 'call', _282 => _282(globalThis)]);
11221
11784
  const httpClient = createApiClient({
11222
11785
  baseUrl,
11223
11786
  fetchPolyfill,
11224
- currentUserId,
11225
11787
  authManager
11226
11788
  });
11227
11789
  const roomsById = /* @__PURE__ */ new Map();
@@ -11235,11 +11797,12 @@ function createClient(options) {
11235
11797
  delegates: {
11236
11798
  createSocket: makeCreateSocketDelegateForAi(
11237
11799
  baseUrl,
11238
- _optionalChain([clientOptions, 'access', _268 => _268.polyfills, 'optionalAccess', _269 => _269.WebSocket])
11800
+ _optionalChain([clientOptions, 'access', _283 => _283.polyfills, 'optionalAccess', _284 => _284.WebSocket])
11239
11801
  ),
11240
11802
  authenticate: async () => {
11241
11803
  const resp = await authManager.getAuthValue({
11242
- requestedScope: "room:read"
11804
+ resource: "personal",
11805
+ access: "write"
11243
11806
  });
11244
11807
  if (resp.type === "public") {
11245
11808
  throw new StopRetrying(
@@ -11305,14 +11868,13 @@ function createClient(options) {
11305
11868
  createSocket: makeCreateSocketDelegateForRoom(
11306
11869
  roomId,
11307
11870
  baseUrl,
11308
- _optionalChain([clientOptions, 'access', _270 => _270.polyfills, 'optionalAccess', _271 => _271.WebSocket])
11871
+ _optionalChain([clientOptions, 'access', _285 => _285.polyfills, 'optionalAccess', _286 => _286.WebSocket])
11309
11872
  ),
11310
11873
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
11311
11874
  })),
11312
11875
  enableDebugLogging: clientOptions.enableDebugLogging,
11313
11876
  baseUrl,
11314
11877
  errorEventSource: liveblocksErrorSource,
11315
- unstable_streamData: !!clientOptions.unstable_streamData,
11316
11878
  roomHttpClient: httpClient,
11317
11879
  createSyncSource,
11318
11880
  badgeLocation: _nullishCoalesce(clientOptions.badgeLocation, () => ( "bottom-right"))
@@ -11328,7 +11890,7 @@ function createClient(options) {
11328
11890
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
11329
11891
  if (shouldConnect) {
11330
11892
  if (typeof atob === "undefined") {
11331
- if (_optionalChain([clientOptions, 'access', _272 => _272.polyfills, 'optionalAccess', _273 => _273.atob]) === void 0) {
11893
+ if (_optionalChain([clientOptions, 'access', _287 => _287.polyfills, 'optionalAccess', _288 => _288.atob]) === void 0) {
11332
11894
  throw new Error(
11333
11895
  "You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
11334
11896
  );
@@ -11340,7 +11902,7 @@ function createClient(options) {
11340
11902
  return leaseRoom(newRoomDetails);
11341
11903
  }
11342
11904
  function getRoom(roomId) {
11343
- const room = _optionalChain([roomsById, 'access', _274 => _274.get, 'call', _275 => _275(roomId), 'optionalAccess', _276 => _276.room]);
11905
+ const room = _optionalChain([roomsById, 'access', _289 => _289.get, 'call', _290 => _290(roomId), 'optionalAccess', _291 => _291.room]);
11344
11906
  return room ? room : null;
11345
11907
  }
11346
11908
  function logout() {
@@ -11356,7 +11918,7 @@ function createClient(options) {
11356
11918
  const batchedResolveUsers = new Batch(
11357
11919
  async (batchedUserIds) => {
11358
11920
  const userIds = batchedUserIds.flat();
11359
- const users = await _optionalChain([resolveUsers, 'optionalCall', _277 => _277({ userIds })]);
11921
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _292 => _292({ userIds })]);
11360
11922
  warnOnceIf(
11361
11923
  !resolveUsers,
11362
11924
  "Set the resolveUsers option in createClient to specify user info."
@@ -11373,7 +11935,7 @@ function createClient(options) {
11373
11935
  const batchedResolveRoomsInfo = new Batch(
11374
11936
  async (batchedRoomIds) => {
11375
11937
  const roomIds = batchedRoomIds.flat();
11376
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _278 => _278({ roomIds })]);
11938
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _293 => _293({ roomIds })]);
11377
11939
  warnOnceIf(
11378
11940
  !resolveRoomsInfo,
11379
11941
  "Set the resolveRoomsInfo option in createClient to specify room info."
@@ -11390,7 +11952,7 @@ function createClient(options) {
11390
11952
  const batchedResolveGroupsInfo = new Batch(
11391
11953
  async (batchedGroupIds) => {
11392
11954
  const groupIds = batchedGroupIds.flat();
11393
- const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _279 => _279({ groupIds })]);
11955
+ const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _294 => _294({ groupIds })]);
11394
11956
  warnOnceIf(
11395
11957
  !resolveGroupsInfo,
11396
11958
  "Set the resolveGroupsInfo option in createClient to specify group info."
@@ -11449,7 +12011,7 @@ function createClient(options) {
11449
12011
  }
11450
12012
  };
11451
12013
  const win = typeof window !== "undefined" ? window : void 0;
11452
- _optionalChain([win, 'optionalAccess', _280 => _280.addEventListener, 'call', _281 => _281("beforeunload", maybePreventClose)]);
12014
+ _optionalChain([win, 'optionalAccess', _295 => _295.addEventListener, 'call', _296 => _296("beforeunload", maybePreventClose)]);
11453
12015
  }
11454
12016
  async function getNotificationSettings(options2) {
11455
12017
  const plainSettings = await httpClient.getNotificationSettings(options2);
@@ -11465,6 +12027,7 @@ function createClient(options) {
11465
12027
  {
11466
12028
  enterRoom,
11467
12029
  getRoom,
12030
+ _dump: () => Array.from(roomsById.values(), ({ room }) => room._dump()).join("\n\n"),
11468
12031
  logout,
11469
12032
  // Public inbox notifications API
11470
12033
  getInboxNotifications: httpClient.getInboxNotifications,
@@ -11576,7 +12139,7 @@ var commentBodyElementsTypes = {
11576
12139
  mention: "inline"
11577
12140
  };
11578
12141
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
11579
- if (!body || !_optionalChain([body, 'optionalAccess', _282 => _282.content])) {
12142
+ if (!body || !_optionalChain([body, 'optionalAccess', _297 => _297.content])) {
11580
12143
  return;
11581
12144
  }
11582
12145
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -11586,13 +12149,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
11586
12149
  for (const block of body.content) {
11587
12150
  if (type === "all" || type === "block") {
11588
12151
  if (guard(block)) {
11589
- _optionalChain([visitor, 'optionalCall', _283 => _283(block)]);
12152
+ _optionalChain([visitor, 'optionalCall', _298 => _298(block)]);
11590
12153
  }
11591
12154
  }
11592
12155
  if (type === "all" || type === "inline") {
11593
12156
  for (const inline of block.children) {
11594
12157
  if (guard(inline)) {
11595
- _optionalChain([visitor, 'optionalCall', _284 => _284(inline)]);
12158
+ _optionalChain([visitor, 'optionalCall', _299 => _299(inline)]);
11596
12159
  }
11597
12160
  }
11598
12161
  }
@@ -11762,7 +12325,7 @@ var stringifyCommentBodyPlainElements = {
11762
12325
  text: ({ element }) => element.text,
11763
12326
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
11764
12327
  mention: ({ element, user, group }) => {
11765
- return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _285 => _285.name]), () => ( _optionalChain([group, 'optionalAccess', _286 => _286.name]))), () => ( element.id))}`;
12328
+ return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _300 => _300.name]), () => ( _optionalChain([group, 'optionalAccess', _301 => _301.name]))), () => ( element.id))}`;
11766
12329
  }
11767
12330
  };
11768
12331
  var stringifyCommentBodyHtmlElements = {
@@ -11792,7 +12355,7 @@ var stringifyCommentBodyHtmlElements = {
11792
12355
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
11793
12356
  },
11794
12357
  mention: ({ element, user, group }) => {
11795
- return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _287 => _287.name]) ? html`${_optionalChain([user, 'optionalAccess', _288 => _288.name])}` : _optionalChain([group, 'optionalAccess', _289 => _289.name]) ? html`${_optionalChain([group, 'optionalAccess', _290 => _290.name])}` : element.id}</span>`;
12358
+ return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _302 => _302.name]) ? html`${_optionalChain([user, 'optionalAccess', _303 => _303.name])}` : _optionalChain([group, 'optionalAccess', _304 => _304.name]) ? html`${_optionalChain([group, 'optionalAccess', _305 => _305.name])}` : element.id}</span>`;
11796
12359
  }
11797
12360
  };
11798
12361
  var stringifyCommentBodyMarkdownElements = {
@@ -11822,20 +12385,20 @@ var stringifyCommentBodyMarkdownElements = {
11822
12385
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
11823
12386
  },
11824
12387
  mention: ({ element, user, group }) => {
11825
- return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _291 => _291.name]), () => ( _optionalChain([group, 'optionalAccess', _292 => _292.name]))), () => ( element.id))}`;
12388
+ return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _306 => _306.name]), () => ( _optionalChain([group, 'optionalAccess', _307 => _307.name]))), () => ( element.id))}`;
11826
12389
  }
11827
12390
  };
11828
12391
  async function stringifyCommentBody(body, options) {
11829
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _293 => _293.format]), () => ( "plain"));
11830
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _294 => _294.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
12392
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _308 => _308.format]), () => ( "plain"));
12393
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _309 => _309.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
11831
12394
  const elements = {
11832
12395
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
11833
- ..._optionalChain([options, 'optionalAccess', _295 => _295.elements])
12396
+ ..._optionalChain([options, 'optionalAccess', _310 => _310.elements])
11834
12397
  };
11835
12398
  const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
11836
12399
  body,
11837
- _optionalChain([options, 'optionalAccess', _296 => _296.resolveUsers]),
11838
- _optionalChain([options, 'optionalAccess', _297 => _297.resolveGroupsInfo])
12400
+ _optionalChain([options, 'optionalAccess', _311 => _311.resolveUsers]),
12401
+ _optionalChain([options, 'optionalAccess', _312 => _312.resolveGroupsInfo])
11839
12402
  );
11840
12403
  const blocks = body.content.flatMap((block, blockIndex) => {
11841
12404
  switch (block.type) {
@@ -11970,9 +12533,9 @@ function makePoller(callback, intervalMs, options) {
11970
12533
  const startTime = performance.now();
11971
12534
  const doc = typeof document !== "undefined" ? document : void 0;
11972
12535
  const win = typeof window !== "undefined" ? window : void 0;
11973
- const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _298 => _298.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
12536
+ const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _313 => _313.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
11974
12537
  const context = {
11975
- inForeground: _optionalChain([doc, 'optionalAccess', _299 => _299.visibilityState]) !== "hidden",
12538
+ inForeground: _optionalChain([doc, 'optionalAccess', _314 => _314.visibilityState]) !== "hidden",
11976
12539
  lastSuccessfulPollAt: startTime,
11977
12540
  count: 0,
11978
12541
  backoff: 0
@@ -12053,11 +12616,11 @@ function makePoller(callback, intervalMs, options) {
12053
12616
  pollNowIfStale();
12054
12617
  }
12055
12618
  function onVisibilityChange() {
12056
- setInForeground(_optionalChain([doc, 'optionalAccess', _300 => _300.visibilityState]) !== "hidden");
12619
+ setInForeground(_optionalChain([doc, 'optionalAccess', _315 => _315.visibilityState]) !== "hidden");
12057
12620
  }
12058
- _optionalChain([doc, 'optionalAccess', _301 => _301.addEventListener, 'call', _302 => _302("visibilitychange", onVisibilityChange)]);
12059
- _optionalChain([win, 'optionalAccess', _303 => _303.addEventListener, 'call', _304 => _304("online", onVisibilityChange)]);
12060
- _optionalChain([win, 'optionalAccess', _305 => _305.addEventListener, 'call', _306 => _306("focus", pollNowIfStale)]);
12621
+ _optionalChain([doc, 'optionalAccess', _316 => _316.addEventListener, 'call', _317 => _317("visibilitychange", onVisibilityChange)]);
12622
+ _optionalChain([win, 'optionalAccess', _318 => _318.addEventListener, 'call', _319 => _319("online", onVisibilityChange)]);
12623
+ _optionalChain([win, 'optionalAccess', _320 => _320.addEventListener, 'call', _321 => _321("focus", pollNowIfStale)]);
12061
12624
  fsm.start();
12062
12625
  return {
12063
12626
  inc,
@@ -12194,5 +12757,13 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
12194
12757
 
12195
12758
 
12196
12759
 
12197
- exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.Deque = Deque; exports.DerivedSignal = DerivedSignal; exports.FeedRequestErrorCode = FeedRequestErrorCode; exports.HttpError = HttpError; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveblocksError = LiveblocksError; exports.MENTION_CHARACTER = MENTION_CHARACTER; exports.MutableSignal = MutableSignal; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.checkBounds = checkBounds; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactNodesToNodeStream = compactNodesToNodeStream; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToGroupData = convertToGroupData; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToSubscriptionData = convertToSubscriptionData; exports.convertToThreadData = convertToThreadData; exports.convertToUserSubscriptionData = convertToUserSubscriptionData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createManagedPool = createManagedPool; exports.createNotificationSettings = createNotificationSettings; exports.createThreadId = createThreadId; exports.defineAiTool = defineAiTool; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.entries = entries; exports.errorIf = errorIf; exports.findLastIndex = findLastIndex; exports.freeze = freeze; exports.generateUrl = generateUrl; exports.getMentionsFromCommentBody = getMentionsFromCommentBody; exports.getSubscriptionKey = getSubscriptionKey; exports.html = html; exports.htmlSafe = htmlSafe; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isListStorageNode = isListStorageNode; exports.isLiveNode = isLiveNode; exports.isMapStorageNode = isMapStorageNode; exports.isNotificationChannelEnabled = isNotificationChannelEnabled; exports.isNumberOperator = isNumberOperator; exports.isObjectStorageNode = isObjectStorageNode; exports.isPlainObject = isPlainObject; exports.isRegisterStorageNode = isRegisterStorageNode; exports.isRootStorageNode = isRootStorageNode; exports.isStartsWithOperator = isStartsWithOperator; exports.isUrl = isUrl; exports.kInternal = kInternal; exports.keys = keys; exports.makeAbortController = makeAbortController; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.nanoid = nanoid; exports.nn = nn; exports.nodeStreamToCompactNodes = nodeStreamToCompactNodes; exports.objectToQuery = objectToQuery; exports.patchNotificationSettings = patchNotificationSettings; exports.raise = raise; exports.resolveMentionsInCommentBody = resolveMentionsInCommentBody; exports.sanitizeUrl = sanitizeUrl; exports.shallow = shallow; exports.shallow2 = shallow2; exports.stableStringify = stableStringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.wait = wait; exports.warnOnce = warnOnce; exports.warnOnceIf = warnOnceIf; exports.withTimeout = withTimeout;
12760
+
12761
+
12762
+
12763
+
12764
+
12765
+
12766
+
12767
+
12768
+ exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.DefaultMap = DefaultMap; exports.Deque = Deque; exports.DerivedSignal = DerivedSignal; exports.FeedRequestErrorCode = FeedRequestErrorCode; exports.HttpError = HttpError; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.LiveblocksError = LiveblocksError; exports.MENTION_CHARACTER = MENTION_CHARACTER; exports.MutableSignal = MutableSignal; exports.OpCode = OpCode; exports.Permission = Permission; exports.Promise_withResolvers = Promise_withResolvers; exports.ServerMsgCode = ServerMsgCode; exports.Signal = Signal; exports.SortedList = SortedList; exports.TextEditorType = TextEditorType; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.autoRetry = autoRetry; exports.b64decode = b64decode; exports.batch = batch; exports.checkBounds = checkBounds; exports.chunk = chunk; exports.cloneLson = cloneLson; exports.compactNodesToNodeStream = compactNodesToNodeStream; exports.compactObject = compactObject; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToGroupData = convertToGroupData; exports.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToSubscriptionData = convertToSubscriptionData; exports.convertToThreadData = convertToThreadData; exports.convertToUserSubscriptionData = convertToUserSubscriptionData; exports.createClient = createClient; exports.createCommentAttachmentId = createCommentAttachmentId; exports.createCommentId = createCommentId; exports.createInboxNotificationId = createInboxNotificationId; exports.createManagedPool = createManagedPool; exports.createNotificationSettings = createNotificationSettings; exports.createThreadId = createThreadId; exports.deepLiveify = deepLiveify; exports.defineAiTool = defineAiTool; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.entries = entries; exports.errorIf = errorIf; exports.findLastIndex = findLastIndex; exports.freeze = freeze; exports.generateUrl = generateUrl; exports.getMentionsFromCommentBody = getMentionsFromCommentBody; exports.getSubscriptionKey = getSubscriptionKey; exports.hasPermissionAccess = hasPermissionAccess; exports.html = html; exports.htmlSafe = htmlSafe; exports.isCommentBodyLink = isCommentBodyLink; exports.isCommentBodyMention = isCommentBodyMention; exports.isCommentBodyText = isCommentBodyText; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isListStorageNode = isListStorageNode; exports.isLiveNode = isLiveNode; exports.isMapStorageNode = isMapStorageNode; exports.isNotificationChannelEnabled = isNotificationChannelEnabled; exports.isNumberOperator = isNumberOperator; exports.isObjectStorageNode = isObjectStorageNode; exports.isPlainObject = isPlainObject; exports.isRegisterStorageNode = isRegisterStorageNode; exports.isRootStorageNode = isRootStorageNode; exports.isStartsWithOperator = isStartsWithOperator; exports.isUrl = isUrl; exports.kInternal = kInternal; exports.keys = keys; exports.makeAbortController = makeAbortController; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.mapValues = mapValues; exports.memoizeOnSuccess = memoizeOnSuccess; exports.mergeRoomPermissionScopes = mergeRoomPermissionScopes; exports.nanoid = nanoid; exports.nn = nn; exports.nodeStreamToCompactNodes = nodeStreamToCompactNodes; exports.normalizeRoomAccesses = normalizeRoomAccesses; exports.normalizeRoomPermissions = normalizeRoomPermissions; exports.normalizeUpdateRoomAccesses = normalizeUpdateRoomAccesses; exports.objectToQuery = objectToQuery; exports.patchNotificationSettings = patchNotificationSettings; exports.permissionMatrixFromScopes = permissionMatrixFromScopes; exports.raise = raise; exports.resolveMentionsInCommentBody = resolveMentionsInCommentBody; exports.sanitizeUrl = sanitizeUrl; exports.shallow = shallow; exports.shallow2 = shallow2; exports.stableStringify = stableStringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.url = url; exports.urljoin = urljoin; exports.validatePermissionsSet = validatePermissionsSet; exports.wait = wait; exports.warnOnce = warnOnce; exports.warnOnceIf = warnOnceIf; exports.withTimeout = withTimeout;
12198
12769
  //# sourceMappingURL=index.cjs.map