@liveblocks/core 3.20.0-exp6 → 3.20.0-perm2
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 +562 -986
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -140
- package/dist/index.d.ts +80 -140
- package/dist/index.js +492 -916
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
|
|
7
7
|
// src/version.ts
|
|
8
8
|
var PKG_NAME = "@liveblocks/core";
|
|
9
|
-
var PKG_VERSION = "3.20.0-
|
|
9
|
+
var PKG_VERSION = "3.20.0-perm2";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1570,7 +1570,6 @@ function isUrl(string) {
|
|
|
1570
1570
|
function createApiClient({
|
|
1571
1571
|
baseUrl,
|
|
1572
1572
|
authManager,
|
|
1573
|
-
currentUserId,
|
|
1574
1573
|
fetchPolyfill
|
|
1575
1574
|
}) {
|
|
1576
1575
|
const httpClient = new HttpClient(baseUrl, fetchPolyfill);
|
|
@@ -1578,8 +1577,9 @@ function createApiClient({
|
|
|
1578
1577
|
const result = await httpClient.get(
|
|
1579
1578
|
url`/v2/c/rooms/${options.roomId}/threads/delta`,
|
|
1580
1579
|
await authManager.getAuthValue({
|
|
1581
|
-
|
|
1582
|
-
|
|
1580
|
+
roomId: options.roomId,
|
|
1581
|
+
resource: "comments",
|
|
1582
|
+
access: "read"
|
|
1583
1583
|
}),
|
|
1584
1584
|
{
|
|
1585
1585
|
since: options.since.toISOString()
|
|
@@ -1617,8 +1617,9 @@ function createApiClient({
|
|
|
1617
1617
|
const result = await httpClient.get(
|
|
1618
1618
|
url`/v2/c/rooms/${options.roomId}/threads`,
|
|
1619
1619
|
await authManager.getAuthValue({
|
|
1620
|
-
|
|
1621
|
-
|
|
1620
|
+
roomId: options.roomId,
|
|
1621
|
+
resource: "comments",
|
|
1622
|
+
access: "read"
|
|
1622
1623
|
}),
|
|
1623
1624
|
{
|
|
1624
1625
|
cursor: options.cursor,
|
|
@@ -1662,8 +1663,9 @@ function createApiClient({
|
|
|
1662
1663
|
const result = await httpClient.get(
|
|
1663
1664
|
url`/v2/c/rooms/${options.roomId}/threads/comments/search`,
|
|
1664
1665
|
await authManager.getAuthValue({
|
|
1665
|
-
|
|
1666
|
-
|
|
1666
|
+
roomId: options.roomId,
|
|
1667
|
+
resource: "comments",
|
|
1668
|
+
access: "read"
|
|
1667
1669
|
}),
|
|
1668
1670
|
{
|
|
1669
1671
|
text: options.query.text,
|
|
@@ -1684,8 +1686,9 @@ function createApiClient({
|
|
|
1684
1686
|
const thread = await httpClient.post(
|
|
1685
1687
|
url`/v2/c/rooms/${options.roomId}/threads`,
|
|
1686
1688
|
await authManager.getAuthValue({
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
+
roomId: options.roomId,
|
|
1690
|
+
resource: "comments",
|
|
1691
|
+
access: "write"
|
|
1689
1692
|
}),
|
|
1690
1693
|
{
|
|
1691
1694
|
id: threadId,
|
|
@@ -1704,8 +1707,9 @@ function createApiClient({
|
|
|
1704
1707
|
await httpClient.delete(
|
|
1705
1708
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}`,
|
|
1706
1709
|
await authManager.getAuthValue({
|
|
1707
|
-
|
|
1708
|
-
|
|
1710
|
+
roomId: options.roomId,
|
|
1711
|
+
resource: "comments",
|
|
1712
|
+
access: "write"
|
|
1709
1713
|
})
|
|
1710
1714
|
);
|
|
1711
1715
|
}
|
|
@@ -1713,8 +1717,9 @@ function createApiClient({
|
|
|
1713
1717
|
const response = await httpClient.rawGet(
|
|
1714
1718
|
url`/v2/c/rooms/${options.roomId}/thread-with-notification/${options.threadId}`,
|
|
1715
1719
|
await authManager.getAuthValue({
|
|
1716
|
-
|
|
1717
|
-
|
|
1720
|
+
roomId: options.roomId,
|
|
1721
|
+
resource: "comments",
|
|
1722
|
+
access: "read"
|
|
1718
1723
|
})
|
|
1719
1724
|
);
|
|
1720
1725
|
if (response.ok) {
|
|
@@ -1740,8 +1745,9 @@ function createApiClient({
|
|
|
1740
1745
|
return await httpClient.post(
|
|
1741
1746
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/metadata`,
|
|
1742
1747
|
await authManager.getAuthValue({
|
|
1743
|
-
|
|
1744
|
-
|
|
1748
|
+
roomId: options.roomId,
|
|
1749
|
+
resource: "comments",
|
|
1750
|
+
access: "write"
|
|
1745
1751
|
}),
|
|
1746
1752
|
options.metadata
|
|
1747
1753
|
);
|
|
@@ -1750,8 +1756,9 @@ function createApiClient({
|
|
|
1750
1756
|
return await httpClient.post(
|
|
1751
1757
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/metadata`,
|
|
1752
1758
|
await authManager.getAuthValue({
|
|
1753
|
-
|
|
1754
|
-
|
|
1759
|
+
roomId: options.roomId,
|
|
1760
|
+
resource: "comments",
|
|
1761
|
+
access: "write"
|
|
1755
1762
|
}),
|
|
1756
1763
|
options.metadata
|
|
1757
1764
|
);
|
|
@@ -1761,8 +1768,9 @@ function createApiClient({
|
|
|
1761
1768
|
const comment = await httpClient.post(
|
|
1762
1769
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments`,
|
|
1763
1770
|
await authManager.getAuthValue({
|
|
1764
|
-
|
|
1765
|
-
|
|
1771
|
+
roomId: options.roomId,
|
|
1772
|
+
resource: "comments",
|
|
1773
|
+
access: "write"
|
|
1766
1774
|
}),
|
|
1767
1775
|
{
|
|
1768
1776
|
id: commentId,
|
|
@@ -1777,8 +1785,9 @@ function createApiClient({
|
|
|
1777
1785
|
const comment = await httpClient.post(
|
|
1778
1786
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}`,
|
|
1779
1787
|
await authManager.getAuthValue({
|
|
1780
|
-
|
|
1781
|
-
|
|
1788
|
+
roomId: options.roomId,
|
|
1789
|
+
resource: "comments",
|
|
1790
|
+
access: "write"
|
|
1782
1791
|
}),
|
|
1783
1792
|
{
|
|
1784
1793
|
body: options.body,
|
|
@@ -1792,8 +1801,9 @@ function createApiClient({
|
|
|
1792
1801
|
await httpClient.delete(
|
|
1793
1802
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}`,
|
|
1794
1803
|
await authManager.getAuthValue({
|
|
1795
|
-
|
|
1796
|
-
|
|
1804
|
+
roomId: options.roomId,
|
|
1805
|
+
resource: "comments",
|
|
1806
|
+
access: "write"
|
|
1797
1807
|
})
|
|
1798
1808
|
);
|
|
1799
1809
|
}
|
|
@@ -1801,8 +1811,9 @@ function createApiClient({
|
|
|
1801
1811
|
const reaction = await httpClient.post(
|
|
1802
1812
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/reactions`,
|
|
1803
1813
|
await authManager.getAuthValue({
|
|
1804
|
-
|
|
1805
|
-
|
|
1814
|
+
roomId: options.roomId,
|
|
1815
|
+
resource: "comments",
|
|
1816
|
+
access: "write"
|
|
1806
1817
|
}),
|
|
1807
1818
|
{ emoji: options.emoji }
|
|
1808
1819
|
);
|
|
@@ -1812,8 +1823,9 @@ function createApiClient({
|
|
|
1812
1823
|
await httpClient.delete(
|
|
1813
1824
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/reactions/${options.emoji}`,
|
|
1814
1825
|
await authManager.getAuthValue({
|
|
1815
|
-
|
|
1816
|
-
|
|
1826
|
+
roomId: options.roomId,
|
|
1827
|
+
resource: "comments",
|
|
1828
|
+
access: "write"
|
|
1817
1829
|
})
|
|
1818
1830
|
);
|
|
1819
1831
|
}
|
|
@@ -1821,8 +1833,9 @@ function createApiClient({
|
|
|
1821
1833
|
await httpClient.post(
|
|
1822
1834
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/mark-as-resolved`,
|
|
1823
1835
|
await authManager.getAuthValue({
|
|
1824
|
-
|
|
1825
|
-
|
|
1836
|
+
roomId: options.roomId,
|
|
1837
|
+
resource: "comments",
|
|
1838
|
+
access: "write"
|
|
1826
1839
|
})
|
|
1827
1840
|
);
|
|
1828
1841
|
}
|
|
@@ -1830,8 +1843,9 @@ function createApiClient({
|
|
|
1830
1843
|
await httpClient.post(
|
|
1831
1844
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/mark-as-unresolved`,
|
|
1832
1845
|
await authManager.getAuthValue({
|
|
1833
|
-
|
|
1834
|
-
|
|
1846
|
+
roomId: options.roomId,
|
|
1847
|
+
resource: "comments",
|
|
1848
|
+
access: "write"
|
|
1835
1849
|
})
|
|
1836
1850
|
);
|
|
1837
1851
|
}
|
|
@@ -1839,8 +1853,9 @@ function createApiClient({
|
|
|
1839
1853
|
const subscription = await httpClient.post(
|
|
1840
1854
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/subscribe`,
|
|
1841
1855
|
await authManager.getAuthValue({
|
|
1842
|
-
|
|
1843
|
-
|
|
1856
|
+
roomId: options.roomId,
|
|
1857
|
+
resource: "comments",
|
|
1858
|
+
access: "read"
|
|
1844
1859
|
})
|
|
1845
1860
|
);
|
|
1846
1861
|
return convertToSubscriptionData(subscription);
|
|
@@ -1849,8 +1864,9 @@ function createApiClient({
|
|
|
1849
1864
|
await httpClient.post(
|
|
1850
1865
|
url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/unsubscribe`,
|
|
1851
1866
|
await authManager.getAuthValue({
|
|
1852
|
-
|
|
1853
|
-
|
|
1867
|
+
roomId: options.roomId,
|
|
1868
|
+
resource: "comments",
|
|
1869
|
+
access: "read"
|
|
1854
1870
|
})
|
|
1855
1871
|
);
|
|
1856
1872
|
}
|
|
@@ -1906,8 +1922,9 @@ function createApiClient({
|
|
|
1906
1922
|
async () => httpClient.putBlob(
|
|
1907
1923
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.name)}`,
|
|
1908
1924
|
await authManager.getAuthValue({
|
|
1909
|
-
|
|
1910
|
-
|
|
1925
|
+
roomId,
|
|
1926
|
+
resource: "comments",
|
|
1927
|
+
access: "write"
|
|
1911
1928
|
}),
|
|
1912
1929
|
attachment.file,
|
|
1913
1930
|
{ fileSize: attachment.size },
|
|
@@ -1924,8 +1941,9 @@ function createApiClient({
|
|
|
1924
1941
|
async () => httpClient.post(
|
|
1925
1942
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.name)}`,
|
|
1926
1943
|
await authManager.getAuthValue({
|
|
1927
|
-
|
|
1928
|
-
|
|
1944
|
+
roomId,
|
|
1945
|
+
resource: "comments",
|
|
1946
|
+
access: "write"
|
|
1929
1947
|
}),
|
|
1930
1948
|
void 0,
|
|
1931
1949
|
{ signal: abortSignal },
|
|
@@ -1950,8 +1968,9 @@ function createApiClient({
|
|
|
1950
1968
|
async () => httpClient.putBlob(
|
|
1951
1969
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${createMultiPartUpload.uploadId}/${String(partNumber)}`,
|
|
1952
1970
|
await authManager.getAuthValue({
|
|
1953
|
-
|
|
1954
|
-
|
|
1971
|
+
roomId,
|
|
1972
|
+
resource: "comments",
|
|
1973
|
+
access: "write"
|
|
1955
1974
|
}),
|
|
1956
1975
|
part,
|
|
1957
1976
|
void 0,
|
|
@@ -1974,8 +1993,9 @@ function createApiClient({
|
|
|
1974
1993
|
return httpClient.post(
|
|
1975
1994
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}/complete`,
|
|
1976
1995
|
await authManager.getAuthValue({
|
|
1977
|
-
|
|
1978
|
-
|
|
1996
|
+
roomId,
|
|
1997
|
+
resource: "comments",
|
|
1998
|
+
access: "write"
|
|
1979
1999
|
}),
|
|
1980
2000
|
{ parts: sortedUploadedParts },
|
|
1981
2001
|
{ signal: abortSignal }
|
|
@@ -1986,8 +2006,9 @@ function createApiClient({
|
|
|
1986
2006
|
await httpClient.rawDelete(
|
|
1987
2007
|
url`/v2/c/rooms/${roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
|
|
1988
2008
|
await authManager.getAuthValue({
|
|
1989
|
-
|
|
1990
|
-
|
|
2009
|
+
roomId,
|
|
2010
|
+
resource: "comments",
|
|
2011
|
+
access: "write"
|
|
1991
2012
|
})
|
|
1992
2013
|
);
|
|
1993
2014
|
} catch {
|
|
@@ -2004,8 +2025,9 @@ function createApiClient({
|
|
|
2004
2025
|
const { urls } = await httpClient.post(
|
|
2005
2026
|
url`/v2/c/rooms/${roomId}/attachments/presigned-urls`,
|
|
2006
2027
|
await authManager.getAuthValue({
|
|
2007
|
-
|
|
2008
|
-
|
|
2028
|
+
roomId,
|
|
2029
|
+
resource: "comments",
|
|
2030
|
+
access: "read"
|
|
2009
2031
|
}),
|
|
2010
2032
|
{ attachmentIds }
|
|
2011
2033
|
);
|
|
@@ -2024,109 +2046,13 @@ function createApiClient({
|
|
|
2024
2046
|
const batch2 = getOrCreateAttachmentUrlsStore(options.roomId).batch;
|
|
2025
2047
|
return batch2.get(options.attachmentId);
|
|
2026
2048
|
}
|
|
2027
|
-
async function uploadChatAttachment(options) {
|
|
2028
|
-
const { chatId, attachment, signal } = options;
|
|
2029
|
-
const userId = currentUserId.get();
|
|
2030
|
-
if (userId === void 0) {
|
|
2031
|
-
throw new Error("Attachment upload requires an authenticated user.");
|
|
2032
|
-
}
|
|
2033
|
-
const ATTACHMENT_PART_SIZE = 5 * 1024 * 1024;
|
|
2034
|
-
if (options.attachment.file.size <= ATTACHMENT_PART_SIZE) {
|
|
2035
|
-
await httpClient.putBlob(
|
|
2036
|
-
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.file.name)}`,
|
|
2037
|
-
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
2038
|
-
attachment.file,
|
|
2039
|
-
{ fileSize: attachment.file.size },
|
|
2040
|
-
{ signal }
|
|
2041
|
-
);
|
|
2042
|
-
} else {
|
|
2043
|
-
const multipartUpload = await httpClient.post(
|
|
2044
|
-
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.file.name)}`,
|
|
2045
|
-
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
2046
|
-
void 0,
|
|
2047
|
-
{ signal },
|
|
2048
|
-
{ fileSize: attachment.file.size }
|
|
2049
|
-
);
|
|
2050
|
-
try {
|
|
2051
|
-
const uploadedParts = [];
|
|
2052
|
-
const parts = [];
|
|
2053
|
-
let start = 0;
|
|
2054
|
-
while (start < attachment.file.size) {
|
|
2055
|
-
const end = Math.min(
|
|
2056
|
-
start + ATTACHMENT_PART_SIZE,
|
|
2057
|
-
attachment.file.size
|
|
2058
|
-
);
|
|
2059
|
-
parts.push({
|
|
2060
|
-
number: parts.length + 1,
|
|
2061
|
-
part: attachment.file.slice(start, end)
|
|
2062
|
-
});
|
|
2063
|
-
start = end;
|
|
2064
|
-
}
|
|
2065
|
-
uploadedParts.push(
|
|
2066
|
-
...await Promise.all(
|
|
2067
|
-
parts.map(async ({ number, part }) => {
|
|
2068
|
-
return await httpClient.putBlob(
|
|
2069
|
-
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}/${String(number)}`,
|
|
2070
|
-
await authManager.getAuthValue({
|
|
2071
|
-
requestedScope: "comments:read"
|
|
2072
|
-
}),
|
|
2073
|
-
part,
|
|
2074
|
-
void 0,
|
|
2075
|
-
{ signal }
|
|
2076
|
-
);
|
|
2077
|
-
})
|
|
2078
|
-
)
|
|
2079
|
-
);
|
|
2080
|
-
await httpClient.post(
|
|
2081
|
-
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}/complete`,
|
|
2082
|
-
await authManager.getAuthValue({ requestedScope: "comments:read" }),
|
|
2083
|
-
{ parts: uploadedParts.sort((a, b) => a.number - b.number) },
|
|
2084
|
-
{ signal }
|
|
2085
|
-
);
|
|
2086
|
-
} catch (err) {
|
|
2087
|
-
try {
|
|
2088
|
-
await httpClient.delete(
|
|
2089
|
-
url`/v2/c/chats/${chatId}/attachments/${attachment.id}/multipart/${multipartUpload.uploadId}`,
|
|
2090
|
-
await authManager.getAuthValue({ requestedScope: "comments:read" })
|
|
2091
|
-
);
|
|
2092
|
-
} catch {
|
|
2093
|
-
}
|
|
2094
|
-
throw err;
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
const attachmentUrlsBatchStoresByChat = new DefaultMap((chatId) => {
|
|
2099
|
-
const batch2 = new Batch(
|
|
2100
|
-
async (batchedAttachmentIds) => {
|
|
2101
|
-
const attachmentIds = batchedAttachmentIds.flat();
|
|
2102
|
-
const { urls } = await httpClient.post(
|
|
2103
|
-
url`/v2/c/chats/${chatId}/attachments/presigned-urls`,
|
|
2104
|
-
await authManager.getAuthValue({
|
|
2105
|
-
requestedScope: "comments:read"
|
|
2106
|
-
}),
|
|
2107
|
-
{ attachmentIds }
|
|
2108
|
-
);
|
|
2109
|
-
return urls.map(
|
|
2110
|
-
(url2) => url2 ?? new Error("There was an error while getting this attachment's URL")
|
|
2111
|
-
);
|
|
2112
|
-
},
|
|
2113
|
-
{ delay: 50 }
|
|
2114
|
-
);
|
|
2115
|
-
return createBatchStore(batch2);
|
|
2116
|
-
});
|
|
2117
|
-
function getOrCreateChatAttachmentUrlsStore(chatId) {
|
|
2118
|
-
return attachmentUrlsBatchStoresByChat.getOrCreate(chatId);
|
|
2119
|
-
}
|
|
2120
|
-
function getChatAttachmentUrl(options) {
|
|
2121
|
-
const batch2 = getOrCreateChatAttachmentUrlsStore(options.chatId).batch;
|
|
2122
|
-
return batch2.get(options.attachmentId);
|
|
2123
|
-
}
|
|
2124
2049
|
async function getSubscriptionSettings(options) {
|
|
2125
2050
|
return httpClient.get(
|
|
2126
2051
|
url`/v2/c/rooms/${options.roomId}/subscription-settings`,
|
|
2127
2052
|
await authManager.getAuthValue({
|
|
2128
|
-
|
|
2129
|
-
|
|
2053
|
+
roomId: options.roomId,
|
|
2054
|
+
resource: "comments",
|
|
2055
|
+
access: "read"
|
|
2130
2056
|
}),
|
|
2131
2057
|
void 0,
|
|
2132
2058
|
{
|
|
@@ -2138,8 +2064,9 @@ function createApiClient({
|
|
|
2138
2064
|
return httpClient.post(
|
|
2139
2065
|
url`/v2/c/rooms/${options.roomId}/subscription-settings`,
|
|
2140
2066
|
await authManager.getAuthValue({
|
|
2141
|
-
|
|
2142
|
-
|
|
2067
|
+
roomId: options.roomId,
|
|
2068
|
+
resource: "comments",
|
|
2069
|
+
access: "read"
|
|
2143
2070
|
}),
|
|
2144
2071
|
options.settings
|
|
2145
2072
|
);
|
|
@@ -2151,8 +2078,9 @@ function createApiClient({
|
|
|
2151
2078
|
await httpClient.post(
|
|
2152
2079
|
url`/v2/c/rooms/${roomId}/inbox-notifications/read`,
|
|
2153
2080
|
await authManager.getAuthValue({
|
|
2154
|
-
|
|
2155
|
-
|
|
2081
|
+
roomId,
|
|
2082
|
+
resource: "comments",
|
|
2083
|
+
access: "read"
|
|
2156
2084
|
}),
|
|
2157
2085
|
{ inboxNotificationIds }
|
|
2158
2086
|
);
|
|
@@ -2172,8 +2100,9 @@ function createApiClient({
|
|
|
2172
2100
|
await httpClient.rawPost(
|
|
2173
2101
|
url`/v2/c/rooms/${options.roomId}/text-mentions`,
|
|
2174
2102
|
await authManager.getAuthValue({
|
|
2175
|
-
|
|
2176
|
-
|
|
2103
|
+
roomId: options.roomId,
|
|
2104
|
+
resource: "storage",
|
|
2105
|
+
access: "write"
|
|
2177
2106
|
}),
|
|
2178
2107
|
{
|
|
2179
2108
|
userId: options.mention.kind === "user" ? options.mention.id : void 0,
|
|
@@ -2187,8 +2116,9 @@ function createApiClient({
|
|
|
2187
2116
|
await httpClient.rawDelete(
|
|
2188
2117
|
url`/v2/c/rooms/${options.roomId}/text-mentions/${options.mentionId}`,
|
|
2189
2118
|
await authManager.getAuthValue({
|
|
2190
|
-
|
|
2191
|
-
|
|
2119
|
+
roomId: options.roomId,
|
|
2120
|
+
resource: "storage",
|
|
2121
|
+
access: "write"
|
|
2192
2122
|
})
|
|
2193
2123
|
);
|
|
2194
2124
|
}
|
|
@@ -2196,8 +2126,9 @@ function createApiClient({
|
|
|
2196
2126
|
return httpClient.rawGet(
|
|
2197
2127
|
url`/v2/c/rooms/${options.roomId}/y-version/${options.versionId}`,
|
|
2198
2128
|
await authManager.getAuthValue({
|
|
2199
|
-
|
|
2200
|
-
|
|
2129
|
+
roomId: options.roomId,
|
|
2130
|
+
resource: "storage",
|
|
2131
|
+
access: "read"
|
|
2201
2132
|
})
|
|
2202
2133
|
);
|
|
2203
2134
|
}
|
|
@@ -2205,8 +2136,9 @@ function createApiClient({
|
|
|
2205
2136
|
await httpClient.rawPost(
|
|
2206
2137
|
url`/v2/c/rooms/${options.roomId}/version`,
|
|
2207
2138
|
await authManager.getAuthValue({
|
|
2208
|
-
|
|
2209
|
-
|
|
2139
|
+
roomId: options.roomId,
|
|
2140
|
+
resource: "storage",
|
|
2141
|
+
access: "write"
|
|
2210
2142
|
})
|
|
2211
2143
|
);
|
|
2212
2144
|
}
|
|
@@ -2214,8 +2146,9 @@ function createApiClient({
|
|
|
2214
2146
|
await httpClient.rawPost(
|
|
2215
2147
|
url`/v2/c/rooms/${options.roomId}/text-metadata`,
|
|
2216
2148
|
await authManager.getAuthValue({
|
|
2217
|
-
|
|
2218
|
-
|
|
2149
|
+
roomId: options.roomId,
|
|
2150
|
+
resource: "storage",
|
|
2151
|
+
access: "read"
|
|
2219
2152
|
}),
|
|
2220
2153
|
{
|
|
2221
2154
|
type: options.type,
|
|
@@ -2227,8 +2160,9 @@ function createApiClient({
|
|
|
2227
2160
|
const result = await httpClient.post(
|
|
2228
2161
|
url`/v2/c/rooms/${options.roomId}/ai/contextual-prompt`,
|
|
2229
2162
|
await authManager.getAuthValue({
|
|
2230
|
-
|
|
2231
|
-
|
|
2163
|
+
roomId: options.roomId,
|
|
2164
|
+
resource: "storage",
|
|
2165
|
+
access: "read"
|
|
2232
2166
|
}),
|
|
2233
2167
|
{
|
|
2234
2168
|
prompt: options.prompt,
|
|
@@ -2250,8 +2184,9 @@ function createApiClient({
|
|
|
2250
2184
|
const result = await httpClient.get(
|
|
2251
2185
|
url`/v2/c/rooms/${options.roomId}/versions`,
|
|
2252
2186
|
await authManager.getAuthValue({
|
|
2253
|
-
|
|
2254
|
-
|
|
2187
|
+
roomId: options.roomId,
|
|
2188
|
+
resource: "storage",
|
|
2189
|
+
access: "read"
|
|
2255
2190
|
})
|
|
2256
2191
|
);
|
|
2257
2192
|
return {
|
|
@@ -2268,8 +2203,9 @@ function createApiClient({
|
|
|
2268
2203
|
const result = await httpClient.get(
|
|
2269
2204
|
url`/v2/c/rooms/${options.roomId}/versions/delta`,
|
|
2270
2205
|
await authManager.getAuthValue({
|
|
2271
|
-
|
|
2272
|
-
|
|
2206
|
+
roomId: options.roomId,
|
|
2207
|
+
resource: "storage",
|
|
2208
|
+
access: "read"
|
|
2273
2209
|
}),
|
|
2274
2210
|
{ since: options.since.toISOString() },
|
|
2275
2211
|
{ signal: options.signal }
|
|
@@ -2288,8 +2224,9 @@ function createApiClient({
|
|
|
2288
2224
|
const result = await httpClient.rawGet(
|
|
2289
2225
|
url`/v2/c/rooms/${options.roomId}/storage`,
|
|
2290
2226
|
await authManager.getAuthValue({
|
|
2291
|
-
|
|
2292
|
-
|
|
2227
|
+
roomId: options.roomId,
|
|
2228
|
+
resource: "storage",
|
|
2229
|
+
access: "read"
|
|
2293
2230
|
})
|
|
2294
2231
|
);
|
|
2295
2232
|
return await result.json();
|
|
@@ -2302,7 +2239,7 @@ function createApiClient({
|
|
|
2302
2239
|
}
|
|
2303
2240
|
const json = await httpClient.get(
|
|
2304
2241
|
url`/v2/c/inbox-notifications`,
|
|
2305
|
-
await authManager.getAuthValue({
|
|
2242
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2306
2243
|
{
|
|
2307
2244
|
cursor: options?.cursor,
|
|
2308
2245
|
limit: PAGE_SIZE,
|
|
@@ -2328,7 +2265,7 @@ function createApiClient({
|
|
|
2328
2265
|
}
|
|
2329
2266
|
const json = await httpClient.get(
|
|
2330
2267
|
url`/v2/c/inbox-notifications/delta`,
|
|
2331
|
-
await authManager.getAuthValue({
|
|
2268
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2332
2269
|
{ since: options.since.toISOString(), query },
|
|
2333
2270
|
{ signal: options.signal }
|
|
2334
2271
|
);
|
|
@@ -2357,7 +2294,7 @@ function createApiClient({
|
|
|
2357
2294
|
}
|
|
2358
2295
|
const { count } = await httpClient.get(
|
|
2359
2296
|
url`/v2/c/inbox-notifications/count`,
|
|
2360
|
-
await authManager.getAuthValue({
|
|
2297
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2361
2298
|
{ query },
|
|
2362
2299
|
{ signal: options?.signal }
|
|
2363
2300
|
);
|
|
@@ -2366,7 +2303,7 @@ function createApiClient({
|
|
|
2366
2303
|
async function markAllInboxNotificationsAsRead() {
|
|
2367
2304
|
await httpClient.post(
|
|
2368
2305
|
url`/v2/c/inbox-notifications/read`,
|
|
2369
|
-
await authManager.getAuthValue({
|
|
2306
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2370
2307
|
{
|
|
2371
2308
|
inboxNotificationIds: "all"
|
|
2372
2309
|
}
|
|
@@ -2375,7 +2312,7 @@ function createApiClient({
|
|
|
2375
2312
|
async function markInboxNotificationsAsRead(inboxNotificationIds) {
|
|
2376
2313
|
await httpClient.post(
|
|
2377
2314
|
url`/v2/c/inbox-notifications/read`,
|
|
2378
|
-
await authManager.getAuthValue({
|
|
2315
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2379
2316
|
{
|
|
2380
2317
|
inboxNotificationIds
|
|
2381
2318
|
}
|
|
@@ -2395,19 +2332,19 @@ function createApiClient({
|
|
|
2395
2332
|
async function deleteAllInboxNotifications() {
|
|
2396
2333
|
await httpClient.delete(
|
|
2397
2334
|
url`/v2/c/inbox-notifications`,
|
|
2398
|
-
await authManager.getAuthValue({
|
|
2335
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" })
|
|
2399
2336
|
);
|
|
2400
2337
|
}
|
|
2401
2338
|
async function deleteInboxNotification(inboxNotificationId) {
|
|
2402
2339
|
await httpClient.delete(
|
|
2403
2340
|
url`/v2/c/inbox-notifications/${inboxNotificationId}`,
|
|
2404
|
-
await authManager.getAuthValue({
|
|
2341
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" })
|
|
2405
2342
|
);
|
|
2406
2343
|
}
|
|
2407
2344
|
async function getNotificationSettings(options) {
|
|
2408
2345
|
return httpClient.get(
|
|
2409
2346
|
url`/v2/c/notification-settings`,
|
|
2410
|
-
await authManager.getAuthValue({
|
|
2347
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2411
2348
|
void 0,
|
|
2412
2349
|
{ signal: options?.signal }
|
|
2413
2350
|
);
|
|
@@ -2415,7 +2352,7 @@ function createApiClient({
|
|
|
2415
2352
|
async function updateNotificationSettings(settings) {
|
|
2416
2353
|
return httpClient.post(
|
|
2417
2354
|
url`/v2/c/notification-settings`,
|
|
2418
|
-
await authManager.getAuthValue({
|
|
2355
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2419
2356
|
settings
|
|
2420
2357
|
);
|
|
2421
2358
|
}
|
|
@@ -2427,7 +2364,7 @@ function createApiClient({
|
|
|
2427
2364
|
const PAGE_SIZE = 50;
|
|
2428
2365
|
const json = await httpClient.get(
|
|
2429
2366
|
url`/v2/c/threads`,
|
|
2430
|
-
await authManager.getAuthValue({
|
|
2367
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2431
2368
|
{
|
|
2432
2369
|
cursor: options?.cursor,
|
|
2433
2370
|
query,
|
|
@@ -2448,7 +2385,7 @@ function createApiClient({
|
|
|
2448
2385
|
async function getUserThreadsSince_experimental(options) {
|
|
2449
2386
|
const json = await httpClient.get(
|
|
2450
2387
|
url`/v2/c/threads/delta`,
|
|
2451
|
-
await authManager.getAuthValue({
|
|
2388
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2452
2389
|
{ since: options.since.toISOString() },
|
|
2453
2390
|
{ signal: options.signal }
|
|
2454
2391
|
);
|
|
@@ -2477,7 +2414,8 @@ function createApiClient({
|
|
|
2477
2414
|
const { groups: plainGroups } = await httpClient.post(
|
|
2478
2415
|
url`/v2/c/groups/find`,
|
|
2479
2416
|
await authManager.getAuthValue({
|
|
2480
|
-
|
|
2417
|
+
resource: "personal",
|
|
2418
|
+
access: "write"
|
|
2481
2419
|
}),
|
|
2482
2420
|
{ groupIds }
|
|
2483
2421
|
);
|
|
@@ -2496,7 +2434,7 @@ function createApiClient({
|
|
|
2496
2434
|
async function getUrlMetadata(_url) {
|
|
2497
2435
|
const { metadata } = await httpClient.get(
|
|
2498
2436
|
url`/v2/c/urls/metadata`,
|
|
2499
|
-
await authManager.getAuthValue({
|
|
2437
|
+
await authManager.getAuthValue({ resource: "personal", access: "write" }),
|
|
2500
2438
|
{ url: _url }
|
|
2501
2439
|
);
|
|
2502
2440
|
return metadata;
|
|
@@ -2536,10 +2474,6 @@ function createApiClient({
|
|
|
2536
2474
|
getAttachmentUrl,
|
|
2537
2475
|
uploadAttachment,
|
|
2538
2476
|
getOrCreateAttachmentUrlsStore,
|
|
2539
|
-
// User attachments
|
|
2540
|
-
uploadChatAttachment,
|
|
2541
|
-
getOrCreateChatAttachmentUrlsStore,
|
|
2542
|
-
getChatAttachmentUrl,
|
|
2543
2477
|
// Room storage
|
|
2544
2478
|
streamStorage,
|
|
2545
2479
|
// Notifications
|
|
@@ -5233,22 +5167,291 @@ function createReceivingToolInvocation(invocationId, name, partialArgsText = "")
|
|
|
5233
5167
|
};
|
|
5234
5168
|
}
|
|
5235
5169
|
|
|
5236
|
-
// src/protocol/
|
|
5237
|
-
var Permission =
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5170
|
+
// src/protocol/Permissions.ts
|
|
5171
|
+
var Permission = {
|
|
5172
|
+
/**
|
|
5173
|
+
* Default permission for a room
|
|
5174
|
+
*/
|
|
5175
|
+
RoomWrite: "room:write",
|
|
5176
|
+
RoomRead: "room:read",
|
|
5177
|
+
/**
|
|
5178
|
+
* Presence (LiveRoom Websocket access)
|
|
5179
|
+
*/
|
|
5180
|
+
RoomPresenceRead: "room:presence:read",
|
|
5181
|
+
RoomPresenceNone: "room:presence:none",
|
|
5182
|
+
/**
|
|
5183
|
+
* Storage
|
|
5184
|
+
*/
|
|
5185
|
+
RoomStorageRead: "room:storage:read",
|
|
5186
|
+
RoomStorageWrite: "room:storage:write",
|
|
5187
|
+
RoomStorageNone: "room:storage:none",
|
|
5188
|
+
/**
|
|
5189
|
+
* Comments
|
|
5190
|
+
*/
|
|
5191
|
+
RoomCommentsWrite: "room:comments:write",
|
|
5192
|
+
RoomCommentsRead: "room:comments:read",
|
|
5193
|
+
RoomCommentsNone: "room:comments:none",
|
|
5194
|
+
/**
|
|
5195
|
+
* Feeds
|
|
5196
|
+
*/
|
|
5197
|
+
RoomFeedsRead: "room:feeds:read",
|
|
5198
|
+
RoomFeedsWrite: "room:feeds:write",
|
|
5199
|
+
RoomFeedsNone: "room:feeds:none",
|
|
5200
|
+
/**
|
|
5201
|
+
* Legacy
|
|
5202
|
+
*/
|
|
5203
|
+
LegacyRoomPresenceWrite: "room:presence:write",
|
|
5204
|
+
LegacyCommentsWrite: "comments:write",
|
|
5205
|
+
LegacyCommentsRead: "comments:read",
|
|
5206
|
+
LegacyFeedsWrite: "feeds:write"
|
|
5207
|
+
};
|
|
5208
|
+
var ACCESS_LEVELS = [
|
|
5209
|
+
"none",
|
|
5210
|
+
"read",
|
|
5211
|
+
"write"
|
|
5212
|
+
];
|
|
5213
|
+
var ACCESS_RANKS = {
|
|
5214
|
+
none: 0,
|
|
5215
|
+
read: 1,
|
|
5216
|
+
write: 2
|
|
5217
|
+
};
|
|
5218
|
+
var NO_PERMISSION_CAPABILITIES = {
|
|
5219
|
+
creation: "none",
|
|
5220
|
+
presence: "none",
|
|
5221
|
+
storage: "none",
|
|
5222
|
+
comments: "none",
|
|
5223
|
+
feeds: "none",
|
|
5224
|
+
personal: "write"
|
|
5225
|
+
};
|
|
5226
|
+
var RESOURCE_PERMISSIONS = {
|
|
5227
|
+
creation: {
|
|
5228
|
+
read: [Permission.RoomRead],
|
|
5229
|
+
write: [Permission.RoomWrite]
|
|
5230
|
+
},
|
|
5231
|
+
personal: {
|
|
5232
|
+
write: []
|
|
5233
|
+
},
|
|
5234
|
+
presence: {
|
|
5235
|
+
write: [Permission.LegacyRoomPresenceWrite],
|
|
5236
|
+
read: [Permission.RoomPresenceRead],
|
|
5237
|
+
none: [Permission.RoomPresenceNone]
|
|
5238
|
+
},
|
|
5239
|
+
storage: {
|
|
5240
|
+
write: [Permission.RoomStorageWrite],
|
|
5241
|
+
read: [Permission.RoomStorageRead],
|
|
5242
|
+
none: [Permission.RoomStorageNone]
|
|
5243
|
+
},
|
|
5244
|
+
comments: {
|
|
5245
|
+
write: [Permission.RoomCommentsWrite, Permission.LegacyCommentsWrite],
|
|
5246
|
+
read: [Permission.RoomCommentsRead, Permission.LegacyCommentsRead],
|
|
5247
|
+
none: [Permission.RoomCommentsNone]
|
|
5248
|
+
},
|
|
5249
|
+
feeds: {
|
|
5250
|
+
write: [Permission.RoomFeedsWrite, Permission.LegacyFeedsWrite],
|
|
5251
|
+
read: [Permission.RoomFeedsRead],
|
|
5252
|
+
none: [Permission.RoomFeedsNone]
|
|
5253
|
+
}
|
|
5254
|
+
};
|
|
5255
|
+
var DEFAULT_PERMISSION_RESOURCE = "creation";
|
|
5256
|
+
var ROOM_PERMISSION_RESOURCES = [
|
|
5257
|
+
"presence",
|
|
5258
|
+
"storage",
|
|
5259
|
+
"comments",
|
|
5260
|
+
"feeds"
|
|
5261
|
+
];
|
|
5262
|
+
function resolveResourceAccess(scopes, resource) {
|
|
5263
|
+
const permissions = RESOURCE_PERMISSIONS[resource];
|
|
5264
|
+
let resourceAccess;
|
|
5265
|
+
for (const access of ACCESS_LEVELS) {
|
|
5266
|
+
const scopedPermissions = permissions[access];
|
|
5267
|
+
if (scopedPermissions !== void 0 && scopedPermissions.some((permission) => scopes.includes(permission))) {
|
|
5268
|
+
resourceAccess = access;
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
return resourceAccess;
|
|
5272
|
+
}
|
|
5273
|
+
function resolveFullPermissionCapabilities(resolved) {
|
|
5274
|
+
if (!resolved.hasDefaultPermission) {
|
|
5275
|
+
return { ...NO_PERMISSION_CAPABILITIES, ...resolved.capabilities };
|
|
5276
|
+
}
|
|
5277
|
+
const capabilities = {
|
|
5278
|
+
...NO_PERMISSION_CAPABILITIES,
|
|
5279
|
+
[DEFAULT_PERMISSION_RESOURCE]: resolved.baseAccess
|
|
5280
|
+
};
|
|
5281
|
+
for (const resource of ROOM_PERMISSION_RESOURCES) {
|
|
5282
|
+
capabilities[resource] = resolved.capabilities[resource] ?? resolved.baseAccess;
|
|
5283
|
+
}
|
|
5284
|
+
return capabilities;
|
|
5285
|
+
}
|
|
5286
|
+
function permissionCapabilitiesFromScopes(scopes) {
|
|
5287
|
+
return resolveFullPermissionCapabilities(
|
|
5288
|
+
resolvePermissionCapabilities(scopes)
|
|
5289
|
+
);
|
|
5290
|
+
}
|
|
5291
|
+
function resolvePermissionCapabilities(scopes) {
|
|
5292
|
+
const hasDefaultPermission = scopes.includes(Permission.RoomWrite) || scopes.includes(Permission.RoomRead);
|
|
5293
|
+
const baseAccess = scopes.includes(Permission.RoomWrite) ? "write" : scopes.includes(Permission.RoomRead) ? "read" : "none";
|
|
5294
|
+
const capabilities = {};
|
|
5295
|
+
for (const resource of ROOM_PERMISSION_RESOURCES) {
|
|
5296
|
+
const access = resolveResourceAccess(scopes, resource);
|
|
5297
|
+
if (access !== void 0) {
|
|
5298
|
+
capabilities[resource] = access;
|
|
5299
|
+
}
|
|
5300
|
+
}
|
|
5301
|
+
return { hasDefaultPermission, baseAccess, capabilities };
|
|
5302
|
+
}
|
|
5303
|
+
function hasPermissionCapability(scopes, resource, requiredAccess) {
|
|
5304
|
+
const access = permissionCapabilitiesFromScopes(scopes)[resource];
|
|
5305
|
+
return ACCESS_RANKS[access] >= ACCESS_RANKS[requiredAccess];
|
|
5306
|
+
}
|
|
5307
|
+
function hasPermissionCapabilityAccess(capabilities, resource, requiredAccess) {
|
|
5308
|
+
const access = capabilities[resource] ?? "none";
|
|
5309
|
+
return ACCESS_RANKS[access] >= ACCESS_RANKS[requiredAccess];
|
|
5310
|
+
}
|
|
5311
|
+
|
|
5312
|
+
// src/permissions.ts
|
|
5313
|
+
var VALID_PERMISSIONS = new Set(Object.values(Permission));
|
|
5314
|
+
var DEFAULT_PERMISSIONS = [
|
|
5315
|
+
Permission.RoomRead,
|
|
5316
|
+
Permission.RoomWrite
|
|
5317
|
+
];
|
|
5318
|
+
var ROOM_PERMISSION_OBJECT_KEYS = /* @__PURE__ */ new Set([
|
|
5319
|
+
"default",
|
|
5320
|
+
...ROOM_PERMISSION_RESOURCES
|
|
5321
|
+
]);
|
|
5322
|
+
var RESOURCE_SPECIFIC_PERMISSIONS_BY_RESOURCE = {
|
|
5323
|
+
presence: Object.values(RESOURCE_PERMISSIONS.presence).flat(),
|
|
5324
|
+
storage: Object.values(RESOURCE_PERMISSIONS.storage).flat(),
|
|
5325
|
+
comments: Object.values(RESOURCE_PERMISSIONS.comments).flat(),
|
|
5326
|
+
feeds: Object.values(RESOURCE_PERMISSIONS.feeds).flat()
|
|
5327
|
+
};
|
|
5328
|
+
var RESOURCE_SPECIFIC_PERMISSIONS = ROOM_PERMISSION_RESOURCES.flatMap(
|
|
5329
|
+
(resource) => RESOURCE_SPECIFIC_PERMISSIONS_BY_RESOURCE[resource]
|
|
5330
|
+
);
|
|
5331
|
+
function permissionForAccessLevel(resource, access) {
|
|
5332
|
+
const levels = RESOURCE_PERMISSIONS[resource];
|
|
5333
|
+
const permissions = levels[access];
|
|
5334
|
+
if (permissions === void 0 || permissions.length === 0) {
|
|
5335
|
+
throw new Error(
|
|
5336
|
+
`Invalid permission level for ${resource}: ${String(access)}`
|
|
5337
|
+
);
|
|
5338
|
+
}
|
|
5339
|
+
return permissions[0];
|
|
5340
|
+
}
|
|
5341
|
+
function resolveRoomPermissionCapabilities(permissions, roomId) {
|
|
5342
|
+
const matchedPermissions = permissions.filter(
|
|
5343
|
+
(permission) => resourceMatchesRoomId(permission.resource, roomId)
|
|
5344
|
+
);
|
|
5345
|
+
if (matchedPermissions.length === 0) {
|
|
5346
|
+
return void 0;
|
|
5347
|
+
}
|
|
5348
|
+
let hasDefaultPermission = false;
|
|
5349
|
+
let baseAccess = "none";
|
|
5350
|
+
const explicitCapabilities = {};
|
|
5351
|
+
for (const permission of matchedPermissions) {
|
|
5352
|
+
const resolved = resolvePermissionCapabilities(permission.scopes);
|
|
5353
|
+
if (resolved.hasDefaultPermission) {
|
|
5354
|
+
hasDefaultPermission = true;
|
|
5355
|
+
baseAccess = strongestAccess(baseAccess, resolved.baseAccess);
|
|
5356
|
+
}
|
|
5357
|
+
for (const resource of ROOM_PERMISSION_RESOURCES) {
|
|
5358
|
+
const access = resolved.capabilities[resource];
|
|
5359
|
+
if (access !== void 0) {
|
|
5360
|
+
explicitCapabilities[resource] = strongestAccess(
|
|
5361
|
+
explicitCapabilities[resource] ?? "none",
|
|
5362
|
+
access
|
|
5363
|
+
);
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
return resolveFullPermissionCapabilities({
|
|
5368
|
+
hasDefaultPermission,
|
|
5369
|
+
baseAccess,
|
|
5370
|
+
capabilities: explicitCapabilities
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
5373
|
+
function isRoomPermissionArray(input) {
|
|
5374
|
+
return Array.isArray(input);
|
|
5375
|
+
}
|
|
5376
|
+
function normalizeRoomPermissionInput(input) {
|
|
5377
|
+
if (isRoomPermissionArray(input)) {
|
|
5378
|
+
return input.map((permission) => {
|
|
5379
|
+
if (!VALID_PERMISSIONS.has(permission)) {
|
|
5380
|
+
throw new Error(`Not a valid permission: ${permission}`);
|
|
5381
|
+
}
|
|
5382
|
+
return permission;
|
|
5383
|
+
});
|
|
5384
|
+
}
|
|
5385
|
+
return normalizeRoomPermissionObject(input);
|
|
5386
|
+
}
|
|
5387
|
+
function normalizeRoomPermissionObject(objectInput) {
|
|
5388
|
+
for (const key of Object.keys(objectInput)) {
|
|
5389
|
+
if (!ROOM_PERMISSION_OBJECT_KEYS.has(key)) {
|
|
5390
|
+
throw new Error(`Unknown permission field: ${key}`);
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
const permissions = [];
|
|
5394
|
+
if (objectInput.default !== void 0) {
|
|
5395
|
+
permissions.push(
|
|
5396
|
+
permissionForAccessLevel(DEFAULT_PERMISSION_RESOURCE, objectInput.default)
|
|
5397
|
+
);
|
|
5398
|
+
}
|
|
5399
|
+
for (const resource of ROOM_PERMISSION_RESOURCES) {
|
|
5400
|
+
const access = objectInput[resource];
|
|
5401
|
+
if (access !== void 0) {
|
|
5402
|
+
permissions.push(permissionForAccessLevel(resource, access));
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
if (permissions.length === 0) {
|
|
5406
|
+
throw new Error("Permission object cannot be empty");
|
|
5407
|
+
}
|
|
5408
|
+
return permissions;
|
|
5409
|
+
}
|
|
5410
|
+
function normalizeRoomAccessesInput(input) {
|
|
5411
|
+
if (input === void 0) {
|
|
5412
|
+
return void 0;
|
|
5413
|
+
}
|
|
5414
|
+
return Object.fromEntries(
|
|
5415
|
+
Object.entries(input).map(([id, permissions]) => [
|
|
5416
|
+
id,
|
|
5417
|
+
normalizeRoomPermissionInput(permissions)
|
|
5418
|
+
])
|
|
5419
|
+
);
|
|
5420
|
+
}
|
|
5421
|
+
function normalizeRoomAccessesUpdateInput(input) {
|
|
5422
|
+
if (input === void 0) {
|
|
5423
|
+
return void 0;
|
|
5424
|
+
}
|
|
5425
|
+
return Object.fromEntries(
|
|
5426
|
+
Object.entries(input).map(([id, permissions]) => [
|
|
5427
|
+
id,
|
|
5428
|
+
permissions === null ? null : normalizeRoomPermissionInput(permissions)
|
|
5429
|
+
])
|
|
5430
|
+
);
|
|
5431
|
+
}
|
|
5432
|
+
function getRoomPermissionConflicts(permission) {
|
|
5433
|
+
if (DEFAULT_PERMISSIONS.includes(permission)) {
|
|
5434
|
+
return [...DEFAULT_PERMISSIONS, ...RESOURCE_SPECIFIC_PERMISSIONS];
|
|
5435
|
+
}
|
|
5436
|
+
for (const resource of ROOM_PERMISSION_RESOURCES) {
|
|
5437
|
+
const permissions = RESOURCE_SPECIFIC_PERMISSIONS_BY_RESOURCE[resource];
|
|
5438
|
+
if (permissions.includes(permission)) {
|
|
5439
|
+
return permissions;
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
return [];
|
|
5443
|
+
}
|
|
5444
|
+
function strongestAccess(left, right) {
|
|
5445
|
+
return ACCESS_RANKS[right] > ACCESS_RANKS[left] ? right : left;
|
|
5446
|
+
}
|
|
5447
|
+
function resourceMatchesRoomId(resource, roomId) {
|
|
5448
|
+
if (resource.includes("*")) {
|
|
5449
|
+
return roomId.startsWith(resource.replace("*", ""));
|
|
5450
|
+
}
|
|
5451
|
+
return resource === roomId;
|
|
5251
5452
|
}
|
|
5453
|
+
|
|
5454
|
+
// src/protocol/AuthToken.ts
|
|
5252
5455
|
function isValidAuthTokenPayload(data) {
|
|
5253
5456
|
return isPlainObject(data) && (data.k === "acc" /* ACCESS_TOKEN */ || data.k === "id" /* ID_TOKEN */);
|
|
5254
5457
|
}
|
|
@@ -5287,47 +5490,22 @@ function createAuthManager(authOptions, onAuthenticate) {
|
|
|
5287
5490
|
const authentication = prepareAuthentication(authOptions);
|
|
5288
5491
|
const seenTokens = /* @__PURE__ */ new Set();
|
|
5289
5492
|
const tokens = [];
|
|
5290
|
-
const expiryTimes = [];
|
|
5291
5493
|
const requestPromises = /* @__PURE__ */ new Map();
|
|
5292
5494
|
function reset() {
|
|
5293
5495
|
seenTokens.clear();
|
|
5294
5496
|
tokens.length = 0;
|
|
5295
|
-
expiryTimes.length = 0;
|
|
5296
5497
|
requestPromises.clear();
|
|
5297
5498
|
}
|
|
5298
|
-
function hasCorrespondingScopes(requestedScope, scopes) {
|
|
5299
|
-
if (requestedScope === "comments:read") {
|
|
5300
|
-
return scopes.includes("comments:read" /* CommentsRead */) || scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
|
|
5301
|
-
} else if (requestedScope === "room:read") {
|
|
5302
|
-
return scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
|
|
5303
|
-
}
|
|
5304
|
-
return false;
|
|
5305
|
-
}
|
|
5306
5499
|
function getCachedToken(requestOptions) {
|
|
5307
5500
|
const now2 = Math.ceil(Date.now() / 1e3);
|
|
5308
5501
|
for (let i = tokens.length - 1; i >= 0; i--) {
|
|
5309
|
-
const
|
|
5310
|
-
|
|
5311
|
-
if (expiresAt <= now2) {
|
|
5502
|
+
const cachedToken = tokens[i];
|
|
5503
|
+
if (cachedToken.expiresAt <= now2) {
|
|
5312
5504
|
tokens.splice(i, 1);
|
|
5313
|
-
expiryTimes.splice(i, 1);
|
|
5314
5505
|
continue;
|
|
5315
5506
|
}
|
|
5316
|
-
if (
|
|
5317
|
-
return token;
|
|
5318
|
-
} else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
|
|
5319
|
-
if (!requestOptions.roomId && Object.entries(token.parsed.perms).length === 0) {
|
|
5320
|
-
return token;
|
|
5321
|
-
}
|
|
5322
|
-
for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
|
|
5323
|
-
if (!requestOptions.roomId) {
|
|
5324
|
-
if (resource.includes("*") && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
|
|
5325
|
-
return token;
|
|
5326
|
-
}
|
|
5327
|
-
} else if (resource.includes("*") && requestOptions.roomId.startsWith(resource.replace("*", "")) || requestOptions.roomId === resource && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
|
|
5328
|
-
return token;
|
|
5329
|
-
}
|
|
5330
|
-
}
|
|
5507
|
+
if (cachedTokenSatisfiesRequest(cachedToken, requestOptions)) {
|
|
5508
|
+
return cachedToken.token;
|
|
5331
5509
|
}
|
|
5332
5510
|
}
|
|
5333
5511
|
return void 0;
|
|
@@ -5385,11 +5563,12 @@ function createAuthManager(authOptions, onAuthenticate) {
|
|
|
5385
5563
|
return { type: "secret", token: cachedToken };
|
|
5386
5564
|
}
|
|
5387
5565
|
let currentPromise;
|
|
5388
|
-
|
|
5389
|
-
|
|
5566
|
+
const requestKey = getAuthRequestKey(requestOptions);
|
|
5567
|
+
if (requestKey !== void 0) {
|
|
5568
|
+
currentPromise = requestPromises.get(requestKey);
|
|
5390
5569
|
if (currentPromise === void 0) {
|
|
5391
5570
|
currentPromise = makeAuthRequest(requestOptions);
|
|
5392
|
-
requestPromises.set(
|
|
5571
|
+
requestPromises.set(requestKey, currentPromise);
|
|
5393
5572
|
}
|
|
5394
5573
|
} else {
|
|
5395
5574
|
currentPromise = requestPromises.get("liveblocks-user-token");
|
|
@@ -5403,12 +5582,12 @@ function createAuthManager(authOptions, onAuthenticate) {
|
|
|
5403
5582
|
const BUFFER = 30;
|
|
5404
5583
|
const expiresAt = Math.floor(Date.now() / 1e3) + (token.parsed.exp - token.parsed.iat) - BUFFER;
|
|
5405
5584
|
seenTokens.add(token.raw);
|
|
5406
|
-
|
|
5407
|
-
|
|
5585
|
+
const cachedToken2 = makeCachedToken(token, expiresAt);
|
|
5586
|
+
tokens.push(cachedToken2);
|
|
5408
5587
|
return { type: "secret", token };
|
|
5409
5588
|
} finally {
|
|
5410
|
-
if (
|
|
5411
|
-
requestPromises.delete(
|
|
5589
|
+
if (requestKey !== void 0) {
|
|
5590
|
+
requestPromises.delete(requestKey);
|
|
5412
5591
|
} else {
|
|
5413
5592
|
requestPromises.delete("liveblocks-user-token");
|
|
5414
5593
|
}
|
|
@@ -5419,6 +5598,48 @@ function createAuthManager(authOptions, onAuthenticate) {
|
|
|
5419
5598
|
getAuthValue
|
|
5420
5599
|
};
|
|
5421
5600
|
}
|
|
5601
|
+
function getAuthRequestKey(request) {
|
|
5602
|
+
if (request.roomId === void 0) {
|
|
5603
|
+
return void 0;
|
|
5604
|
+
}
|
|
5605
|
+
return `${request.roomId}:${request.resource}:${request.access}`;
|
|
5606
|
+
}
|
|
5607
|
+
function makeCachedToken(token, expiresAt) {
|
|
5608
|
+
if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
|
|
5609
|
+
return {
|
|
5610
|
+
token,
|
|
5611
|
+
expiresAt,
|
|
5612
|
+
permissions: getAuthTokenPermissionScopes(token.parsed.perms)
|
|
5613
|
+
};
|
|
5614
|
+
}
|
|
5615
|
+
return { token, expiresAt };
|
|
5616
|
+
}
|
|
5617
|
+
function getAuthTokenPermissionScopes(permissions) {
|
|
5618
|
+
return Object.entries(permissions).map(([resource, scopes]) => ({
|
|
5619
|
+
resource,
|
|
5620
|
+
scopes
|
|
5621
|
+
}));
|
|
5622
|
+
}
|
|
5623
|
+
function cachedTokenSatisfiesRequest(cachedToken, request) {
|
|
5624
|
+
if (cachedToken.token.parsed.k === "id" /* ID_TOKEN */) {
|
|
5625
|
+
return true;
|
|
5626
|
+
}
|
|
5627
|
+
if (request.resource === "personal") {
|
|
5628
|
+
return true;
|
|
5629
|
+
}
|
|
5630
|
+
if (request.roomId === void 0) {
|
|
5631
|
+
return false;
|
|
5632
|
+
}
|
|
5633
|
+
const capabilities = resolveRoomPermissionCapabilities(
|
|
5634
|
+
cachedToken.permissions ?? [],
|
|
5635
|
+
request.roomId
|
|
5636
|
+
);
|
|
5637
|
+
return capabilities !== void 0 && hasPermissionCapabilityAccess(
|
|
5638
|
+
capabilities,
|
|
5639
|
+
request.resource,
|
|
5640
|
+
request.access
|
|
5641
|
+
);
|
|
5642
|
+
}
|
|
5422
5643
|
function prepareAuthentication(authOptions) {
|
|
5423
5644
|
const { publicApiKey, authEndpoint } = authOptions;
|
|
5424
5645
|
if (authEndpoint !== void 0 && publicApiKey !== void 0) {
|
|
@@ -5511,9 +5732,7 @@ var OpCode = Object.freeze({
|
|
|
5511
5732
|
DELETE_CRDT: 5,
|
|
5512
5733
|
DELETE_OBJECT_KEY: 6,
|
|
5513
5734
|
CREATE_MAP: 7,
|
|
5514
|
-
CREATE_REGISTER: 8
|
|
5515
|
-
CREATE_TEXT: 9,
|
|
5516
|
-
UPDATE_TEXT: 10
|
|
5735
|
+
CREATE_REGISTER: 8
|
|
5517
5736
|
});
|
|
5518
5737
|
function isIgnoredOp(op) {
|
|
5519
5738
|
return op.type === OpCode.DELETE_CRDT && op.id === "ACK";
|
|
@@ -5527,8 +5746,7 @@ var CrdtType = Object.freeze({
|
|
|
5527
5746
|
OBJECT: 0,
|
|
5528
5747
|
LIST: 1,
|
|
5529
5748
|
MAP: 2,
|
|
5530
|
-
REGISTER: 3
|
|
5531
|
-
TEXT: 4
|
|
5749
|
+
REGISTER: 3
|
|
5532
5750
|
});
|
|
5533
5751
|
function isRootStorageNode(node) {
|
|
5534
5752
|
return node[0] === "root";
|
|
@@ -5545,9 +5763,6 @@ function isMapStorageNode(node) {
|
|
|
5545
5763
|
function isRegisterStorageNode(node) {
|
|
5546
5764
|
return node[1].type === CrdtType.REGISTER;
|
|
5547
5765
|
}
|
|
5548
|
-
function isTextStorageNode(node) {
|
|
5549
|
-
return node[1].type === CrdtType.TEXT;
|
|
5550
|
-
}
|
|
5551
5766
|
function isCompactRootNode(node) {
|
|
5552
5767
|
return node[0] === "root";
|
|
5553
5768
|
}
|
|
@@ -5570,9 +5785,6 @@ function* compactNodesToNodeStream(compactNodes) {
|
|
|
5570
5785
|
case CrdtType.REGISTER:
|
|
5571
5786
|
yield [cnode[0], { type: CrdtType.REGISTER, parentId: cnode[2], parentKey: cnode[3], data: cnode[4] }];
|
|
5572
5787
|
break;
|
|
5573
|
-
case CrdtType.TEXT:
|
|
5574
|
-
yield [cnode[0], { type: CrdtType.TEXT, parentId: cnode[2], parentKey: cnode[3], data: cnode[4], version: cnode[5] }];
|
|
5575
|
-
break;
|
|
5576
5788
|
default:
|
|
5577
5789
|
}
|
|
5578
5790
|
}
|
|
@@ -5601,17 +5813,6 @@ function* nodeStreamToCompactNodes(nodes) {
|
|
|
5601
5813
|
const id = node[0];
|
|
5602
5814
|
const crdt = node[1];
|
|
5603
5815
|
yield [id, CrdtType.REGISTER, crdt.parentId, crdt.parentKey, crdt.data];
|
|
5604
|
-
} else if (isTextStorageNode(node)) {
|
|
5605
|
-
const id = node[0];
|
|
5606
|
-
const crdt = node[1];
|
|
5607
|
-
yield [
|
|
5608
|
-
id,
|
|
5609
|
-
CrdtType.TEXT,
|
|
5610
|
-
crdt.parentId,
|
|
5611
|
-
crdt.parentKey,
|
|
5612
|
-
crdt.data,
|
|
5613
|
-
crdt.version
|
|
5614
|
-
];
|
|
5615
5816
|
} else {
|
|
5616
5817
|
}
|
|
5617
5818
|
}
|
|
@@ -8474,580 +8675,6 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
|
|
|
8474
8675
|
}
|
|
8475
8676
|
};
|
|
8476
8677
|
|
|
8477
|
-
// src/crdts/liveTextOps.ts
|
|
8478
|
-
function attributesEqual(left, right) {
|
|
8479
|
-
if (left === right) {
|
|
8480
|
-
return true;
|
|
8481
|
-
}
|
|
8482
|
-
if (left === void 0 || right === void 0) {
|
|
8483
|
-
return false;
|
|
8484
|
-
}
|
|
8485
|
-
const leftKeys = Object.keys(left);
|
|
8486
|
-
const rightKeys = Object.keys(right);
|
|
8487
|
-
if (leftKeys.length !== rightKeys.length) {
|
|
8488
|
-
return false;
|
|
8489
|
-
}
|
|
8490
|
-
for (const key of leftKeys) {
|
|
8491
|
-
if (left[key] !== right[key]) {
|
|
8492
|
-
return false;
|
|
8493
|
-
}
|
|
8494
|
-
}
|
|
8495
|
-
return true;
|
|
8496
|
-
}
|
|
8497
|
-
function cloneAttributes(attributes) {
|
|
8498
|
-
return attributes === void 0 ? void 0 : freeze({ ...attributes });
|
|
8499
|
-
}
|
|
8500
|
-
function normalizeSegments(segments) {
|
|
8501
|
-
const normalized = [];
|
|
8502
|
-
for (const segment of segments) {
|
|
8503
|
-
if (segment.text.length === 0) {
|
|
8504
|
-
continue;
|
|
8505
|
-
}
|
|
8506
|
-
const last = normalized.at(-1);
|
|
8507
|
-
const attributes = cloneAttributes(segment.attributes);
|
|
8508
|
-
if (last !== void 0 && attributesEqual(last.attributes, attributes)) {
|
|
8509
|
-
last.text += segment.text;
|
|
8510
|
-
} else {
|
|
8511
|
-
normalized.push({ text: segment.text, attributes });
|
|
8512
|
-
}
|
|
8513
|
-
}
|
|
8514
|
-
return normalized;
|
|
8515
|
-
}
|
|
8516
|
-
function dataToSegments(data) {
|
|
8517
|
-
return normalizeSegments(
|
|
8518
|
-
data.map(([text, attributes]) => ({
|
|
8519
|
-
text,
|
|
8520
|
-
attributes
|
|
8521
|
-
}))
|
|
8522
|
-
);
|
|
8523
|
-
}
|
|
8524
|
-
function segmentsToData(segments) {
|
|
8525
|
-
return segments.map(
|
|
8526
|
-
(segment) => segment.attributes === void 0 ? [segment.text] : [segment.text, { ...segment.attributes }]
|
|
8527
|
-
);
|
|
8528
|
-
}
|
|
8529
|
-
function textLength(segments) {
|
|
8530
|
-
return segments.reduce((sum, segment) => sum + segment.text.length, 0);
|
|
8531
|
-
}
|
|
8532
|
-
function splitSegmentsAt(segments, index) {
|
|
8533
|
-
const result = [];
|
|
8534
|
-
let offset = 0;
|
|
8535
|
-
for (const segment of segments) {
|
|
8536
|
-
const end = offset + segment.text.length;
|
|
8537
|
-
if (index > offset && index < end) {
|
|
8538
|
-
const before2 = segment.text.slice(0, index - offset);
|
|
8539
|
-
const after2 = segment.text.slice(index - offset);
|
|
8540
|
-
result.push({ text: before2, attributes: segment.attributes });
|
|
8541
|
-
result.push({ text: after2, attributes: segment.attributes });
|
|
8542
|
-
} else {
|
|
8543
|
-
result.push({ text: segment.text, attributes: segment.attributes });
|
|
8544
|
-
}
|
|
8545
|
-
offset = end;
|
|
8546
|
-
}
|
|
8547
|
-
return result;
|
|
8548
|
-
}
|
|
8549
|
-
function clipRange(index, length, contentLength) {
|
|
8550
|
-
const clippedIndex = Math.max(0, Math.min(index, contentLength));
|
|
8551
|
-
const clippedEnd = Math.max(
|
|
8552
|
-
clippedIndex,
|
|
8553
|
-
Math.min(index + length, contentLength)
|
|
8554
|
-
);
|
|
8555
|
-
return { index: clippedIndex, length: clippedEnd - clippedIndex };
|
|
8556
|
-
}
|
|
8557
|
-
function applyInsert(segments, index, text, attributes) {
|
|
8558
|
-
if (text.length === 0) {
|
|
8559
|
-
return normalizeSegments(segments);
|
|
8560
|
-
}
|
|
8561
|
-
const split = splitSegmentsAt(segments, index);
|
|
8562
|
-
const result = [];
|
|
8563
|
-
let offset = 0;
|
|
8564
|
-
let inserted = false;
|
|
8565
|
-
for (const segment of split) {
|
|
8566
|
-
if (!inserted && offset === index) {
|
|
8567
|
-
result.push({ text, attributes });
|
|
8568
|
-
inserted = true;
|
|
8569
|
-
}
|
|
8570
|
-
result.push(segment);
|
|
8571
|
-
offset += segment.text.length;
|
|
8572
|
-
}
|
|
8573
|
-
if (!inserted) {
|
|
8574
|
-
result.push({ text, attributes });
|
|
8575
|
-
}
|
|
8576
|
-
return normalizeSegments(result);
|
|
8577
|
-
}
|
|
8578
|
-
function extractDeletedSegments(segments, index, length) {
|
|
8579
|
-
const split = splitSegmentsAt(
|
|
8580
|
-
splitSegmentsAt(segments, index),
|
|
8581
|
-
index + length
|
|
8582
|
-
);
|
|
8583
|
-
const deleted = [];
|
|
8584
|
-
let offset = 0;
|
|
8585
|
-
for (const segment of split) {
|
|
8586
|
-
const end = offset + segment.text.length;
|
|
8587
|
-
if (offset >= index && end <= index + length) {
|
|
8588
|
-
deleted.push({
|
|
8589
|
-
text: segment.text,
|
|
8590
|
-
attributes: segment.attributes
|
|
8591
|
-
});
|
|
8592
|
-
}
|
|
8593
|
-
offset = end;
|
|
8594
|
-
}
|
|
8595
|
-
return normalizeSegments(deleted);
|
|
8596
|
-
}
|
|
8597
|
-
function applyDelete(segments, index, length) {
|
|
8598
|
-
const deletedSegments = extractDeletedSegments(segments, index, length);
|
|
8599
|
-
const split = splitSegmentsAt(
|
|
8600
|
-
splitSegmentsAt(segments, index),
|
|
8601
|
-
index + length
|
|
8602
|
-
);
|
|
8603
|
-
const result = [];
|
|
8604
|
-
let offset = 0;
|
|
8605
|
-
let deletedText = "";
|
|
8606
|
-
for (const segment of split) {
|
|
8607
|
-
const end = offset + segment.text.length;
|
|
8608
|
-
if (offset >= index && end <= index + length) {
|
|
8609
|
-
deletedText += segment.text;
|
|
8610
|
-
} else {
|
|
8611
|
-
result.push(segment);
|
|
8612
|
-
}
|
|
8613
|
-
offset = end;
|
|
8614
|
-
}
|
|
8615
|
-
return {
|
|
8616
|
-
segments: normalizeSegments(result),
|
|
8617
|
-
deletedText,
|
|
8618
|
-
deletedSegments
|
|
8619
|
-
};
|
|
8620
|
-
}
|
|
8621
|
-
function applyFormat(segments, index, length, attributes) {
|
|
8622
|
-
const split = splitSegmentsAt(
|
|
8623
|
-
splitSegmentsAt(segments, index),
|
|
8624
|
-
index + length
|
|
8625
|
-
);
|
|
8626
|
-
const result = [];
|
|
8627
|
-
let offset = 0;
|
|
8628
|
-
for (const segment of split) {
|
|
8629
|
-
const end = offset + segment.text.length;
|
|
8630
|
-
if (offset >= index && end <= index + length) {
|
|
8631
|
-
const nextAttributes = {
|
|
8632
|
-
...segment.attributes ?? {}
|
|
8633
|
-
};
|
|
8634
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
8635
|
-
if (value === null) {
|
|
8636
|
-
delete nextAttributes[key];
|
|
8637
|
-
} else {
|
|
8638
|
-
nextAttributes[key] = value;
|
|
8639
|
-
}
|
|
8640
|
-
}
|
|
8641
|
-
result.push({
|
|
8642
|
-
text: segment.text,
|
|
8643
|
-
attributes: Object.keys(nextAttributes).length === 0 ? void 0 : freeze(nextAttributes)
|
|
8644
|
-
});
|
|
8645
|
-
} else {
|
|
8646
|
-
result.push(segment);
|
|
8647
|
-
}
|
|
8648
|
-
offset = end;
|
|
8649
|
-
}
|
|
8650
|
-
return normalizeSegments(result);
|
|
8651
|
-
}
|
|
8652
|
-
function formatReverseOperations(segments, index, length, patch) {
|
|
8653
|
-
const split = splitSegmentsAt(
|
|
8654
|
-
splitSegmentsAt(segments, index),
|
|
8655
|
-
index + length
|
|
8656
|
-
);
|
|
8657
|
-
const result = [];
|
|
8658
|
-
let offset = 0;
|
|
8659
|
-
for (const segment of split) {
|
|
8660
|
-
const end = offset + segment.text.length;
|
|
8661
|
-
if (offset >= index && end <= index + length) {
|
|
8662
|
-
const attributes = {};
|
|
8663
|
-
for (const key of Object.keys(patch)) {
|
|
8664
|
-
attributes[key] = segment.attributes?.[key] ?? null;
|
|
8665
|
-
}
|
|
8666
|
-
result.push({
|
|
8667
|
-
type: "format",
|
|
8668
|
-
index: offset,
|
|
8669
|
-
length: segment.text.length,
|
|
8670
|
-
attributes
|
|
8671
|
-
});
|
|
8672
|
-
}
|
|
8673
|
-
offset = end;
|
|
8674
|
-
}
|
|
8675
|
-
return result;
|
|
8676
|
-
}
|
|
8677
|
-
function mapIndexThroughOperation(index, op) {
|
|
8678
|
-
if (op.type === "insert") {
|
|
8679
|
-
return op.index <= index ? index + op.text.length : index;
|
|
8680
|
-
} else if (op.type === "delete") {
|
|
8681
|
-
if (op.index >= index) {
|
|
8682
|
-
return index;
|
|
8683
|
-
}
|
|
8684
|
-
return Math.max(op.index, index - op.length);
|
|
8685
|
-
} else {
|
|
8686
|
-
return index;
|
|
8687
|
-
}
|
|
8688
|
-
}
|
|
8689
|
-
function mapTextIndexThroughOperations(index, ops) {
|
|
8690
|
-
let mapped = index;
|
|
8691
|
-
for (const op of ops) {
|
|
8692
|
-
mapped = mapIndexThroughOperation(mapped, op);
|
|
8693
|
-
}
|
|
8694
|
-
return mapped;
|
|
8695
|
-
}
|
|
8696
|
-
function rebaseTextOperations(ops, acceptedOps) {
|
|
8697
|
-
return ops.map((op) => {
|
|
8698
|
-
if (op.type === "insert") {
|
|
8699
|
-
return {
|
|
8700
|
-
...op,
|
|
8701
|
-
index: mapTextIndexThroughOperations(op.index, acceptedOps)
|
|
8702
|
-
};
|
|
8703
|
-
} else if (op.type === "delete" || op.type === "format") {
|
|
8704
|
-
const start = mapTextIndexThroughOperations(op.index, acceptedOps);
|
|
8705
|
-
const end = mapTextIndexThroughOperations(
|
|
8706
|
-
op.index + op.length,
|
|
8707
|
-
acceptedOps
|
|
8708
|
-
);
|
|
8709
|
-
return { ...op, index: start, length: Math.max(0, end - start) };
|
|
8710
|
-
} else {
|
|
8711
|
-
return op;
|
|
8712
|
-
}
|
|
8713
|
-
});
|
|
8714
|
-
}
|
|
8715
|
-
function applyTextOperationsToSegments(segments, ops) {
|
|
8716
|
-
let next = [...segments];
|
|
8717
|
-
for (const op of ops) {
|
|
8718
|
-
if (op.type === "insert") {
|
|
8719
|
-
const index = Math.max(0, Math.min(op.index, textLength(next)));
|
|
8720
|
-
next = applyInsert(next, index, op.text, op.attributes);
|
|
8721
|
-
} else if (op.type === "delete") {
|
|
8722
|
-
const index = Math.max(0, Math.min(op.index, textLength(next)));
|
|
8723
|
-
const clipped = clipRange(index, op.length, textLength(next));
|
|
8724
|
-
next = applyDelete(next, clipped.index, clipped.length).segments;
|
|
8725
|
-
} else {
|
|
8726
|
-
const index = Math.max(0, Math.min(op.index, textLength(next)));
|
|
8727
|
-
const clipped = clipRange(index, op.length, textLength(next));
|
|
8728
|
-
next = applyFormat(next, clipped.index, clipped.length, op.attributes);
|
|
8729
|
-
}
|
|
8730
|
-
}
|
|
8731
|
-
return next;
|
|
8732
|
-
}
|
|
8733
|
-
function applyLiveTextOperations(data, ops) {
|
|
8734
|
-
return segmentsToData(
|
|
8735
|
-
applyTextOperationsToSegments(dataToSegments(data), ops)
|
|
8736
|
-
);
|
|
8737
|
-
}
|
|
8738
|
-
function invertTextOperations(segments, ops) {
|
|
8739
|
-
let shadow = [...segments];
|
|
8740
|
-
const reverse = [];
|
|
8741
|
-
for (const op of ops) {
|
|
8742
|
-
if (op.type === "insert") {
|
|
8743
|
-
shadow = applyInsert(shadow, op.index, op.text, op.attributes);
|
|
8744
|
-
reverse.unshift({
|
|
8745
|
-
type: "delete",
|
|
8746
|
-
index: op.index,
|
|
8747
|
-
length: op.text.length
|
|
8748
|
-
});
|
|
8749
|
-
} else if (op.type === "delete") {
|
|
8750
|
-
const deletedSegments = extractDeletedSegments(
|
|
8751
|
-
shadow,
|
|
8752
|
-
op.index,
|
|
8753
|
-
op.length
|
|
8754
|
-
);
|
|
8755
|
-
shadow = applyDelete(shadow, op.index, op.length).segments;
|
|
8756
|
-
const inserts = [];
|
|
8757
|
-
let insertIndex = op.index;
|
|
8758
|
-
for (const segment of deletedSegments) {
|
|
8759
|
-
inserts.push({
|
|
8760
|
-
type: "insert",
|
|
8761
|
-
index: insertIndex,
|
|
8762
|
-
text: segment.text,
|
|
8763
|
-
attributes: segment.attributes
|
|
8764
|
-
});
|
|
8765
|
-
insertIndex += segment.text.length;
|
|
8766
|
-
}
|
|
8767
|
-
for (let index = inserts.length - 1; index >= 0; index--) {
|
|
8768
|
-
reverse.unshift(inserts[index]);
|
|
8769
|
-
}
|
|
8770
|
-
} else {
|
|
8771
|
-
const inverse = formatReverseOperations(
|
|
8772
|
-
shadow,
|
|
8773
|
-
op.index,
|
|
8774
|
-
op.length,
|
|
8775
|
-
op.attributes
|
|
8776
|
-
);
|
|
8777
|
-
shadow = applyFormat(shadow, op.index, op.length, op.attributes);
|
|
8778
|
-
reverse.unshift(...inverse.reverse());
|
|
8779
|
-
}
|
|
8780
|
-
}
|
|
8781
|
-
return reverse;
|
|
8782
|
-
}
|
|
8783
|
-
|
|
8784
|
-
// src/crdts/LiveText.ts
|
|
8785
|
-
var LiveText = class _LiveText extends AbstractCrdt {
|
|
8786
|
-
#segments;
|
|
8787
|
-
#version;
|
|
8788
|
-
#pendingOps;
|
|
8789
|
-
constructor(textOrData = "", version = 0) {
|
|
8790
|
-
super();
|
|
8791
|
-
this.#segments = typeof textOrData === "string" ? textOrData.length === 0 ? [] : [{ text: textOrData }] : dataToSegments(textOrData);
|
|
8792
|
-
this.#version = version;
|
|
8793
|
-
this.#pendingOps = /* @__PURE__ */ new Map();
|
|
8794
|
-
}
|
|
8795
|
-
get version() {
|
|
8796
|
-
return this.#version;
|
|
8797
|
-
}
|
|
8798
|
-
get length() {
|
|
8799
|
-
return this.toString().length;
|
|
8800
|
-
}
|
|
8801
|
-
/** @internal */
|
|
8802
|
-
static _deserialize([id, item], _parentToChildren, pool) {
|
|
8803
|
-
const text = new _LiveText(item.data, item.version);
|
|
8804
|
-
text._attach(id, pool);
|
|
8805
|
-
return text;
|
|
8806
|
-
}
|
|
8807
|
-
/** @internal */
|
|
8808
|
-
_toOps(parentId, parentKey) {
|
|
8809
|
-
if (this._id === void 0) {
|
|
8810
|
-
throw new Error("Cannot serialize LiveText if it is not attached");
|
|
8811
|
-
}
|
|
8812
|
-
return [
|
|
8813
|
-
{
|
|
8814
|
-
type: OpCode.CREATE_TEXT,
|
|
8815
|
-
id: this._id,
|
|
8816
|
-
parentId,
|
|
8817
|
-
parentKey,
|
|
8818
|
-
data: this.toJSON(),
|
|
8819
|
-
version: this.#version
|
|
8820
|
-
}
|
|
8821
|
-
];
|
|
8822
|
-
}
|
|
8823
|
-
/** @internal */
|
|
8824
|
-
_serialize() {
|
|
8825
|
-
if (this.parent.type !== "HasParent") {
|
|
8826
|
-
throw new Error("Cannot serialize LiveText if parent is missing");
|
|
8827
|
-
}
|
|
8828
|
-
return {
|
|
8829
|
-
type: CrdtType.TEXT,
|
|
8830
|
-
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
8831
|
-
parentKey: this.parent.key,
|
|
8832
|
-
data: this.toJSON(),
|
|
8833
|
-
version: this.#version
|
|
8834
|
-
};
|
|
8835
|
-
}
|
|
8836
|
-
/** @internal */
|
|
8837
|
-
_attachChild(_op) {
|
|
8838
|
-
throw new Error("LiveText cannot contain child nodes");
|
|
8839
|
-
}
|
|
8840
|
-
/** @internal */
|
|
8841
|
-
_detachChild(_crdt) {
|
|
8842
|
-
throw new Error("LiveText cannot contain child nodes");
|
|
8843
|
-
}
|
|
8844
|
-
/** @internal */
|
|
8845
|
-
_apply(op, isLocal) {
|
|
8846
|
-
if (op.type !== OpCode.UPDATE_TEXT) {
|
|
8847
|
-
return super._apply(op, isLocal);
|
|
8848
|
-
}
|
|
8849
|
-
if (isLocal) {
|
|
8850
|
-
this.#pendingOps.set(nn(op.opId), op.ops);
|
|
8851
|
-
return this.#applyOperations(op.ops, op.version ?? this.#version);
|
|
8852
|
-
}
|
|
8853
|
-
if (op.opId !== void 0) {
|
|
8854
|
-
const pending2 = this.#pendingOps.get(op.opId);
|
|
8855
|
-
this.#pendingOps.delete(op.opId);
|
|
8856
|
-
const otherPending = Array.from(this.#pendingOps.values()).flat();
|
|
8857
|
-
if (pending2 !== void 0 && otherPending.length > 0) {
|
|
8858
|
-
this.#segments = applyTextOperationsToSegments(
|
|
8859
|
-
this.#segments,
|
|
8860
|
-
invertTextOperations(this.#segments, pending2)
|
|
8861
|
-
);
|
|
8862
|
-
const ops2 = rebaseTextOperations(op.ops, otherPending);
|
|
8863
|
-
return this.#applyOperations(
|
|
8864
|
-
ops2,
|
|
8865
|
-
op.version ?? Math.max(this.#version, op.baseVersion + 1)
|
|
8866
|
-
);
|
|
8867
|
-
}
|
|
8868
|
-
this.#version = op.version ?? Math.max(this.#version, op.baseVersion + 1);
|
|
8869
|
-
return { modified: false };
|
|
8870
|
-
}
|
|
8871
|
-
const pending = Array.from(this.#pendingOps.values()).flat();
|
|
8872
|
-
const ops = pending.length > 0 ? rebaseTextOperations(op.ops, pending) : op.ops;
|
|
8873
|
-
return this.#applyOperations(ops, op.version ?? this.#version + 1);
|
|
8874
|
-
}
|
|
8875
|
-
insert(index, text, attributes) {
|
|
8876
|
-
const clippedIndex = Math.max(0, Math.min(index, this.length));
|
|
8877
|
-
this.#dispatch([{ type: "insert", index: clippedIndex, text, attributes }]);
|
|
8878
|
-
}
|
|
8879
|
-
delete(index, length) {
|
|
8880
|
-
const clipped = clipRange(index, length, this.length);
|
|
8881
|
-
if (clipped.length === 0) {
|
|
8882
|
-
return;
|
|
8883
|
-
}
|
|
8884
|
-
this.#dispatch([
|
|
8885
|
-
{ type: "delete", index: clipped.index, length: clipped.length }
|
|
8886
|
-
]);
|
|
8887
|
-
}
|
|
8888
|
-
replace(index, length, text, attributes) {
|
|
8889
|
-
const clipped = clipRange(index, length, this.length);
|
|
8890
|
-
const ops = [];
|
|
8891
|
-
if (clipped.length > 0) {
|
|
8892
|
-
ops.push({
|
|
8893
|
-
type: "delete",
|
|
8894
|
-
index: clipped.index,
|
|
8895
|
-
length: clipped.length
|
|
8896
|
-
});
|
|
8897
|
-
}
|
|
8898
|
-
if (text.length > 0) {
|
|
8899
|
-
ops.push({ type: "insert", index: clipped.index, text, attributes });
|
|
8900
|
-
}
|
|
8901
|
-
this.#dispatch(ops);
|
|
8902
|
-
}
|
|
8903
|
-
format(index, length, attributes) {
|
|
8904
|
-
const clipped = clipRange(index, length, this.length);
|
|
8905
|
-
if (clipped.length === 0) {
|
|
8906
|
-
return;
|
|
8907
|
-
}
|
|
8908
|
-
this.#dispatch([
|
|
8909
|
-
{
|
|
8910
|
-
type: "format",
|
|
8911
|
-
index: clipped.index,
|
|
8912
|
-
length: clipped.length,
|
|
8913
|
-
attributes
|
|
8914
|
-
}
|
|
8915
|
-
]);
|
|
8916
|
-
}
|
|
8917
|
-
#dispatch(ops) {
|
|
8918
|
-
if (ops.length === 0) {
|
|
8919
|
-
return;
|
|
8920
|
-
}
|
|
8921
|
-
this._pool?.assertStorageIsWritable();
|
|
8922
|
-
const baseVersion = this.#version;
|
|
8923
|
-
const reverse = this._pool !== void 0 && this._id !== void 0 ? this.#invertOperations(ops) : [];
|
|
8924
|
-
const changes = this.#applyOperationsLocally(ops);
|
|
8925
|
-
if (this._pool !== void 0 && this._id !== void 0) {
|
|
8926
|
-
const opId = this._pool.generateOpId();
|
|
8927
|
-
this.#pendingOps.set(opId, ops);
|
|
8928
|
-
this._pool.dispatch(
|
|
8929
|
-
[
|
|
8930
|
-
{
|
|
8931
|
-
type: OpCode.UPDATE_TEXT,
|
|
8932
|
-
id: this._id,
|
|
8933
|
-
opId,
|
|
8934
|
-
baseVersion,
|
|
8935
|
-
ops: [...ops]
|
|
8936
|
-
}
|
|
8937
|
-
],
|
|
8938
|
-
reverse,
|
|
8939
|
-
/* @__PURE__ */ new Map([
|
|
8940
|
-
[
|
|
8941
|
-
this._id,
|
|
8942
|
-
{
|
|
8943
|
-
type: "LiveText",
|
|
8944
|
-
node: this,
|
|
8945
|
-
version: this.#version,
|
|
8946
|
-
updates: changes
|
|
8947
|
-
}
|
|
8948
|
-
]
|
|
8949
|
-
])
|
|
8950
|
-
);
|
|
8951
|
-
}
|
|
8952
|
-
}
|
|
8953
|
-
#applyOperations(ops, version) {
|
|
8954
|
-
const reverse = this.#invertOperations(ops);
|
|
8955
|
-
const changes = this.#applyOperationsLocally(ops);
|
|
8956
|
-
this.#version = Math.max(this.#version, version);
|
|
8957
|
-
return {
|
|
8958
|
-
reverse,
|
|
8959
|
-
modified: {
|
|
8960
|
-
type: "LiveText",
|
|
8961
|
-
node: this,
|
|
8962
|
-
version: this.#version,
|
|
8963
|
-
updates: changes
|
|
8964
|
-
}
|
|
8965
|
-
};
|
|
8966
|
-
}
|
|
8967
|
-
#applyOperationsLocally(ops) {
|
|
8968
|
-
const changes = [];
|
|
8969
|
-
for (const op of ops) {
|
|
8970
|
-
if (op.type === "insert") {
|
|
8971
|
-
this.#segments = applyInsert(
|
|
8972
|
-
this.#segments,
|
|
8973
|
-
op.index,
|
|
8974
|
-
op.text,
|
|
8975
|
-
op.attributes
|
|
8976
|
-
);
|
|
8977
|
-
changes.push({
|
|
8978
|
-
type: "insert",
|
|
8979
|
-
index: op.index,
|
|
8980
|
-
text: op.text,
|
|
8981
|
-
attributes: op.attributes
|
|
8982
|
-
});
|
|
8983
|
-
} else if (op.type === "delete") {
|
|
8984
|
-
const result = applyDelete(this.#segments, op.index, op.length);
|
|
8985
|
-
this.#segments = result.segments;
|
|
8986
|
-
changes.push({
|
|
8987
|
-
type: "delete",
|
|
8988
|
-
index: op.index,
|
|
8989
|
-
length: op.length,
|
|
8990
|
-
deletedText: result.deletedText
|
|
8991
|
-
});
|
|
8992
|
-
} else {
|
|
8993
|
-
this.#segments = applyFormat(
|
|
8994
|
-
this.#segments,
|
|
8995
|
-
op.index,
|
|
8996
|
-
op.length,
|
|
8997
|
-
op.attributes
|
|
8998
|
-
);
|
|
8999
|
-
changes.push({
|
|
9000
|
-
type: "format",
|
|
9001
|
-
index: op.index,
|
|
9002
|
-
length: op.length,
|
|
9003
|
-
attributes: op.attributes
|
|
9004
|
-
});
|
|
9005
|
-
}
|
|
9006
|
-
}
|
|
9007
|
-
this.invalidate();
|
|
9008
|
-
return changes;
|
|
9009
|
-
}
|
|
9010
|
-
#invertOperations(ops) {
|
|
9011
|
-
return [
|
|
9012
|
-
{
|
|
9013
|
-
type: OpCode.UPDATE_TEXT,
|
|
9014
|
-
id: nn(this._id),
|
|
9015
|
-
baseVersion: this.#version,
|
|
9016
|
-
ops: invertTextOperations(this.#segments, ops)
|
|
9017
|
-
}
|
|
9018
|
-
];
|
|
9019
|
-
}
|
|
9020
|
-
toString() {
|
|
9021
|
-
return this.#segments.map((segment) => segment.text).join("");
|
|
9022
|
-
}
|
|
9023
|
-
toJSON() {
|
|
9024
|
-
return super.toJSON();
|
|
9025
|
-
}
|
|
9026
|
-
/** @internal */
|
|
9027
|
-
_toJSON() {
|
|
9028
|
-
return segmentsToData(this.#segments);
|
|
9029
|
-
}
|
|
9030
|
-
/** @internal */
|
|
9031
|
-
_toTreeNode(key) {
|
|
9032
|
-
return {
|
|
9033
|
-
type: "LiveText",
|
|
9034
|
-
id: this._id ?? nanoid(),
|
|
9035
|
-
key,
|
|
9036
|
-
payload: [
|
|
9037
|
-
{
|
|
9038
|
-
type: "Json",
|
|
9039
|
-
id: `${this._id ?? nanoid()}:text`,
|
|
9040
|
-
key: "text",
|
|
9041
|
-
payload: this.toString()
|
|
9042
|
-
}
|
|
9043
|
-
]
|
|
9044
|
-
};
|
|
9045
|
-
}
|
|
9046
|
-
clone() {
|
|
9047
|
-
return new _LiveText(this.toJSON(), this.#version);
|
|
9048
|
-
}
|
|
9049
|
-
};
|
|
9050
|
-
|
|
9051
8678
|
// src/crdts/liveblocks-helpers.ts
|
|
9052
8679
|
function creationOpToLiveNode(op) {
|
|
9053
8680
|
return lsonToLiveNode(creationOpToLson(op));
|
|
@@ -9062,8 +8689,6 @@ function creationOpToLson(op) {
|
|
|
9062
8689
|
return new LiveMap();
|
|
9063
8690
|
case OpCode.CREATE_LIST:
|
|
9064
8691
|
return new LiveList([]);
|
|
9065
|
-
case OpCode.CREATE_TEXT:
|
|
9066
|
-
return new LiveText(op.data, op.version);
|
|
9067
8692
|
default:
|
|
9068
8693
|
return assertNever(op, "Unknown creation Op");
|
|
9069
8694
|
}
|
|
@@ -9086,8 +8711,6 @@ function deserialize(node, parentToChildren, pool) {
|
|
|
9086
8711
|
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
9087
8712
|
} else if (isRegisterStorageNode(node)) {
|
|
9088
8713
|
return LiveRegister._deserialize(node, parentToChildren, pool);
|
|
9089
|
-
} else if (isTextStorageNode(node)) {
|
|
9090
|
-
return LiveText._deserialize(node, parentToChildren, pool);
|
|
9091
8714
|
} else {
|
|
9092
8715
|
throw new Error("Unexpected CRDT type");
|
|
9093
8716
|
}
|
|
@@ -9101,14 +8724,12 @@ function deserializeToLson(node, parentToChildren, pool) {
|
|
|
9101
8724
|
return LiveMap._deserialize(node, parentToChildren, pool);
|
|
9102
8725
|
} else if (isRegisterStorageNode(node)) {
|
|
9103
8726
|
return node[1].data;
|
|
9104
|
-
} else if (isTextStorageNode(node)) {
|
|
9105
|
-
return LiveText._deserialize(node, parentToChildren, pool);
|
|
9106
8727
|
} else {
|
|
9107
8728
|
throw new Error("Unexpected CRDT type");
|
|
9108
8729
|
}
|
|
9109
8730
|
}
|
|
9110
8731
|
function isLiveStructure(value) {
|
|
9111
|
-
return isLiveList(value) || isLiveMap(value) || isLiveObject(value)
|
|
8732
|
+
return isLiveList(value) || isLiveMap(value) || isLiveObject(value);
|
|
9112
8733
|
}
|
|
9113
8734
|
function isLiveNode(value) {
|
|
9114
8735
|
return isLiveStructure(value) || isLiveRegister(value);
|
|
@@ -9122,9 +8743,6 @@ function isLiveMap(value) {
|
|
|
9122
8743
|
function isLiveObject(value) {
|
|
9123
8744
|
return value instanceof LiveObject;
|
|
9124
8745
|
}
|
|
9125
|
-
function isLiveText(value) {
|
|
9126
|
-
return value instanceof LiveText;
|
|
9127
|
-
}
|
|
9128
8746
|
function isLiveRegister(value) {
|
|
9129
8747
|
return value instanceof LiveRegister;
|
|
9130
8748
|
}
|
|
@@ -9134,14 +8752,14 @@ function cloneLson(value) {
|
|
|
9134
8752
|
function liveNodeToLson(obj) {
|
|
9135
8753
|
if (obj instanceof LiveRegister) {
|
|
9136
8754
|
return obj.data;
|
|
9137
|
-
} else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject
|
|
8755
|
+
} else if (obj instanceof LiveList || obj instanceof LiveMap || obj instanceof LiveObject) {
|
|
9138
8756
|
return obj;
|
|
9139
8757
|
} else {
|
|
9140
8758
|
return assertNever(obj, "Unknown AbstractCrdt");
|
|
9141
8759
|
}
|
|
9142
8760
|
}
|
|
9143
8761
|
function lsonToLiveNode(value) {
|
|
9144
|
-
if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList
|
|
8762
|
+
if (value instanceof LiveObject || value instanceof LiveMap || value instanceof LiveList) {
|
|
9145
8763
|
return value;
|
|
9146
8764
|
} else {
|
|
9147
8765
|
return new LiveRegister(value);
|
|
@@ -9236,40 +8854,6 @@ function getTreesDiffOperations(currentItems, newItems) {
|
|
|
9236
8854
|
}
|
|
9237
8855
|
}
|
|
9238
8856
|
}
|
|
9239
|
-
if (crdt.type === CrdtType.TEXT) {
|
|
9240
|
-
if (currentCrdt.type !== CrdtType.TEXT || stringifyOrLog(crdt.data) !== stringifyOrLog(currentCrdt.data) || crdt.version !== currentCrdt.version) {
|
|
9241
|
-
ops.push({
|
|
9242
|
-
type: OpCode.UPDATE_TEXT,
|
|
9243
|
-
id,
|
|
9244
|
-
baseVersion: currentCrdt.type === CrdtType.TEXT ? currentCrdt.version : 0,
|
|
9245
|
-
version: crdt.version,
|
|
9246
|
-
ops: [
|
|
9247
|
-
{
|
|
9248
|
-
type: "delete",
|
|
9249
|
-
index: 0,
|
|
9250
|
-
length: currentCrdt.type === CrdtType.TEXT ? currentCrdt.data.reduce(
|
|
9251
|
-
(sum, segment) => sum + segment[0].length,
|
|
9252
|
-
0
|
|
9253
|
-
) : 0
|
|
9254
|
-
},
|
|
9255
|
-
...crdt.data.map((segment, index, items) => {
|
|
9256
|
-
const [text, attributes] = segment;
|
|
9257
|
-
const insertIndex = items.slice(0, index).reduce((sum, item) => sum + item[0].length, 0);
|
|
9258
|
-
return attributes === void 0 ? {
|
|
9259
|
-
type: "insert",
|
|
9260
|
-
index: insertIndex,
|
|
9261
|
-
text
|
|
9262
|
-
} : {
|
|
9263
|
-
type: "insert",
|
|
9264
|
-
index: insertIndex,
|
|
9265
|
-
text,
|
|
9266
|
-
attributes
|
|
9267
|
-
};
|
|
9268
|
-
})
|
|
9269
|
-
]
|
|
9270
|
-
});
|
|
9271
|
-
}
|
|
9272
|
-
}
|
|
9273
8857
|
if (crdt.parentKey !== currentCrdt.parentKey) {
|
|
9274
8858
|
ops.push({
|
|
9275
8859
|
type: OpCode.SET_PARENT_KEY,
|
|
@@ -9318,16 +8902,6 @@ function getTreesDiffOperations(currentItems, newItems) {
|
|
|
9318
8902
|
parentKey: crdt.parentKey
|
|
9319
8903
|
});
|
|
9320
8904
|
break;
|
|
9321
|
-
case CrdtType.TEXT:
|
|
9322
|
-
ops.push({
|
|
9323
|
-
type: OpCode.CREATE_TEXT,
|
|
9324
|
-
id,
|
|
9325
|
-
parentId: crdt.parentId,
|
|
9326
|
-
parentKey: crdt.parentKey,
|
|
9327
|
-
data: crdt.data,
|
|
9328
|
-
version: crdt.version
|
|
9329
|
-
});
|
|
9330
|
-
break;
|
|
9331
8905
|
}
|
|
9332
8906
|
}
|
|
9333
8907
|
});
|
|
@@ -9360,12 +8934,6 @@ function mergeListStorageUpdates(first, second) {
|
|
|
9360
8934
|
updates: updates.concat(second.updates)
|
|
9361
8935
|
};
|
|
9362
8936
|
}
|
|
9363
|
-
function mergeTextStorageUpdates(first, second) {
|
|
9364
|
-
return {
|
|
9365
|
-
...second,
|
|
9366
|
-
updates: first.updates.concat(second.updates)
|
|
9367
|
-
};
|
|
9368
|
-
}
|
|
9369
8937
|
function mergeStorageUpdates(first, second) {
|
|
9370
8938
|
if (first === void 0) {
|
|
9371
8939
|
return second;
|
|
@@ -9376,8 +8944,6 @@ function mergeStorageUpdates(first, second) {
|
|
|
9376
8944
|
return mergeMapStorageUpdates(first, second);
|
|
9377
8945
|
} else if (first.type === "LiveList" && second.type === "LiveList") {
|
|
9378
8946
|
return mergeListStorageUpdates(first, second);
|
|
9379
|
-
} else if (first.type === "LiveText" && second.type === "LiveText") {
|
|
9380
|
-
return mergeTextStorageUpdates(first, second);
|
|
9381
8947
|
} else {
|
|
9382
8948
|
}
|
|
9383
8949
|
return second;
|
|
@@ -9964,14 +9530,14 @@ var ClientMsgCode = Object.freeze({
|
|
|
9964
9530
|
// src/refs/ManagedOthers.ts
|
|
9965
9531
|
function makeUser(conn, presence) {
|
|
9966
9532
|
const { connectionId, id, info } = conn;
|
|
9967
|
-
const canWrite =
|
|
9533
|
+
const canWrite = hasPermissionCapability(conn.scopes, "storage", "write");
|
|
9968
9534
|
return freeze(
|
|
9969
9535
|
compactObject({
|
|
9970
9536
|
connectionId,
|
|
9971
9537
|
id,
|
|
9972
9538
|
info,
|
|
9973
9539
|
canWrite,
|
|
9974
|
-
canComment:
|
|
9540
|
+
canComment: hasPermissionCapability(conn.scopes, "comments", "write"),
|
|
9975
9541
|
isReadOnly: !canWrite,
|
|
9976
9542
|
// Deprecated, kept for backward-compatibility
|
|
9977
9543
|
presence
|
|
@@ -10428,7 +9994,7 @@ function createRoom(options, config) {
|
|
|
10428
9994
|
}
|
|
10429
9995
|
function isStorageWritable() {
|
|
10430
9996
|
const scopes = context.dynamicSessionInfoSig.get()?.scopes;
|
|
10431
|
-
return scopes !== void 0 ?
|
|
9997
|
+
return scopes !== void 0 ? hasPermissionCapability(scopes, "storage", "write") : true;
|
|
10432
9998
|
}
|
|
10433
9999
|
const eventHub = {
|
|
10434
10000
|
status: makeEventSource(),
|
|
@@ -10489,14 +10055,22 @@ function createRoom(options, config) {
|
|
|
10489
10055
|
if (staticSession === null || dynamicSession === null) {
|
|
10490
10056
|
return null;
|
|
10491
10057
|
} else {
|
|
10492
|
-
const canWrite =
|
|
10058
|
+
const canWrite = hasPermissionCapability(
|
|
10059
|
+
dynamicSession.scopes,
|
|
10060
|
+
"storage",
|
|
10061
|
+
"write"
|
|
10062
|
+
);
|
|
10493
10063
|
return {
|
|
10494
10064
|
connectionId: dynamicSession.actor,
|
|
10495
10065
|
id: staticSession.userId,
|
|
10496
10066
|
info: staticSession.userInfo,
|
|
10497
10067
|
presence: myPresence,
|
|
10498
10068
|
canWrite,
|
|
10499
|
-
canComment:
|
|
10069
|
+
canComment: hasPermissionCapability(
|
|
10070
|
+
dynamicSession.scopes,
|
|
10071
|
+
"comments",
|
|
10072
|
+
"write"
|
|
10073
|
+
)
|
|
10500
10074
|
};
|
|
10501
10075
|
}
|
|
10502
10076
|
}
|
|
@@ -10662,7 +10236,7 @@ function createRoom(options, config) {
|
|
|
10662
10236
|
);
|
|
10663
10237
|
output.reverse.pushLeft(applyOpResult.reverse);
|
|
10664
10238
|
}
|
|
10665
|
-
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT
|
|
10239
|
+
if (op.type === OpCode.CREATE_LIST || op.type === OpCode.CREATE_MAP || op.type === OpCode.CREATE_OBJECT) {
|
|
10666
10240
|
createdNodeIds.add(op.id);
|
|
10667
10241
|
}
|
|
10668
10242
|
}
|
|
@@ -10682,7 +10256,6 @@ function createRoom(options, config) {
|
|
|
10682
10256
|
switch (op.type) {
|
|
10683
10257
|
case OpCode.DELETE_OBJECT_KEY:
|
|
10684
10258
|
case OpCode.UPDATE_OBJECT:
|
|
10685
|
-
case OpCode.UPDATE_TEXT:
|
|
10686
10259
|
case OpCode.DELETE_CRDT: {
|
|
10687
10260
|
const node = context.pool.nodes.get(op.id);
|
|
10688
10261
|
if (node === void 0) {
|
|
@@ -10707,7 +10280,6 @@ function createRoom(options, config) {
|
|
|
10707
10280
|
case OpCode.CREATE_OBJECT:
|
|
10708
10281
|
case OpCode.CREATE_LIST:
|
|
10709
10282
|
case OpCode.CREATE_MAP:
|
|
10710
|
-
case OpCode.CREATE_TEXT:
|
|
10711
10283
|
case OpCode.CREATE_REGISTER: {
|
|
10712
10284
|
if (op.parentId === void 0) {
|
|
10713
10285
|
return { modified: false };
|
|
@@ -12098,7 +11670,11 @@ function isRoomEventName(value) {
|
|
|
12098
11670
|
}
|
|
12099
11671
|
function makeAuthDelegateForRoom(roomId, authManager) {
|
|
12100
11672
|
return async () => {
|
|
12101
|
-
return authManager.getAuthValue({
|
|
11673
|
+
return authManager.getAuthValue({
|
|
11674
|
+
roomId,
|
|
11675
|
+
resource: "presence",
|
|
11676
|
+
access: "read"
|
|
11677
|
+
});
|
|
12102
11678
|
};
|
|
12103
11679
|
}
|
|
12104
11680
|
function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
|
|
@@ -12188,7 +11764,9 @@ function createClient(options) {
|
|
|
12188
11764
|
),
|
|
12189
11765
|
authenticate: async () => {
|
|
12190
11766
|
const resp = await authManager.getAuthValue({
|
|
12191
|
-
|
|
11767
|
+
// TODO: Should we have permissions for AI Copilots?
|
|
11768
|
+
resource: "personal",
|
|
11769
|
+
access: "write"
|
|
12192
11770
|
});
|
|
12193
11771
|
if (resp.type === "public") {
|
|
12194
11772
|
throw new StopRetrying(
|
|
@@ -12867,12 +12445,6 @@ function toPlainLson(lson) {
|
|
|
12867
12445
|
liveblocksType: "LiveList",
|
|
12868
12446
|
data: [...lson].map((item) => toPlainLson(item))
|
|
12869
12447
|
};
|
|
12870
|
-
} else if (lson instanceof LiveText) {
|
|
12871
|
-
return {
|
|
12872
|
-
liveblocksType: "LiveText",
|
|
12873
|
-
data: lson.toJSON(),
|
|
12874
|
-
version: lson.version
|
|
12875
|
-
};
|
|
12876
12448
|
} else {
|
|
12877
12449
|
return lson;
|
|
12878
12450
|
}
|
|
@@ -13054,7 +12626,6 @@ export {
|
|
|
13054
12626
|
LiveList,
|
|
13055
12627
|
LiveMap,
|
|
13056
12628
|
LiveObject,
|
|
13057
|
-
LiveText,
|
|
13058
12629
|
LiveblocksError,
|
|
13059
12630
|
MENTION_CHARACTER,
|
|
13060
12631
|
MutableSignal,
|
|
@@ -13066,7 +12637,6 @@ export {
|
|
|
13066
12637
|
SortedList,
|
|
13067
12638
|
TextEditorType,
|
|
13068
12639
|
WebsocketCloseCodes,
|
|
13069
|
-
applyLiveTextOperations,
|
|
13070
12640
|
asPos,
|
|
13071
12641
|
assert,
|
|
13072
12642
|
assertNever,
|
|
@@ -13104,7 +12674,10 @@ export {
|
|
|
13104
12674
|
freeze,
|
|
13105
12675
|
generateUrl,
|
|
13106
12676
|
getMentionsFromCommentBody,
|
|
12677
|
+
getRoomPermissionConflicts,
|
|
13107
12678
|
getSubscriptionKey,
|
|
12679
|
+
hasPermissionCapability,
|
|
12680
|
+
hasPermissionCapabilityAccess,
|
|
13108
12681
|
html,
|
|
13109
12682
|
htmlSafe,
|
|
13110
12683
|
isCommentBodyLink,
|
|
@@ -13123,7 +12696,6 @@ export {
|
|
|
13123
12696
|
isRegisterStorageNode,
|
|
13124
12697
|
isRootStorageNode,
|
|
13125
12698
|
isStartsWithOperator,
|
|
13126
|
-
isTextStorageNode,
|
|
13127
12699
|
isUrl,
|
|
13128
12700
|
kInternal,
|
|
13129
12701
|
keys,
|
|
@@ -13136,8 +12708,12 @@ export {
|
|
|
13136
12708
|
nanoid,
|
|
13137
12709
|
nn,
|
|
13138
12710
|
nodeStreamToCompactNodes,
|
|
12711
|
+
normalizeRoomAccessesInput,
|
|
12712
|
+
normalizeRoomAccessesUpdateInput,
|
|
12713
|
+
normalizeRoomPermissionInput,
|
|
13139
12714
|
objectToQuery,
|
|
13140
12715
|
patchNotificationSettings,
|
|
12716
|
+
permissionCapabilitiesFromScopes,
|
|
13141
12717
|
raise,
|
|
13142
12718
|
resolveMentionsInCommentBody,
|
|
13143
12719
|
sanitizeUrl,
|