@liveblocks/core 1.8.2 → 1.9.0-example1
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.d.mts +56 -12
- package/dist/index.d.ts +56 -12
- package/dist/index.js +2454 -2399
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2353 -2298
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
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 = "1.
|
|
9
|
+
var PKG_VERSION = "1.9.0-example1";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1744,1405 +1744,1765 @@ function errorIf(condition, message) {
|
|
|
1744
1744
|
}
|
|
1745
1745
|
}
|
|
1746
1746
|
|
|
1747
|
-
// src/comments/
|
|
1748
|
-
function
|
|
1749
|
-
|
|
1750
|
-
return authValue.publicApiKey;
|
|
1751
|
-
} else {
|
|
1752
|
-
return authValue.token.raw;
|
|
1753
|
-
}
|
|
1747
|
+
// src/comments/comment-body.ts
|
|
1748
|
+
function isCommentBodyParagraph(element) {
|
|
1749
|
+
return "type" in element && element.type === "mention";
|
|
1754
1750
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1751
|
+
function isCommentBodyText(element) {
|
|
1752
|
+
return "text" in element && typeof element.text === "string";
|
|
1753
|
+
}
|
|
1754
|
+
function isCommentBodyMention(element) {
|
|
1755
|
+
return "type" in element && element.type === "mention";
|
|
1756
|
+
}
|
|
1757
|
+
function isCommentBodyLink(element) {
|
|
1758
|
+
return "type" in element && element.type === "link";
|
|
1759
|
+
}
|
|
1760
|
+
var commentBodyElementsGuards = {
|
|
1761
|
+
paragraph: isCommentBodyParagraph,
|
|
1762
|
+
text: isCommentBodyText,
|
|
1763
|
+
link: isCommentBodyLink,
|
|
1764
|
+
mention: isCommentBodyMention
|
|
1762
1765
|
};
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1766
|
+
var commentBodyElementsTypes = {
|
|
1767
|
+
paragraph: "block",
|
|
1768
|
+
text: "inline",
|
|
1769
|
+
link: "inline",
|
|
1770
|
+
mention: "inline"
|
|
1771
|
+
};
|
|
1772
|
+
function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
1773
|
+
if (!body || !body?.content) {
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
|
|
1777
|
+
const type = element ? commentBodyElementsTypes[element] : "all";
|
|
1778
|
+
const guard = element ? commentBodyElementsGuards[element] : () => true;
|
|
1779
|
+
const visitor = typeof elementOrVisitor === "function" ? elementOrVisitor : possiblyVisitor;
|
|
1780
|
+
for (const block of body.content) {
|
|
1781
|
+
if (type === "all" || type === "block") {
|
|
1782
|
+
if (guard(block)) {
|
|
1783
|
+
visitor?.(block);
|
|
1780
1784
|
}
|
|
1781
1785
|
}
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
}
|
|
1788
|
-
return body;
|
|
1789
|
-
}
|
|
1790
|
-
async function fetchApi(roomId2, endpoint, options) {
|
|
1791
|
-
const authValue = await getAuthValue();
|
|
1792
|
-
const url = new URL(
|
|
1793
|
-
`/v2/c/rooms/${encodeURIComponent(roomId2)}${endpoint}`,
|
|
1794
|
-
config.baseUrl
|
|
1795
|
-
).toString();
|
|
1796
|
-
return await fetch(url, {
|
|
1797
|
-
...options,
|
|
1798
|
-
headers: {
|
|
1799
|
-
...options?.headers,
|
|
1800
|
-
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
1786
|
+
if (type === "all" || type === "inline") {
|
|
1787
|
+
for (const inline of block.children) {
|
|
1788
|
+
if (guard(inline)) {
|
|
1789
|
+
visitor?.(inline);
|
|
1790
|
+
}
|
|
1801
1791
|
}
|
|
1802
|
-
});
|
|
1803
|
-
}
|
|
1804
|
-
async function getThreads() {
|
|
1805
|
-
const response = await fetchApi(roomId, "/threads");
|
|
1806
|
-
if (response.ok) {
|
|
1807
|
-
const json = await response.json();
|
|
1808
|
-
return json.data;
|
|
1809
|
-
} else if (response.status === 404) {
|
|
1810
|
-
return [];
|
|
1811
|
-
} else {
|
|
1812
|
-
throw new Error("There was an error while getting threads.");
|
|
1813
1792
|
}
|
|
1814
1793
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1794
|
+
}
|
|
1795
|
+
function getMentionedIdsFromCommentBody(body) {
|
|
1796
|
+
const mentionedIds = /* @__PURE__ */ new Set();
|
|
1797
|
+
traverseCommentBody(
|
|
1817
1798
|
body,
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
id: threadId,
|
|
1828
|
-
comment: {
|
|
1829
|
-
id: commentId,
|
|
1830
|
-
body
|
|
1831
|
-
},
|
|
1832
|
-
metadata
|
|
1833
|
-
})
|
|
1834
|
-
});
|
|
1835
|
-
}
|
|
1836
|
-
function editThreadMetadata({
|
|
1837
|
-
metadata,
|
|
1838
|
-
threadId
|
|
1839
|
-
}) {
|
|
1840
|
-
return fetchJson(
|
|
1841
|
-
`/threads/${encodeURIComponent(threadId)}/metadata`,
|
|
1842
|
-
{
|
|
1843
|
-
method: "POST",
|
|
1844
|
-
headers: {
|
|
1845
|
-
"Content-Type": "application/json"
|
|
1846
|
-
},
|
|
1847
|
-
body: JSON.stringify(metadata)
|
|
1848
|
-
}
|
|
1849
|
-
);
|
|
1799
|
+
"mention",
|
|
1800
|
+
(mention) => mentionedIds.add(mention.id)
|
|
1801
|
+
);
|
|
1802
|
+
return Array.from(mentionedIds);
|
|
1803
|
+
}
|
|
1804
|
+
async function resolveUsersInCommentBody(body, resolveUsers) {
|
|
1805
|
+
const resolvedUsers = /* @__PURE__ */ new Map();
|
|
1806
|
+
if (!resolveUsers) {
|
|
1807
|
+
return resolvedUsers;
|
|
1850
1808
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
headers: {
|
|
1861
|
-
"Content-Type": "application/json"
|
|
1862
|
-
},
|
|
1863
|
-
body: JSON.stringify({
|
|
1864
|
-
id: commentId,
|
|
1865
|
-
body
|
|
1866
|
-
})
|
|
1867
|
-
}
|
|
1868
|
-
);
|
|
1809
|
+
const userIds = getMentionedIdsFromCommentBody(body);
|
|
1810
|
+
const users = await resolveUsers({
|
|
1811
|
+
userIds
|
|
1812
|
+
});
|
|
1813
|
+
for (const [index, userId] of userIds.entries()) {
|
|
1814
|
+
const user = users?.[index];
|
|
1815
|
+
if (user) {
|
|
1816
|
+
resolvedUsers.set(userId, user);
|
|
1817
|
+
}
|
|
1869
1818
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
);
|
|
1819
|
+
return resolvedUsers;
|
|
1820
|
+
}
|
|
1821
|
+
var htmlEscapables = {
|
|
1822
|
+
"&": "&",
|
|
1823
|
+
"<": "<",
|
|
1824
|
+
">": ">",
|
|
1825
|
+
'"': """,
|
|
1826
|
+
"'": "'"
|
|
1827
|
+
};
|
|
1828
|
+
var htmlEscapablesRegex = new RegExp(
|
|
1829
|
+
Object.keys(htmlEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
1830
|
+
"g"
|
|
1831
|
+
);
|
|
1832
|
+
function htmlSafe(value) {
|
|
1833
|
+
return new HtmlSafeString([String(value)], []);
|
|
1834
|
+
}
|
|
1835
|
+
function joinHtml(strings) {
|
|
1836
|
+
if (strings.length <= 0) {
|
|
1837
|
+
return new HtmlSafeString([""], []);
|
|
1889
1838
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
{
|
|
1899
|
-
method: "DELETE"
|
|
1900
|
-
}
|
|
1901
|
-
);
|
|
1839
|
+
return new HtmlSafeString(
|
|
1840
|
+
["", ...Array(strings.length - 1).fill(""), ""],
|
|
1841
|
+
strings
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
function escapeHtml(value) {
|
|
1845
|
+
if (value instanceof HtmlSafeString) {
|
|
1846
|
+
return value.toString();
|
|
1902
1847
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
commentId,
|
|
1906
|
-
emoji
|
|
1907
|
-
}) {
|
|
1908
|
-
return fetchJson(
|
|
1909
|
-
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
1910
|
-
commentId
|
|
1911
|
-
)}/reactions`,
|
|
1912
|
-
{
|
|
1913
|
-
method: "POST",
|
|
1914
|
-
headers: {
|
|
1915
|
-
"Content-Type": "application/json"
|
|
1916
|
-
},
|
|
1917
|
-
body: JSON.stringify({ emoji })
|
|
1918
|
-
}
|
|
1919
|
-
);
|
|
1848
|
+
if (Array.isArray(value)) {
|
|
1849
|
+
return joinHtml(value).toString();
|
|
1920
1850
|
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
{
|
|
1931
|
-
method: "DELETE"
|
|
1932
|
-
}
|
|
1933
|
-
);
|
|
1851
|
+
return String(value).replace(
|
|
1852
|
+
htmlEscapablesRegex,
|
|
1853
|
+
(character) => htmlEscapables[character]
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
var HtmlSafeString = class {
|
|
1857
|
+
constructor(strings, values) {
|
|
1858
|
+
this._strings = strings;
|
|
1859
|
+
this._values = values;
|
|
1934
1860
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
createComment,
|
|
1940
|
-
editComment,
|
|
1941
|
-
deleteComment,
|
|
1942
|
-
addReaction,
|
|
1943
|
-
removeReaction
|
|
1944
|
-
};
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
// src/lib/position.ts
|
|
1948
|
-
var MIN_CODE = 32;
|
|
1949
|
-
var MAX_CODE = 126;
|
|
1950
|
-
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
1951
|
-
var ZERO = nthDigit(0);
|
|
1952
|
-
var ONE = nthDigit(1);
|
|
1953
|
-
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
1954
|
-
function nthDigit(n) {
|
|
1955
|
-
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
1956
|
-
if (code < MIN_CODE || code > MAX_CODE) {
|
|
1957
|
-
throw new Error(`Invalid n value: ${n}`);
|
|
1861
|
+
toString() {
|
|
1862
|
+
return this._strings.reduce((result, str, i) => {
|
|
1863
|
+
return result + escapeHtml(nn(this._values[i - 1])) + str;
|
|
1864
|
+
});
|
|
1958
1865
|
}
|
|
1959
|
-
|
|
1866
|
+
};
|
|
1867
|
+
function html(strings, ...values) {
|
|
1868
|
+
return new HtmlSafeString(strings, values);
|
|
1960
1869
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1870
|
+
var markdownEscapables = {
|
|
1871
|
+
_: "\\_",
|
|
1872
|
+
"*": "\\*",
|
|
1873
|
+
"#": "\\#",
|
|
1874
|
+
"`": "\\`",
|
|
1875
|
+
"~": "\\~",
|
|
1876
|
+
"!": "\\!",
|
|
1877
|
+
"|": "\\|",
|
|
1878
|
+
"(": "\\(",
|
|
1879
|
+
")": "\\)",
|
|
1880
|
+
"{": "\\{",
|
|
1881
|
+
"}": "\\}",
|
|
1882
|
+
"[": "\\[",
|
|
1883
|
+
"]": "\\]"
|
|
1884
|
+
};
|
|
1885
|
+
var markdownEscapablesRegex = new RegExp(
|
|
1886
|
+
Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
1887
|
+
"g"
|
|
1888
|
+
);
|
|
1889
|
+
function joinMarkdown(strings) {
|
|
1890
|
+
if (strings.length <= 0) {
|
|
1891
|
+
return new MarkdownSafeString([""], []);
|
|
1970
1892
|
}
|
|
1893
|
+
return new MarkdownSafeString(
|
|
1894
|
+
["", ...Array(strings.length - 1).fill(""), ""],
|
|
1895
|
+
strings
|
|
1896
|
+
);
|
|
1971
1897
|
}
|
|
1972
|
-
function
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
const code = pos.charCodeAt(i);
|
|
1976
|
-
if (code <= MIN_CODE) {
|
|
1977
|
-
continue;
|
|
1978
|
-
}
|
|
1979
|
-
if (i === lastIndex) {
|
|
1980
|
-
if (code === MIN_CODE + 1) {
|
|
1981
|
-
return pos.substring(0, i) + ZERO_NINE;
|
|
1982
|
-
} else {
|
|
1983
|
-
return pos.substring(0, i) + String.fromCharCode(code - 1);
|
|
1984
|
-
}
|
|
1985
|
-
} else {
|
|
1986
|
-
return pos.substring(0, i + 1);
|
|
1987
|
-
}
|
|
1898
|
+
function escapeMarkdown(value) {
|
|
1899
|
+
if (value instanceof MarkdownSafeString) {
|
|
1900
|
+
return value.toString();
|
|
1988
1901
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
function after(pos) {
|
|
1992
|
-
for (let i = 0; i <= pos.length - 1; i++) {
|
|
1993
|
-
const code = pos.charCodeAt(i);
|
|
1994
|
-
if (code >= MAX_CODE) {
|
|
1995
|
-
continue;
|
|
1996
|
-
}
|
|
1997
|
-
return pos.substring(0, i) + String.fromCharCode(code + 1);
|
|
1902
|
+
if (Array.isArray(value)) {
|
|
1903
|
+
return joinMarkdown(value).toString();
|
|
1998
1904
|
}
|
|
1999
|
-
return
|
|
1905
|
+
return String(value).replace(
|
|
1906
|
+
markdownEscapablesRegex,
|
|
1907
|
+
(character) => markdownEscapables[character]
|
|
1908
|
+
);
|
|
2000
1909
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
return _between(hi, lo);
|
|
2006
|
-
} else {
|
|
2007
|
-
throw new Error("Cannot compute value between two equal positions");
|
|
1910
|
+
var MarkdownSafeString = class {
|
|
1911
|
+
constructor(strings, values) {
|
|
1912
|
+
this._strings = strings;
|
|
1913
|
+
this._values = values;
|
|
2008
1914
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
const hiLen = hi.length;
|
|
2014
|
-
while (true) {
|
|
2015
|
-
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
2016
|
-
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
2017
|
-
if (loCode === hiCode) {
|
|
2018
|
-
index++;
|
|
2019
|
-
continue;
|
|
2020
|
-
}
|
|
2021
|
-
if (hiCode - loCode === 1) {
|
|
2022
|
-
const size = index + 1;
|
|
2023
|
-
let prefix = lo.substring(0, size);
|
|
2024
|
-
if (prefix.length < size) {
|
|
2025
|
-
prefix += ZERO.repeat(size - prefix.length);
|
|
2026
|
-
}
|
|
2027
|
-
const suffix = lo.substring(size);
|
|
2028
|
-
const nines = "";
|
|
2029
|
-
return prefix + _between(suffix, nines);
|
|
2030
|
-
} else {
|
|
2031
|
-
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
2032
|
-
}
|
|
1915
|
+
toString() {
|
|
1916
|
+
return this._strings.reduce((result, str, i) => {
|
|
1917
|
+
return result + escapeMarkdown(nn(this._values[i - 1])) + str;
|
|
1918
|
+
});
|
|
2033
1919
|
}
|
|
1920
|
+
};
|
|
1921
|
+
function markdown(strings, ...values) {
|
|
1922
|
+
return new MarkdownSafeString(strings, values);
|
|
2034
1923
|
}
|
|
2035
|
-
function
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
if (str === "") {
|
|
2041
|
-
return false;
|
|
1924
|
+
function toAbsoluteUrl(url) {
|
|
1925
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
1926
|
+
return url;
|
|
1927
|
+
} else if (url.startsWith("www.")) {
|
|
1928
|
+
return "https://" + url;
|
|
2042
1929
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
var stringifyCommentBodyPlainElements = {
|
|
1933
|
+
paragraph: ({ children }) => children,
|
|
1934
|
+
text: ({ element }) => element.text,
|
|
1935
|
+
link: ({ element }) => element.url,
|
|
1936
|
+
mention: ({ element, user }) => {
|
|
1937
|
+
return `@${user?.name ?? element.id}`;
|
|
2047
1938
|
}
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
1939
|
+
};
|
|
1940
|
+
var stringifyCommentBodyHtmlElements = {
|
|
1941
|
+
paragraph: ({ children }) => {
|
|
1942
|
+
return children ? html`<p>${htmlSafe(children)}</p>` : children;
|
|
1943
|
+
},
|
|
1944
|
+
text: ({ element }) => {
|
|
1945
|
+
let children = element.text;
|
|
1946
|
+
if (!children) {
|
|
1947
|
+
return children;
|
|
2052
1948
|
}
|
|
1949
|
+
if (element.bold) {
|
|
1950
|
+
children = html`<strong>${children}</strong>`;
|
|
1951
|
+
}
|
|
1952
|
+
if (element.italic) {
|
|
1953
|
+
children = html`<em>${children}</em>`;
|
|
1954
|
+
}
|
|
1955
|
+
if (element.strikethrough) {
|
|
1956
|
+
children = html`<s>${children}</s>`;
|
|
1957
|
+
}
|
|
1958
|
+
if (element.code) {
|
|
1959
|
+
children = html`<code>${children}</code>`;
|
|
1960
|
+
}
|
|
1961
|
+
return children;
|
|
1962
|
+
},
|
|
1963
|
+
link: ({ element, href }) => {
|
|
1964
|
+
return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
|
|
1965
|
+
},
|
|
1966
|
+
mention: ({ element, user }) => {
|
|
1967
|
+
return html`<span data-mention>@${user?.name ?? element.id}</span>`;
|
|
2053
1968
|
}
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
1969
|
+
};
|
|
1970
|
+
var stringifyCommentBodyMarkdownElements = {
|
|
1971
|
+
paragraph: ({ children }) => {
|
|
1972
|
+
return children;
|
|
1973
|
+
},
|
|
1974
|
+
text: ({ element }) => {
|
|
1975
|
+
let children = element.text;
|
|
1976
|
+
if (!children) {
|
|
1977
|
+
return children;
|
|
1978
|
+
}
|
|
1979
|
+
if (element.bold) {
|
|
1980
|
+
children = markdown`**${children}**`;
|
|
1981
|
+
}
|
|
1982
|
+
if (element.italic) {
|
|
1983
|
+
children = markdown`_${children}_`;
|
|
1984
|
+
}
|
|
1985
|
+
if (element.strikethrough) {
|
|
1986
|
+
children = markdown`~~${children}~~`;
|
|
1987
|
+
}
|
|
1988
|
+
if (element.code) {
|
|
1989
|
+
children = markdown`\`${children}\``;
|
|
1990
|
+
}
|
|
1991
|
+
return children;
|
|
1992
|
+
},
|
|
1993
|
+
link: ({ element, href }) => {
|
|
1994
|
+
return markdown`[${element.url}](${href})`;
|
|
1995
|
+
},
|
|
1996
|
+
mention: ({ element, user }) => {
|
|
1997
|
+
return markdown`@${user?.name ?? element.id}`;
|
|
2064
1998
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
1999
|
+
};
|
|
2000
|
+
async function stringifyCommentBody(body, options) {
|
|
2001
|
+
const format = options?.format ?? "plain";
|
|
2002
|
+
const separator = options?.separator ?? (format === "markdown" ? "\n\n" : "\n");
|
|
2003
|
+
const elements = {
|
|
2004
|
+
...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
|
|
2005
|
+
...options?.elements
|
|
2006
|
+
};
|
|
2007
|
+
const resolvedUsers = await resolveUsersInCommentBody(
|
|
2008
|
+
body,
|
|
2009
|
+
options?.resolveUsers
|
|
2068
2010
|
);
|
|
2011
|
+
const blocks = body.content.flatMap((block, blockIndex) => {
|
|
2012
|
+
switch (block.type) {
|
|
2013
|
+
case "paragraph": {
|
|
2014
|
+
const inlines = block.children.flatMap((inline, inlineIndex) => {
|
|
2015
|
+
if (isCommentBodyMention(inline)) {
|
|
2016
|
+
return inline.id ? [
|
|
2017
|
+
elements.mention(
|
|
2018
|
+
{
|
|
2019
|
+
element: inline,
|
|
2020
|
+
user: resolvedUsers.get(inline.id)
|
|
2021
|
+
},
|
|
2022
|
+
inlineIndex
|
|
2023
|
+
)
|
|
2024
|
+
] : [];
|
|
2025
|
+
}
|
|
2026
|
+
if (isCommentBodyLink(inline)) {
|
|
2027
|
+
return [
|
|
2028
|
+
elements.link(
|
|
2029
|
+
{
|
|
2030
|
+
element: inline,
|
|
2031
|
+
href: toAbsoluteUrl(inline.url) ?? inline.url
|
|
2032
|
+
},
|
|
2033
|
+
inlineIndex
|
|
2034
|
+
)
|
|
2035
|
+
];
|
|
2036
|
+
}
|
|
2037
|
+
if (isCommentBodyText(inline)) {
|
|
2038
|
+
return [elements.text({ element: inline }, inlineIndex)];
|
|
2039
|
+
}
|
|
2040
|
+
return [];
|
|
2041
|
+
});
|
|
2042
|
+
return [
|
|
2043
|
+
elements.paragraph(
|
|
2044
|
+
{ element: block, children: inlines.join("") },
|
|
2045
|
+
blockIndex
|
|
2046
|
+
)
|
|
2047
|
+
];
|
|
2048
|
+
}
|
|
2049
|
+
default:
|
|
2050
|
+
return [];
|
|
2051
|
+
}
|
|
2052
|
+
});
|
|
2053
|
+
return blocks.join(separator);
|
|
2069
2054
|
}
|
|
2070
|
-
function
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2055
|
+
function convertToCommentData(data) {
|
|
2056
|
+
const editedAt = data.editedAt ? new Date(data.editedAt) : void 0;
|
|
2057
|
+
const createdAt = new Date(data.createdAt);
|
|
2058
|
+
const reactions = data.reactions.map((reaction) => ({
|
|
2059
|
+
...reaction,
|
|
2060
|
+
createdAt: new Date(reaction.createdAt)
|
|
2061
|
+
}));
|
|
2062
|
+
if (data.body) {
|
|
2063
|
+
return {
|
|
2064
|
+
...data,
|
|
2065
|
+
reactions,
|
|
2066
|
+
createdAt,
|
|
2067
|
+
editedAt
|
|
2068
|
+
};
|
|
2069
|
+
} else {
|
|
2070
|
+
const deletedAt = new Date(data.deletedAt);
|
|
2071
|
+
return {
|
|
2072
|
+
...data,
|
|
2073
|
+
reactions,
|
|
2074
|
+
createdAt,
|
|
2075
|
+
editedAt,
|
|
2076
|
+
deletedAt
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2094
2079
|
}
|
|
2095
|
-
function
|
|
2096
|
-
|
|
2080
|
+
function convertToThreadData(data) {
|
|
2081
|
+
const updatedAt = data.updatedAt ? new Date(data.updatedAt) : void 0;
|
|
2082
|
+
const createdAt = new Date(data.createdAt);
|
|
2083
|
+
const comments = data.comments.map(
|
|
2084
|
+
(comment) => convertToCommentData(comment)
|
|
2085
|
+
);
|
|
2086
|
+
return {
|
|
2087
|
+
...data,
|
|
2088
|
+
createdAt,
|
|
2089
|
+
updatedAt,
|
|
2090
|
+
comments
|
|
2091
|
+
};
|
|
2097
2092
|
}
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2093
|
+
function convertToCommentUserReaction(data) {
|
|
2094
|
+
return {
|
|
2095
|
+
...data,
|
|
2096
|
+
createdAt: new Date(data.createdAt)
|
|
2097
|
+
};
|
|
2101
2098
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
switch (this.parent.type) {
|
|
2110
|
-
case "HasParent":
|
|
2111
|
-
return this.parent.key;
|
|
2112
|
-
case "NoParent":
|
|
2113
|
-
throw new Error("Parent key is missing");
|
|
2114
|
-
case "Orphaned":
|
|
2115
|
-
return this.parent.oldKey;
|
|
2116
|
-
default:
|
|
2117
|
-
return assertNever(this.parent, "Unknown state");
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
/** @internal */
|
|
2121
|
-
get _parentPos() {
|
|
2122
|
-
switch (this.parent.type) {
|
|
2123
|
-
case "HasParent":
|
|
2124
|
-
return this.parent.pos;
|
|
2125
|
-
case "NoParent":
|
|
2126
|
-
throw new Error("Parent key is missing");
|
|
2127
|
-
case "Orphaned":
|
|
2128
|
-
return this.parent.oldPos;
|
|
2129
|
-
default:
|
|
2130
|
-
return assertNever(this.parent, "Unknown state");
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
/** @internal */
|
|
2134
|
-
get _pool() {
|
|
2135
|
-
return this.__pool;
|
|
2136
|
-
}
|
|
2137
|
-
get roomId() {
|
|
2138
|
-
return this.__pool ? this.__pool.roomId : null;
|
|
2139
|
-
}
|
|
2140
|
-
/** @internal */
|
|
2141
|
-
get _id() {
|
|
2142
|
-
return this.__id;
|
|
2143
|
-
}
|
|
2144
|
-
/** @internal */
|
|
2145
|
-
get parent() {
|
|
2146
|
-
return this._parent;
|
|
2099
|
+
|
|
2100
|
+
// src/comments/index.ts
|
|
2101
|
+
function getAuthBearerHeaderFromAuthValue(authValue) {
|
|
2102
|
+
if (authValue.type === "public") {
|
|
2103
|
+
return authValue.publicApiKey;
|
|
2104
|
+
} else {
|
|
2105
|
+
return authValue.token.raw;
|
|
2147
2106
|
}
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
case "Orphaned":
|
|
2156
|
-
return this.parent.oldKey;
|
|
2157
|
-
default:
|
|
2158
|
-
return assertNever(this.parent, "Unknown state");
|
|
2159
|
-
}
|
|
2107
|
+
}
|
|
2108
|
+
var CommentsApiError = class extends Error {
|
|
2109
|
+
constructor(message, status, details) {
|
|
2110
|
+
super(message);
|
|
2111
|
+
this.message = message;
|
|
2112
|
+
this.status = status;
|
|
2113
|
+
this.details = details;
|
|
2160
2114
|
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2115
|
+
};
|
|
2116
|
+
function createCommentsApi(roomId, getAuthValue, config) {
|
|
2117
|
+
async function fetchJson(endpoint, options) {
|
|
2118
|
+
const response = await fetchApi(roomId, endpoint, options);
|
|
2119
|
+
if (!response.ok) {
|
|
2120
|
+
if (response.status >= 400 && response.status < 600) {
|
|
2121
|
+
let error3;
|
|
2122
|
+
try {
|
|
2123
|
+
const errorBody = await response.json();
|
|
2124
|
+
error3 = new CommentsApiError(
|
|
2125
|
+
errorBody.message,
|
|
2126
|
+
response.status,
|
|
2127
|
+
errorBody
|
|
2128
|
+
);
|
|
2129
|
+
} catch {
|
|
2130
|
+
error3 = new CommentsApiError(response.statusText, response.status);
|
|
2167
2131
|
}
|
|
2168
|
-
|
|
2132
|
+
throw error3;
|
|
2169
2133
|
}
|
|
2170
2134
|
}
|
|
2171
|
-
|
|
2135
|
+
let body;
|
|
2136
|
+
try {
|
|
2137
|
+
body = await response.json();
|
|
2138
|
+
} catch {
|
|
2139
|
+
body = {};
|
|
2140
|
+
}
|
|
2141
|
+
return body;
|
|
2172
2142
|
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
case "NoParent": {
|
|
2185
|
-
this._parent = HasParent(newParentNode, newParentKey);
|
|
2186
|
-
return;
|
|
2143
|
+
async function fetchApi(roomId2, endpoint, options) {
|
|
2144
|
+
const authValue = await getAuthValue();
|
|
2145
|
+
const url = new URL(
|
|
2146
|
+
`/v2/c/rooms/${encodeURIComponent(roomId2)}${endpoint}`,
|
|
2147
|
+
config.baseUrl
|
|
2148
|
+
).toString();
|
|
2149
|
+
return await fetch(url, {
|
|
2150
|
+
...options,
|
|
2151
|
+
headers: {
|
|
2152
|
+
...options?.headers,
|
|
2153
|
+
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
2187
2154
|
}
|
|
2188
|
-
|
|
2189
|
-
return assertNever(this.parent, "Unknown state");
|
|
2190
|
-
}
|
|
2155
|
+
});
|
|
2191
2156
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
if (
|
|
2195
|
-
|
|
2157
|
+
async function getThreads() {
|
|
2158
|
+
const response = await fetchApi(roomId, "/threads");
|
|
2159
|
+
if (response.ok) {
|
|
2160
|
+
const json = await response.json();
|
|
2161
|
+
return json.data.map((thread) => convertToThreadData(thread));
|
|
2162
|
+
} else if (response.status === 404) {
|
|
2163
|
+
return [];
|
|
2164
|
+
} else {
|
|
2165
|
+
throw new Error("There was an error while getting threads.");
|
|
2196
2166
|
}
|
|
2197
|
-
pool.addNode(id, crdtAsLiveNode(this));
|
|
2198
|
-
this.__id = id;
|
|
2199
|
-
this.__pool = pool;
|
|
2200
2167
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2168
|
+
async function createThread({
|
|
2169
|
+
metadata,
|
|
2170
|
+
body,
|
|
2171
|
+
commentId,
|
|
2172
|
+
threadId
|
|
2173
|
+
}) {
|
|
2174
|
+
const thread = await fetchJson(
|
|
2175
|
+
"/threads",
|
|
2176
|
+
{
|
|
2177
|
+
method: "POST",
|
|
2178
|
+
headers: {
|
|
2179
|
+
"Content-Type": "application/json"
|
|
2180
|
+
},
|
|
2181
|
+
body: JSON.stringify({
|
|
2182
|
+
id: threadId,
|
|
2183
|
+
comment: {
|
|
2184
|
+
id: commentId,
|
|
2185
|
+
body
|
|
2186
|
+
},
|
|
2187
|
+
metadata
|
|
2188
|
+
})
|
|
2217
2189
|
}
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
}
|
|
2221
|
-
this.__pool = void 0;
|
|
2190
|
+
);
|
|
2191
|
+
return convertToThreadData(thread);
|
|
2222
2192
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
this.parent.node.invalidate();
|
|
2193
|
+
async function editThreadMetadata({
|
|
2194
|
+
metadata,
|
|
2195
|
+
threadId
|
|
2196
|
+
}) {
|
|
2197
|
+
return await fetchJson(
|
|
2198
|
+
`/threads/${encodeURIComponent(threadId)}/metadata`,
|
|
2199
|
+
{
|
|
2200
|
+
method: "POST",
|
|
2201
|
+
headers: {
|
|
2202
|
+
"Content-Type": "application/json"
|
|
2203
|
+
},
|
|
2204
|
+
body: JSON.stringify(metadata)
|
|
2236
2205
|
}
|
|
2237
|
-
|
|
2206
|
+
);
|
|
2238
2207
|
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2208
|
+
async function createComment({
|
|
2209
|
+
threadId,
|
|
2210
|
+
commentId,
|
|
2211
|
+
body
|
|
2212
|
+
}) {
|
|
2213
|
+
const comment = await fetchJson(
|
|
2214
|
+
`/threads/${encodeURIComponent(threadId)}/comments`,
|
|
2215
|
+
{
|
|
2216
|
+
method: "POST",
|
|
2217
|
+
headers: {
|
|
2218
|
+
"Content-Type": "application/json"
|
|
2219
|
+
},
|
|
2220
|
+
body: JSON.stringify({
|
|
2221
|
+
id: commentId,
|
|
2222
|
+
body
|
|
2223
|
+
})
|
|
2224
|
+
}
|
|
2225
|
+
);
|
|
2226
|
+
return convertToCommentData(comment);
|
|
2250
2227
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2228
|
+
async function editComment({
|
|
2229
|
+
threadId,
|
|
2230
|
+
commentId,
|
|
2231
|
+
body
|
|
2232
|
+
}) {
|
|
2233
|
+
const comment = await fetchJson(
|
|
2234
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
2235
|
+
commentId
|
|
2236
|
+
)}`,
|
|
2237
|
+
{
|
|
2238
|
+
method: "POST",
|
|
2239
|
+
headers: {
|
|
2240
|
+
"Content-Type": "application/json"
|
|
2241
|
+
},
|
|
2242
|
+
body: JSON.stringify({
|
|
2243
|
+
body
|
|
2244
|
+
})
|
|
2245
|
+
}
|
|
2246
|
+
);
|
|
2247
|
+
return convertToCommentData(comment);
|
|
2259
2248
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
}
|
|
2273
|
-
function
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2249
|
+
async function deleteComment({
|
|
2250
|
+
threadId,
|
|
2251
|
+
commentId
|
|
2252
|
+
}) {
|
|
2253
|
+
await fetchJson(
|
|
2254
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
2255
|
+
commentId
|
|
2256
|
+
)}`,
|
|
2257
|
+
{
|
|
2258
|
+
method: "DELETE"
|
|
2259
|
+
}
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
async function addReaction({
|
|
2263
|
+
threadId,
|
|
2264
|
+
commentId,
|
|
2265
|
+
emoji
|
|
2266
|
+
}) {
|
|
2267
|
+
const reaction = await fetchJson(
|
|
2268
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
2269
|
+
commentId
|
|
2270
|
+
)}/reactions`,
|
|
2271
|
+
{
|
|
2272
|
+
method: "POST",
|
|
2273
|
+
headers: {
|
|
2274
|
+
"Content-Type": "application/json"
|
|
2275
|
+
},
|
|
2276
|
+
body: JSON.stringify({ emoji })
|
|
2277
|
+
}
|
|
2278
|
+
);
|
|
2279
|
+
return convertToCommentUserReaction(reaction);
|
|
2280
|
+
}
|
|
2281
|
+
async function removeReaction({
|
|
2282
|
+
threadId,
|
|
2283
|
+
commentId,
|
|
2284
|
+
emoji
|
|
2285
|
+
}) {
|
|
2286
|
+
await fetchJson(
|
|
2287
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
2288
|
+
commentId
|
|
2289
|
+
)}/reactions/${encodeURIComponent(emoji)}`,
|
|
2290
|
+
{
|
|
2291
|
+
method: "DELETE"
|
|
2292
|
+
}
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
2295
|
+
return {
|
|
2296
|
+
getThreads,
|
|
2297
|
+
createThread,
|
|
2298
|
+
editThreadMetadata,
|
|
2299
|
+
createComment,
|
|
2300
|
+
editComment,
|
|
2301
|
+
deleteComment,
|
|
2302
|
+
addReaction,
|
|
2303
|
+
removeReaction
|
|
2304
|
+
};
|
|
2285
2305
|
}
|
|
2286
2306
|
|
|
2287
|
-
// src/
|
|
2288
|
-
var
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2307
|
+
// src/lib/position.ts
|
|
2308
|
+
var MIN_CODE = 32;
|
|
2309
|
+
var MAX_CODE = 126;
|
|
2310
|
+
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
2311
|
+
var ZERO = nthDigit(0);
|
|
2312
|
+
var ONE = nthDigit(1);
|
|
2313
|
+
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
2314
|
+
function nthDigit(n) {
|
|
2315
|
+
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
2316
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2317
|
+
throw new Error(`Invalid n value: ${n}`);
|
|
2295
2318
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
return
|
|
2319
|
+
return String.fromCharCode(code);
|
|
2320
|
+
}
|
|
2321
|
+
function makePosition(x, y) {
|
|
2322
|
+
if (x !== void 0 && y !== void 0) {
|
|
2323
|
+
return between(x, y);
|
|
2324
|
+
} else if (x !== void 0) {
|
|
2325
|
+
return after(x);
|
|
2326
|
+
} else if (y !== void 0) {
|
|
2327
|
+
return before(y);
|
|
2328
|
+
} else {
|
|
2329
|
+
return ONE;
|
|
2301
2330
|
}
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2331
|
+
}
|
|
2332
|
+
function before(pos) {
|
|
2333
|
+
const lastIndex = pos.length - 1;
|
|
2334
|
+
for (let i = 0; i <= lastIndex; i++) {
|
|
2335
|
+
const code = pos.charCodeAt(i);
|
|
2336
|
+
if (code <= MIN_CODE) {
|
|
2337
|
+
continue;
|
|
2308
2338
|
}
|
|
2309
|
-
|
|
2310
|
-
{
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
parentId,
|
|
2315
|
-
parentKey,
|
|
2316
|
-
data: this.data
|
|
2339
|
+
if (i === lastIndex) {
|
|
2340
|
+
if (code === MIN_CODE + 1) {
|
|
2341
|
+
return pos.substring(0, i) + ZERO_NINE;
|
|
2342
|
+
} else {
|
|
2343
|
+
return pos.substring(0, i) + String.fromCharCode(code - 1);
|
|
2317
2344
|
}
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
/** @internal */
|
|
2321
|
-
_serialize() {
|
|
2322
|
-
if (this.parent.type !== "HasParent") {
|
|
2323
|
-
throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
2345
|
+
} else {
|
|
2346
|
+
return pos.substring(0, i + 1);
|
|
2324
2347
|
}
|
|
2325
|
-
return {
|
|
2326
|
-
type: 3 /* REGISTER */,
|
|
2327
|
-
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
2328
|
-
parentKey: this.parent.key,
|
|
2329
|
-
data: this.data
|
|
2330
|
-
};
|
|
2331
2348
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2349
|
+
return ONE;
|
|
2350
|
+
}
|
|
2351
|
+
function after(pos) {
|
|
2352
|
+
for (let i = 0; i <= pos.length - 1; i++) {
|
|
2353
|
+
const code = pos.charCodeAt(i);
|
|
2354
|
+
if (code >= MAX_CODE) {
|
|
2355
|
+
continue;
|
|
2356
|
+
}
|
|
2357
|
+
return pos.substring(0, i) + String.fromCharCode(code + 1);
|
|
2335
2358
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2359
|
+
return pos + ONE;
|
|
2360
|
+
}
|
|
2361
|
+
function between(lo, hi) {
|
|
2362
|
+
if (lo < hi) {
|
|
2363
|
+
return _between(lo, hi);
|
|
2364
|
+
} else if (lo > hi) {
|
|
2365
|
+
return _between(hi, lo);
|
|
2366
|
+
} else {
|
|
2367
|
+
throw new Error("Cannot compute value between two equal positions");
|
|
2339
2368
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2369
|
+
}
|
|
2370
|
+
function _between(lo, hi) {
|
|
2371
|
+
let index = 0;
|
|
2372
|
+
const loLen = lo.length;
|
|
2373
|
+
const hiLen = hi.length;
|
|
2374
|
+
while (true) {
|
|
2375
|
+
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
2376
|
+
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
2377
|
+
if (loCode === hiCode) {
|
|
2378
|
+
index++;
|
|
2379
|
+
continue;
|
|
2380
|
+
}
|
|
2381
|
+
if (hiCode - loCode === 1) {
|
|
2382
|
+
const size = index + 1;
|
|
2383
|
+
let prefix = lo.substring(0, size);
|
|
2384
|
+
if (prefix.length < size) {
|
|
2385
|
+
prefix += ZERO.repeat(size - prefix.length);
|
|
2386
|
+
}
|
|
2387
|
+
const suffix = lo.substring(size);
|
|
2388
|
+
const nines = "";
|
|
2389
|
+
return prefix + _between(suffix, nines);
|
|
2390
|
+
} else {
|
|
2391
|
+
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
2392
|
+
}
|
|
2343
2393
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2394
|
+
}
|
|
2395
|
+
function takeN(pos, n) {
|
|
2396
|
+
return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
|
|
2397
|
+
}
|
|
2398
|
+
var MIN_NON_ZERO_CODE = MIN_CODE + 1;
|
|
2399
|
+
function isPos(str) {
|
|
2400
|
+
if (str === "") {
|
|
2401
|
+
return false;
|
|
2352
2402
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2403
|
+
const lastIdx = str.length - 1;
|
|
2404
|
+
const last = str.charCodeAt(lastIdx);
|
|
2405
|
+
if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
|
|
2406
|
+
return false;
|
|
2356
2407
|
}
|
|
2357
|
-
|
|
2358
|
-
|
|
2408
|
+
for (let i = 0; i < lastIdx; i++) {
|
|
2409
|
+
const code = str.charCodeAt(i);
|
|
2410
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2411
|
+
return false;
|
|
2412
|
+
}
|
|
2359
2413
|
}
|
|
2360
|
-
|
|
2414
|
+
return true;
|
|
2415
|
+
}
|
|
2416
|
+
function convertToPos(str) {
|
|
2417
|
+
const codes = [];
|
|
2418
|
+
for (let i = 0; i < str.length; i++) {
|
|
2419
|
+
const code = str.charCodeAt(i);
|
|
2420
|
+
codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
|
|
2421
|
+
}
|
|
2422
|
+
while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
|
|
2423
|
+
codes.length--;
|
|
2424
|
+
}
|
|
2425
|
+
return codes.length > 0 ? String.fromCharCode(...codes) : (
|
|
2426
|
+
// Edge case: the str was a 0-only string, which is invalid. Default back to .1
|
|
2427
|
+
ONE
|
|
2428
|
+
);
|
|
2429
|
+
}
|
|
2430
|
+
function asPos(str) {
|
|
2431
|
+
return isPos(str) ? str : convertToPos(str);
|
|
2432
|
+
}
|
|
2361
2433
|
|
|
2362
|
-
// src/
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2434
|
+
// src/protocol/Op.ts
|
|
2435
|
+
var OpCode = /* @__PURE__ */ ((OpCode2) => {
|
|
2436
|
+
OpCode2[OpCode2["INIT"] = 0] = "INIT";
|
|
2437
|
+
OpCode2[OpCode2["SET_PARENT_KEY"] = 1] = "SET_PARENT_KEY";
|
|
2438
|
+
OpCode2[OpCode2["CREATE_LIST"] = 2] = "CREATE_LIST";
|
|
2439
|
+
OpCode2[OpCode2["UPDATE_OBJECT"] = 3] = "UPDATE_OBJECT";
|
|
2440
|
+
OpCode2[OpCode2["CREATE_OBJECT"] = 4] = "CREATE_OBJECT";
|
|
2441
|
+
OpCode2[OpCode2["DELETE_CRDT"] = 5] = "DELETE_CRDT";
|
|
2442
|
+
OpCode2[OpCode2["DELETE_OBJECT_KEY"] = 6] = "DELETE_OBJECT_KEY";
|
|
2443
|
+
OpCode2[OpCode2["CREATE_MAP"] = 7] = "CREATE_MAP";
|
|
2444
|
+
OpCode2[OpCode2["CREATE_REGISTER"] = 8] = "CREATE_REGISTER";
|
|
2445
|
+
return OpCode2;
|
|
2446
|
+
})(OpCode || {});
|
|
2447
|
+
function isAckOp(op) {
|
|
2448
|
+
return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
|
|
2367
2449
|
}
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2450
|
+
|
|
2451
|
+
// src/crdts/AbstractCrdt.ts
|
|
2452
|
+
function crdtAsLiveNode(value) {
|
|
2453
|
+
return value;
|
|
2454
|
+
}
|
|
2455
|
+
function HasParent(node, key, pos = asPos(key)) {
|
|
2456
|
+
return Object.freeze({ type: "HasParent", node, key, pos });
|
|
2457
|
+
}
|
|
2458
|
+
var NoParent = Object.freeze({ type: "NoParent" });
|
|
2459
|
+
function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
2460
|
+
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
2461
|
+
}
|
|
2462
|
+
var AbstractCrdt = class {
|
|
2463
|
+
constructor() {
|
|
2464
|
+
/** @internal */
|
|
2465
|
+
this._parent = NoParent;
|
|
2382
2466
|
}
|
|
2383
2467
|
/** @internal */
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
list._insertAndSort(child);
|
|
2468
|
+
_getParentKeyOrThrow() {
|
|
2469
|
+
switch (this.parent.type) {
|
|
2470
|
+
case "HasParent":
|
|
2471
|
+
return this.parent.key;
|
|
2472
|
+
case "NoParent":
|
|
2473
|
+
throw new Error("Parent key is missing");
|
|
2474
|
+
case "Orphaned":
|
|
2475
|
+
return this.parent.oldKey;
|
|
2476
|
+
default:
|
|
2477
|
+
return assertNever(this.parent, "Unknown state");
|
|
2395
2478
|
}
|
|
2396
|
-
return list;
|
|
2397
2479
|
}
|
|
2398
|
-
/**
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
throw new Error("Cannot serialize item is not attached");
|
|
2410
|
-
}
|
|
2411
|
-
const ops = [];
|
|
2412
|
-
const op = {
|
|
2413
|
-
id: this._id,
|
|
2414
|
-
opId: pool?.generateOpId(),
|
|
2415
|
-
type: 2 /* CREATE_LIST */,
|
|
2416
|
-
parentId,
|
|
2417
|
-
parentKey
|
|
2418
|
-
};
|
|
2419
|
-
ops.push(op);
|
|
2420
|
-
for (const item of this._items) {
|
|
2421
|
-
const parentKey2 = item._getParentKeyOrThrow();
|
|
2422
|
-
const childOps = HACK_addIntentAndDeletedIdToOperation(
|
|
2423
|
-
item._toOps(this._id, parentKey2, pool),
|
|
2424
|
-
void 0
|
|
2425
|
-
);
|
|
2426
|
-
const childOpId = childOps[0].opId;
|
|
2427
|
-
if (childOpId !== void 0) {
|
|
2428
|
-
this._unacknowledgedSets.set(parentKey2, childOpId);
|
|
2429
|
-
}
|
|
2430
|
-
ops.push(...childOps);
|
|
2480
|
+
/** @internal */
|
|
2481
|
+
get _parentPos() {
|
|
2482
|
+
switch (this.parent.type) {
|
|
2483
|
+
case "HasParent":
|
|
2484
|
+
return this.parent.pos;
|
|
2485
|
+
case "NoParent":
|
|
2486
|
+
throw new Error("Parent key is missing");
|
|
2487
|
+
case "Orphaned":
|
|
2488
|
+
return this.parent.oldPos;
|
|
2489
|
+
default:
|
|
2490
|
+
return assertNever(this.parent, "Unknown state");
|
|
2431
2491
|
}
|
|
2432
|
-
return ops;
|
|
2433
2492
|
}
|
|
2434
|
-
/**
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
this._items.push(item);
|
|
2441
|
-
this._sortItems();
|
|
2493
|
+
/** @internal */
|
|
2494
|
+
get _pool() {
|
|
2495
|
+
return this.__pool;
|
|
2496
|
+
}
|
|
2497
|
+
get roomId() {
|
|
2498
|
+
return this.__pool ? this.__pool.roomId : null;
|
|
2442
2499
|
}
|
|
2443
2500
|
/** @internal */
|
|
2444
|
-
|
|
2445
|
-
this.
|
|
2446
|
-
this.invalidate();
|
|
2501
|
+
get _id() {
|
|
2502
|
+
return this.__id;
|
|
2447
2503
|
}
|
|
2448
2504
|
/** @internal */
|
|
2449
|
-
|
|
2450
|
-
return this.
|
|
2451
|
-
(item) => item._getParentKeyOrThrow() === position
|
|
2452
|
-
);
|
|
2505
|
+
get parent() {
|
|
2506
|
+
return this._parent;
|
|
2453
2507
|
}
|
|
2454
2508
|
/** @internal */
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2509
|
+
get _parentKey() {
|
|
2510
|
+
switch (this.parent.type) {
|
|
2511
|
+
case "HasParent":
|
|
2512
|
+
return this.parent.key;
|
|
2513
|
+
case "NoParent":
|
|
2514
|
+
return null;
|
|
2515
|
+
case "Orphaned":
|
|
2516
|
+
return this.parent.oldKey;
|
|
2517
|
+
default:
|
|
2518
|
+
return assertNever(this.parent, "Unknown state");
|
|
2459
2519
|
}
|
|
2460
2520
|
}
|
|
2461
2521
|
/** @internal */
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2522
|
+
_apply(op, _isLocal) {
|
|
2523
|
+
switch (op.type) {
|
|
2524
|
+
case 5 /* DELETE_CRDT */: {
|
|
2525
|
+
if (this.parent.type === "HasParent") {
|
|
2526
|
+
return this.parent.node._detachChild(crdtAsLiveNode(this));
|
|
2527
|
+
}
|
|
2528
|
+
return { modified: false };
|
|
2529
|
+
}
|
|
2466
2530
|
}
|
|
2531
|
+
return { modified: false };
|
|
2467
2532
|
}
|
|
2468
2533
|
/** @internal */
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
const deletedId = op.deletedId;
|
|
2478
|
-
const indexOfItemWithSamePosition = this._indexOfPosition(key);
|
|
2479
|
-
if (indexOfItemWithSamePosition !== -1) {
|
|
2480
|
-
const itemWithSamePosition = this._items[indexOfItemWithSamePosition];
|
|
2481
|
-
if (itemWithSamePosition._id === deletedId) {
|
|
2482
|
-
itemWithSamePosition._detach();
|
|
2483
|
-
this._items[indexOfItemWithSamePosition] = child;
|
|
2484
|
-
return {
|
|
2485
|
-
modified: makeUpdate(this, [
|
|
2486
|
-
setDelta(indexOfItemWithSamePosition, child)
|
|
2487
|
-
]),
|
|
2488
|
-
reverse: []
|
|
2489
|
-
};
|
|
2490
|
-
} else {
|
|
2491
|
-
this._implicitlyDeletedItems.add(itemWithSamePosition);
|
|
2492
|
-
this._items[indexOfItemWithSamePosition] = child;
|
|
2493
|
-
const delta = [
|
|
2494
|
-
setDelta(indexOfItemWithSamePosition, child)
|
|
2495
|
-
];
|
|
2496
|
-
const deleteDelta2 = this._detachItemAssociatedToSetOperation(
|
|
2497
|
-
op.deletedId
|
|
2498
|
-
);
|
|
2499
|
-
if (deleteDelta2) {
|
|
2500
|
-
delta.push(deleteDelta2);
|
|
2534
|
+
_setParentLink(newParentNode, newParentKey) {
|
|
2535
|
+
switch (this.parent.type) {
|
|
2536
|
+
case "HasParent":
|
|
2537
|
+
if (this.parent.node !== newParentNode) {
|
|
2538
|
+
throw new Error("Cannot set parent: node already has a parent");
|
|
2539
|
+
} else {
|
|
2540
|
+
this._parent = HasParent(newParentNode, newParentKey);
|
|
2541
|
+
return;
|
|
2501
2542
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
}
|
|
2507
|
-
} else {
|
|
2508
|
-
const updates = [];
|
|
2509
|
-
const deleteDelta2 = this._detachItemAssociatedToSetOperation(
|
|
2510
|
-
op.deletedId
|
|
2511
|
-
);
|
|
2512
|
-
if (deleteDelta2) {
|
|
2513
|
-
updates.push(deleteDelta2);
|
|
2543
|
+
case "Orphaned":
|
|
2544
|
+
case "NoParent": {
|
|
2545
|
+
this._parent = HasParent(newParentNode, newParentKey);
|
|
2546
|
+
return;
|
|
2514
2547
|
}
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
return {
|
|
2518
|
-
reverse: [],
|
|
2519
|
-
modified: makeUpdate(this, updates)
|
|
2520
|
-
};
|
|
2548
|
+
default:
|
|
2549
|
+
return assertNever(this.parent, "Unknown state");
|
|
2521
2550
|
}
|
|
2522
2551
|
}
|
|
2523
2552
|
/** @internal */
|
|
2524
|
-
|
|
2525
|
-
if (this.
|
|
2526
|
-
throw new Error("
|
|
2527
|
-
}
|
|
2528
|
-
const delta = [];
|
|
2529
|
-
const deletedDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
2530
|
-
if (deletedDelta) {
|
|
2531
|
-
delta.push(deletedDelta);
|
|
2553
|
+
_attach(id, pool) {
|
|
2554
|
+
if (this.__id || this.__pool) {
|
|
2555
|
+
throw new Error("Cannot attach node: already attached");
|
|
2532
2556
|
}
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2557
|
+
pool.addNode(id, crdtAsLiveNode(this));
|
|
2558
|
+
this.__id = id;
|
|
2559
|
+
this.__pool = pool;
|
|
2560
|
+
}
|
|
2561
|
+
/** @internal */
|
|
2562
|
+
_detach() {
|
|
2563
|
+
if (this.__pool && this.__id) {
|
|
2564
|
+
this.__pool.deleteNode(this.__id);
|
|
2540
2565
|
}
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
return {
|
|
2546
|
-
modified: delta.length > 0 ? makeUpdate(this, delta) : false,
|
|
2547
|
-
reverse: []
|
|
2548
|
-
};
|
|
2549
|
-
}
|
|
2550
|
-
if (indexOfItemWithSamePosition !== -1) {
|
|
2551
|
-
this._implicitlyDeletedItems.add(
|
|
2552
|
-
this._items[indexOfItemWithSamePosition]
|
|
2553
|
-
);
|
|
2554
|
-
this._items.splice(indexOfItemWithSamePosition, 1);
|
|
2555
|
-
delta.push(deleteDelta(indexOfItemWithSamePosition));
|
|
2566
|
+
switch (this.parent.type) {
|
|
2567
|
+
case "HasParent": {
|
|
2568
|
+
this._parent = Orphaned(this.parent.key, this.parent.pos);
|
|
2569
|
+
break;
|
|
2556
2570
|
}
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
const newIndex = this._items.indexOf(existingItem);
|
|
2561
|
-
if (newIndex !== previousIndex) {
|
|
2562
|
-
delta.push(moveDelta(previousIndex, newIndex, existingItem));
|
|
2571
|
+
case "NoParent": {
|
|
2572
|
+
this._parent = NoParent;
|
|
2573
|
+
break;
|
|
2563
2574
|
}
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
reverse: []
|
|
2567
|
-
};
|
|
2568
|
-
} else {
|
|
2569
|
-
const orphan = this._pool.getNode(op.id);
|
|
2570
|
-
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
2571
|
-
orphan._setParentLink(this, op.parentKey);
|
|
2572
|
-
this._implicitlyDeletedItems.delete(orphan);
|
|
2573
|
-
this._insertAndSort(orphan);
|
|
2574
|
-
const recreatedItemIndex = this._items.indexOf(orphan);
|
|
2575
|
-
return {
|
|
2576
|
-
modified: makeUpdate(this, [
|
|
2577
|
-
// If there is an item at this position, update is a set, else it's an insert
|
|
2578
|
-
indexOfItemWithSamePosition === -1 ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan),
|
|
2579
|
-
...delta
|
|
2580
|
-
]),
|
|
2581
|
-
reverse: []
|
|
2582
|
-
};
|
|
2583
|
-
} else {
|
|
2584
|
-
if (indexOfItemWithSamePosition !== -1) {
|
|
2585
|
-
this._items.splice(indexOfItemWithSamePosition, 1);
|
|
2586
|
-
}
|
|
2587
|
-
const { newItem, newIndex } = this._createAttachItemAndSort(
|
|
2588
|
-
op,
|
|
2589
|
-
op.parentKey
|
|
2590
|
-
);
|
|
2591
|
-
return {
|
|
2592
|
-
modified: makeUpdate(this, [
|
|
2593
|
-
// If there is an item at this position, update is a set, else it's an insert
|
|
2594
|
-
indexOfItemWithSamePosition === -1 ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem),
|
|
2595
|
-
...delta
|
|
2596
|
-
]),
|
|
2597
|
-
reverse: []
|
|
2598
|
-
};
|
|
2575
|
+
case "Orphaned": {
|
|
2576
|
+
break;
|
|
2599
2577
|
}
|
|
2578
|
+
default:
|
|
2579
|
+
assertNever(this.parent, "Unknown state");
|
|
2600
2580
|
}
|
|
2581
|
+
this.__pool = void 0;
|
|
2601
2582
|
}
|
|
2602
2583
|
/**
|
|
2603
|
-
* Returns the update delta of the deletion or null
|
|
2604
2584
|
* @internal
|
|
2585
|
+
*
|
|
2586
|
+
* Clear the Immutable cache, so that the next call to `.toImmutable()` will
|
|
2587
|
+
* recompute the equivalent Immutable value again. Call this after every
|
|
2588
|
+
* mutation to the Live node.
|
|
2605
2589
|
*/
|
|
2606
|
-
|
|
2607
|
-
if (
|
|
2608
|
-
|
|
2590
|
+
invalidate() {
|
|
2591
|
+
if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
|
|
2592
|
+
this._cachedImmutable = void 0;
|
|
2593
|
+
this._cachedTreeNode = void 0;
|
|
2594
|
+
if (this.parent.type === "HasParent") {
|
|
2595
|
+
this.parent.node.invalidate();
|
|
2596
|
+
}
|
|
2609
2597
|
}
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2598
|
+
}
|
|
2599
|
+
/**
|
|
2600
|
+
* @internal
|
|
2601
|
+
*
|
|
2602
|
+
* Return an snapshot of this Live tree for use in DevTools.
|
|
2603
|
+
*/
|
|
2604
|
+
toTreeNode(key) {
|
|
2605
|
+
if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
|
|
2606
|
+
this._cachedTreeNodeKey = key;
|
|
2607
|
+
this._cachedTreeNode = this._toTreeNode(key);
|
|
2613
2608
|
}
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2609
|
+
return this._cachedTreeNode;
|
|
2610
|
+
}
|
|
2611
|
+
/**
|
|
2612
|
+
* Return an immutable snapshot of this Live node and its children.
|
|
2613
|
+
*/
|
|
2614
|
+
toImmutable() {
|
|
2615
|
+
if (this._cachedImmutable === void 0) {
|
|
2616
|
+
this._cachedImmutable = this._toImmutable();
|
|
2617
2617
|
}
|
|
2618
|
-
return
|
|
2618
|
+
return this._cachedImmutable;
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
|
|
2622
|
+
// src/protocol/SerializedCrdt.ts
|
|
2623
|
+
var CrdtType = /* @__PURE__ */ ((CrdtType2) => {
|
|
2624
|
+
CrdtType2[CrdtType2["OBJECT"] = 0] = "OBJECT";
|
|
2625
|
+
CrdtType2[CrdtType2["LIST"] = 1] = "LIST";
|
|
2626
|
+
CrdtType2[CrdtType2["MAP"] = 2] = "MAP";
|
|
2627
|
+
CrdtType2[CrdtType2["REGISTER"] = 3] = "REGISTER";
|
|
2628
|
+
return CrdtType2;
|
|
2629
|
+
})(CrdtType || {});
|
|
2630
|
+
function isRootCrdt(crdt) {
|
|
2631
|
+
return crdt.type === 0 /* OBJECT */ && !isChildCrdt(crdt);
|
|
2632
|
+
}
|
|
2633
|
+
function isChildCrdt(crdt) {
|
|
2634
|
+
return crdt.parentId !== void 0 && crdt.parentKey !== void 0;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
// src/lib/nanoid.ts
|
|
2638
|
+
function nanoid(length = 7) {
|
|
2639
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,./;[]~!@#$%&*()_+=-";
|
|
2640
|
+
const len = alphabet.length;
|
|
2641
|
+
return Array.from(
|
|
2642
|
+
{ length },
|
|
2643
|
+
() => alphabet.charAt(Math.floor(Math.random() * len))
|
|
2644
|
+
).join("");
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
// src/crdts/LiveRegister.ts
|
|
2648
|
+
var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
2649
|
+
constructor(data) {
|
|
2650
|
+
super();
|
|
2651
|
+
this._data = data;
|
|
2652
|
+
}
|
|
2653
|
+
get data() {
|
|
2654
|
+
return this._data;
|
|
2619
2655
|
}
|
|
2620
2656
|
/** @internal */
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
const key = asPos(op.parentKey);
|
|
2626
|
-
const existingItemIndex = this._indexOfPosition(key);
|
|
2627
|
-
if (existingItemIndex !== -1) {
|
|
2628
|
-
this._shiftItemPosition(existingItemIndex, key);
|
|
2629
|
-
}
|
|
2630
|
-
const { newItem, newIndex } = this._createAttachItemAndSort(op, key);
|
|
2631
|
-
return {
|
|
2632
|
-
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
2633
|
-
reverse: []
|
|
2634
|
-
};
|
|
2657
|
+
static _deserialize([id, item], _parentToChildren, pool) {
|
|
2658
|
+
const register = new _LiveRegister(item.data);
|
|
2659
|
+
register._attach(id, pool);
|
|
2660
|
+
return register;
|
|
2635
2661
|
}
|
|
2636
2662
|
/** @internal */
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
if (existingItem._parentKey === key) {
|
|
2643
|
-
return {
|
|
2644
|
-
modified: false
|
|
2645
|
-
};
|
|
2646
|
-
} else {
|
|
2647
|
-
const oldPositionIndex = this._items.indexOf(existingItem);
|
|
2648
|
-
if (itemIndexAtPosition !== -1) {
|
|
2649
|
-
this._shiftItemPosition(itemIndexAtPosition, key);
|
|
2650
|
-
}
|
|
2651
|
-
existingItem._setParentLink(this, key);
|
|
2652
|
-
this._sortItems();
|
|
2653
|
-
const newIndex = this._indexOfPosition(key);
|
|
2654
|
-
if (newIndex === oldPositionIndex) {
|
|
2655
|
-
return { modified: false };
|
|
2656
|
-
}
|
|
2657
|
-
return {
|
|
2658
|
-
modified: makeUpdate(this, [
|
|
2659
|
-
moveDelta(oldPositionIndex, newIndex, existingItem)
|
|
2660
|
-
]),
|
|
2661
|
-
reverse: []
|
|
2662
|
-
};
|
|
2663
|
-
}
|
|
2664
|
-
} else {
|
|
2665
|
-
const orphan = nn(this._pool).getNode(op.id);
|
|
2666
|
-
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
2667
|
-
orphan._setParentLink(this, key);
|
|
2668
|
-
this._implicitlyDeletedItems.delete(orphan);
|
|
2669
|
-
this._insertAndSort(orphan);
|
|
2670
|
-
const newIndex = this._indexOfPosition(key);
|
|
2671
|
-
return {
|
|
2672
|
-
modified: makeUpdate(this, [insertDelta(newIndex, orphan)]),
|
|
2673
|
-
reverse: []
|
|
2674
|
-
};
|
|
2675
|
-
} else {
|
|
2676
|
-
if (itemIndexAtPosition !== -1) {
|
|
2677
|
-
this._shiftItemPosition(itemIndexAtPosition, key);
|
|
2678
|
-
}
|
|
2679
|
-
const { newItem, newIndex } = this._createAttachItemAndSort(op, key);
|
|
2680
|
-
return {
|
|
2681
|
-
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
2682
|
-
reverse: []
|
|
2683
|
-
};
|
|
2684
|
-
}
|
|
2663
|
+
_toOps(parentId, parentKey, pool) {
|
|
2664
|
+
if (this._id === void 0) {
|
|
2665
|
+
throw new Error(
|
|
2666
|
+
"Cannot serialize register if parentId or parentKey is undefined"
|
|
2667
|
+
);
|
|
2685
2668
|
}
|
|
2669
|
+
return [
|
|
2670
|
+
{
|
|
2671
|
+
type: 8 /* CREATE_REGISTER */,
|
|
2672
|
+
opId: pool?.generateOpId(),
|
|
2673
|
+
id: this._id,
|
|
2674
|
+
parentId,
|
|
2675
|
+
parentKey,
|
|
2676
|
+
data: this.data
|
|
2677
|
+
}
|
|
2678
|
+
];
|
|
2686
2679
|
}
|
|
2687
2680
|
/** @internal */
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
if (this._pool?.getNode(id) !== void 0) {
|
|
2692
|
-
return { modified: false };
|
|
2693
|
-
}
|
|
2694
|
-
child._attach(id, nn(this._pool));
|
|
2695
|
-
child._setParentLink(this, key);
|
|
2696
|
-
const existingItemIndex = this._indexOfPosition(key);
|
|
2697
|
-
let newKey = key;
|
|
2698
|
-
if (existingItemIndex !== -1) {
|
|
2699
|
-
const before2 = this._items[existingItemIndex]?._parentPos;
|
|
2700
|
-
const after2 = this._items[existingItemIndex + 1]?._parentPos;
|
|
2701
|
-
newKey = makePosition(before2, after2);
|
|
2702
|
-
child._setParentLink(this, newKey);
|
|
2681
|
+
_serialize() {
|
|
2682
|
+
if (this.parent.type !== "HasParent") {
|
|
2683
|
+
throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
2703
2684
|
}
|
|
2704
|
-
this._insertAndSort(child);
|
|
2705
|
-
const newIndex = this._indexOfPosition(newKey);
|
|
2706
2685
|
return {
|
|
2707
|
-
|
|
2708
|
-
|
|
2686
|
+
type: 3 /* REGISTER */,
|
|
2687
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
2688
|
+
parentKey: this.parent.key,
|
|
2689
|
+
data: this.data
|
|
2709
2690
|
};
|
|
2710
2691
|
}
|
|
2711
2692
|
/** @internal */
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
const child = creationOpToLiveNode(op);
|
|
2715
|
-
if (this._pool?.getNode(id) !== void 0) {
|
|
2716
|
-
return { modified: false };
|
|
2717
|
-
}
|
|
2718
|
-
this._unacknowledgedSets.set(key, nn(op.opId));
|
|
2719
|
-
const indexOfItemWithSameKey = this._indexOfPosition(key);
|
|
2720
|
-
child._attach(id, nn(this._pool));
|
|
2721
|
-
child._setParentLink(this, key);
|
|
2722
|
-
const newKey = key;
|
|
2723
|
-
if (indexOfItemWithSameKey !== -1) {
|
|
2724
|
-
const existingItem = this._items[indexOfItemWithSameKey];
|
|
2725
|
-
existingItem._detach();
|
|
2726
|
-
this._items[indexOfItemWithSameKey] = child;
|
|
2727
|
-
const reverse = HACK_addIntentAndDeletedIdToOperation(
|
|
2728
|
-
existingItem._toOps(nn(this._id), key, this._pool),
|
|
2729
|
-
op.id
|
|
2730
|
-
);
|
|
2731
|
-
const delta = [setDelta(indexOfItemWithSameKey, child)];
|
|
2732
|
-
const deletedDelta = this._detachItemAssociatedToSetOperation(
|
|
2733
|
-
op.deletedId
|
|
2734
|
-
);
|
|
2735
|
-
if (deletedDelta) {
|
|
2736
|
-
delta.push(deletedDelta);
|
|
2737
|
-
}
|
|
2738
|
-
return {
|
|
2739
|
-
modified: makeUpdate(this, delta),
|
|
2740
|
-
reverse
|
|
2741
|
-
};
|
|
2742
|
-
} else {
|
|
2743
|
-
this._insertAndSort(child);
|
|
2744
|
-
this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
2745
|
-
const newIndex = this._indexOfPosition(newKey);
|
|
2746
|
-
return {
|
|
2747
|
-
reverse: [{ type: 5 /* DELETE_CRDT */, id }],
|
|
2748
|
-
modified: makeUpdate(this, [insertDelta(newIndex, child)])
|
|
2749
|
-
};
|
|
2750
|
-
}
|
|
2693
|
+
_attachChild(_op) {
|
|
2694
|
+
throw new Error("Method not implemented.");
|
|
2751
2695
|
}
|
|
2752
2696
|
/** @internal */
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
throw new Error("Can't attach child if managed pool is not present");
|
|
2756
|
-
}
|
|
2757
|
-
let result;
|
|
2758
|
-
if (op.intent === "set") {
|
|
2759
|
-
if (source === 1 /* REMOTE */) {
|
|
2760
|
-
result = this._applySetRemote(op);
|
|
2761
|
-
} else if (source === 2 /* ACK */) {
|
|
2762
|
-
result = this._applySetAck(op);
|
|
2763
|
-
} else {
|
|
2764
|
-
result = this._applySetUndoRedo(op);
|
|
2765
|
-
}
|
|
2766
|
-
} else {
|
|
2767
|
-
if (source === 1 /* REMOTE */) {
|
|
2768
|
-
result = this._applyRemoteInsert(op);
|
|
2769
|
-
} else if (source === 2 /* ACK */) {
|
|
2770
|
-
result = this._applyInsertAck(op);
|
|
2771
|
-
} else {
|
|
2772
|
-
result = this._applyInsertUndoRedo(op);
|
|
2773
|
-
}
|
|
2774
|
-
}
|
|
2775
|
-
if (result.modified !== false) {
|
|
2776
|
-
this.invalidate();
|
|
2777
|
-
}
|
|
2778
|
-
return result;
|
|
2697
|
+
_detachChild(_crdt) {
|
|
2698
|
+
throw new Error("Method not implemented.");
|
|
2779
2699
|
}
|
|
2780
2700
|
/** @internal */
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
const parentKey = nn(child._parentKey);
|
|
2784
|
-
const reverse = child._toOps(nn(this._id), parentKey, this._pool);
|
|
2785
|
-
const indexToDelete = this._items.indexOf(child);
|
|
2786
|
-
if (indexToDelete === -1) {
|
|
2787
|
-
return {
|
|
2788
|
-
modified: false
|
|
2789
|
-
};
|
|
2790
|
-
}
|
|
2791
|
-
this._items.splice(indexToDelete, 1);
|
|
2792
|
-
this.invalidate();
|
|
2793
|
-
child._detach();
|
|
2794
|
-
return {
|
|
2795
|
-
modified: makeUpdate(this, [deleteDelta(indexToDelete)]),
|
|
2796
|
-
reverse
|
|
2797
|
-
};
|
|
2798
|
-
}
|
|
2799
|
-
return { modified: false };
|
|
2701
|
+
_apply(op, isLocal) {
|
|
2702
|
+
return super._apply(op, isLocal);
|
|
2800
2703
|
}
|
|
2801
2704
|
/** @internal */
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
);
|
|
2839
|
-
const previousIndex = this._items.indexOf(child);
|
|
2840
|
-
child._setParentLink(this, newKey);
|
|
2841
|
-
this._sortItems();
|
|
2842
|
-
const newIndex = this._items.indexOf(child);
|
|
2843
|
-
if (newIndex === previousIndex) {
|
|
2844
|
-
return {
|
|
2845
|
-
modified: false
|
|
2846
|
-
};
|
|
2847
|
-
}
|
|
2848
|
-
return {
|
|
2849
|
-
modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
|
|
2850
|
-
reverse: []
|
|
2851
|
-
};
|
|
2705
|
+
_toTreeNode(key) {
|
|
2706
|
+
return {
|
|
2707
|
+
type: "Json",
|
|
2708
|
+
id: this._id ?? nanoid(),
|
|
2709
|
+
key,
|
|
2710
|
+
payload: this._data
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
2713
|
+
/** @internal */
|
|
2714
|
+
_toImmutable() {
|
|
2715
|
+
return this._data;
|
|
2716
|
+
}
|
|
2717
|
+
clone() {
|
|
2718
|
+
return deepClone(this.data);
|
|
2719
|
+
}
|
|
2720
|
+
};
|
|
2721
|
+
|
|
2722
|
+
// src/crdts/LiveList.ts
|
|
2723
|
+
function compareNodePosition(itemA, itemB) {
|
|
2724
|
+
const posA = itemA._parentPos;
|
|
2725
|
+
const posB = itemB._parentPos;
|
|
2726
|
+
return posA === posB ? 0 : posA < posB ? -1 : 1;
|
|
2727
|
+
}
|
|
2728
|
+
var LiveList = class _LiveList extends AbstractCrdt {
|
|
2729
|
+
constructor(items = []) {
|
|
2730
|
+
super();
|
|
2731
|
+
this._items = [];
|
|
2732
|
+
this._implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
|
|
2733
|
+
this._unacknowledgedSets = /* @__PURE__ */ new Map();
|
|
2734
|
+
let position = void 0;
|
|
2735
|
+
for (const item of items) {
|
|
2736
|
+
const newPosition = makePosition(position);
|
|
2737
|
+
const node = lsonToLiveNode(item);
|
|
2738
|
+
node._setParentLink(this, newPosition);
|
|
2739
|
+
this._items.push(node);
|
|
2740
|
+
position = newPosition;
|
|
2852
2741
|
}
|
|
2853
2742
|
}
|
|
2854
2743
|
/** @internal */
|
|
2855
|
-
|
|
2856
|
-
const
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2744
|
+
static _deserialize([id], parentToChildren, pool) {
|
|
2745
|
+
const list = new _LiveList();
|
|
2746
|
+
list._attach(id, pool);
|
|
2747
|
+
const children = parentToChildren.get(id);
|
|
2748
|
+
if (children === void 0) {
|
|
2749
|
+
return list;
|
|
2750
|
+
}
|
|
2751
|
+
for (const [id2, crdt] of children) {
|
|
2752
|
+
const child = deserialize([id2, crdt], parentToChildren, pool);
|
|
2753
|
+
child._setParentLink(list, crdt.parentKey);
|
|
2754
|
+
list._insertAndSort(child);
|
|
2755
|
+
}
|
|
2756
|
+
return list;
|
|
2757
|
+
}
|
|
2758
|
+
/**
|
|
2759
|
+
* @internal
|
|
2760
|
+
* This function assumes that the resulting ops will be sent to the server if they have an 'opId'
|
|
2761
|
+
* so we mutate _unacknowledgedSets to avoid potential flickering
|
|
2762
|
+
* https://github.com/liveblocks/liveblocks/pull/1177
|
|
2763
|
+
*
|
|
2764
|
+
* This is quite unintuitive and should disappear as soon as
|
|
2765
|
+
* we introduce an explicit LiveList.Set operation
|
|
2766
|
+
*/
|
|
2767
|
+
_toOps(parentId, parentKey, pool) {
|
|
2768
|
+
if (this._id === void 0) {
|
|
2769
|
+
throw new Error("Cannot serialize item is not attached");
|
|
2770
|
+
}
|
|
2771
|
+
const ops = [];
|
|
2772
|
+
const op = {
|
|
2773
|
+
id: this._id,
|
|
2774
|
+
opId: pool?.generateOpId(),
|
|
2775
|
+
type: 2 /* CREATE_LIST */,
|
|
2776
|
+
parentId,
|
|
2777
|
+
parentKey
|
|
2778
|
+
};
|
|
2779
|
+
ops.push(op);
|
|
2780
|
+
for (const item of this._items) {
|
|
2781
|
+
const parentKey2 = item._getParentKeyOrThrow();
|
|
2782
|
+
const childOps = HACK_addIntentAndDeletedIdToOperation(
|
|
2783
|
+
item._toOps(this._id, parentKey2, pool),
|
|
2784
|
+
void 0
|
|
2785
|
+
);
|
|
2786
|
+
const childOpId = childOps[0].opId;
|
|
2787
|
+
if (childOpId !== void 0) {
|
|
2788
|
+
this._unacknowledgedSets.set(parentKey2, childOpId);
|
|
2789
|
+
}
|
|
2790
|
+
ops.push(...childOps);
|
|
2791
|
+
}
|
|
2792
|
+
return ops;
|
|
2793
|
+
}
|
|
2794
|
+
/**
|
|
2795
|
+
* @internal
|
|
2796
|
+
*
|
|
2797
|
+
* Adds a new item into the sorted list, in the correct position.
|
|
2798
|
+
*/
|
|
2799
|
+
_insertAndSort(item) {
|
|
2800
|
+
this._items.push(item);
|
|
2801
|
+
this._sortItems();
|
|
2802
|
+
}
|
|
2803
|
+
/** @internal */
|
|
2804
|
+
_sortItems() {
|
|
2805
|
+
this._items.sort(compareNodePosition);
|
|
2806
|
+
this.invalidate();
|
|
2807
|
+
}
|
|
2808
|
+
/** @internal */
|
|
2809
|
+
_indexOfPosition(position) {
|
|
2810
|
+
return this._items.findIndex(
|
|
2811
|
+
(item) => item._getParentKeyOrThrow() === position
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
/** @internal */
|
|
2815
|
+
_attach(id, pool) {
|
|
2816
|
+
super._attach(id, pool);
|
|
2817
|
+
for (const item of this._items) {
|
|
2818
|
+
item._attach(pool.generateId(), pool);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
/** @internal */
|
|
2822
|
+
_detach() {
|
|
2823
|
+
super._detach();
|
|
2824
|
+
for (const item of this._items) {
|
|
2825
|
+
item._detach();
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
/** @internal */
|
|
2829
|
+
_applySetRemote(op) {
|
|
2830
|
+
if (this._pool === void 0) {
|
|
2831
|
+
throw new Error("Can't attach child if managed pool is not present");
|
|
2832
|
+
}
|
|
2833
|
+
const { id, parentKey: key } = op;
|
|
2834
|
+
const child = creationOpToLiveNode(op);
|
|
2835
|
+
child._attach(id, this._pool);
|
|
2836
|
+
child._setParentLink(this, key);
|
|
2837
|
+
const deletedId = op.deletedId;
|
|
2838
|
+
const indexOfItemWithSamePosition = this._indexOfPosition(key);
|
|
2839
|
+
if (indexOfItemWithSamePosition !== -1) {
|
|
2840
|
+
const itemWithSamePosition = this._items[indexOfItemWithSamePosition];
|
|
2841
|
+
if (itemWithSamePosition._id === deletedId) {
|
|
2842
|
+
itemWithSamePosition._detach();
|
|
2843
|
+
this._items[indexOfItemWithSamePosition] = child;
|
|
2844
|
+
return {
|
|
2845
|
+
modified: makeUpdate(this, [
|
|
2846
|
+
setDelta(indexOfItemWithSamePosition, child)
|
|
2847
|
+
]),
|
|
2848
|
+
reverse: []
|
|
2849
|
+
};
|
|
2850
|
+
} else {
|
|
2851
|
+
this._implicitlyDeletedItems.add(itemWithSamePosition);
|
|
2852
|
+
this._items[indexOfItemWithSamePosition] = child;
|
|
2853
|
+
const delta = [
|
|
2854
|
+
setDelta(indexOfItemWithSamePosition, child)
|
|
2855
|
+
];
|
|
2856
|
+
const deleteDelta2 = this._detachItemAssociatedToSetOperation(
|
|
2857
|
+
op.deletedId
|
|
2864
2858
|
);
|
|
2859
|
+
if (deleteDelta2) {
|
|
2860
|
+
delta.push(deleteDelta2);
|
|
2861
|
+
}
|
|
2862
|
+
return {
|
|
2863
|
+
modified: makeUpdate(this, delta),
|
|
2864
|
+
reverse: []
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
} else {
|
|
2868
|
+
const updates = [];
|
|
2869
|
+
const deleteDelta2 = this._detachItemAssociatedToSetOperation(
|
|
2870
|
+
op.deletedId
|
|
2871
|
+
);
|
|
2872
|
+
if (deleteDelta2) {
|
|
2873
|
+
updates.push(deleteDelta2);
|
|
2865
2874
|
}
|
|
2866
|
-
child._setParentLink(this, newKey);
|
|
2867
2875
|
this._insertAndSort(child);
|
|
2876
|
+
updates.push(insertDelta(this._indexOfPosition(key), child));
|
|
2868
2877
|
return {
|
|
2869
|
-
|
|
2878
|
+
reverse: [],
|
|
2879
|
+
modified: makeUpdate(this, updates)
|
|
2870
2880
|
};
|
|
2871
|
-
}
|
|
2872
|
-
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
/** @internal */
|
|
2884
|
+
_applySetAck(op) {
|
|
2885
|
+
if (this._pool === void 0) {
|
|
2886
|
+
throw new Error("Can't attach child if managed pool is not present");
|
|
2887
|
+
}
|
|
2888
|
+
const delta = [];
|
|
2889
|
+
const deletedDelta = this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
2890
|
+
if (deletedDelta) {
|
|
2891
|
+
delta.push(deletedDelta);
|
|
2892
|
+
}
|
|
2893
|
+
const unacknowledgedOpId = this._unacknowledgedSets.get(op.parentKey);
|
|
2894
|
+
if (unacknowledgedOpId !== void 0) {
|
|
2895
|
+
if (unacknowledgedOpId !== op.opId) {
|
|
2896
|
+
return delta.length === 0 ? { modified: false } : { modified: makeUpdate(this, delta), reverse: [] };
|
|
2897
|
+
} else {
|
|
2898
|
+
this._unacknowledgedSets.delete(op.parentKey);
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
const indexOfItemWithSamePosition = this._indexOfPosition(op.parentKey);
|
|
2902
|
+
const existingItem = this._items.find((item) => item._id === op.id);
|
|
2903
|
+
if (existingItem !== void 0) {
|
|
2904
|
+
if (existingItem._parentKey === op.parentKey) {
|
|
2873
2905
|
return {
|
|
2874
|
-
modified: false
|
|
2906
|
+
modified: delta.length > 0 ? makeUpdate(this, delta) : false,
|
|
2907
|
+
reverse: []
|
|
2875
2908
|
};
|
|
2876
2909
|
}
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
this._items[existingItemIndex]._setParentLink(
|
|
2881
|
-
this,
|
|
2882
|
-
makePosition(newKey, this._items[existingItemIndex + 1]?._parentPos)
|
|
2910
|
+
if (indexOfItemWithSamePosition !== -1) {
|
|
2911
|
+
this._implicitlyDeletedItems.add(
|
|
2912
|
+
this._items[indexOfItemWithSamePosition]
|
|
2883
2913
|
);
|
|
2914
|
+
this._items.splice(indexOfItemWithSamePosition, 1);
|
|
2915
|
+
delta.push(deleteDelta(indexOfItemWithSamePosition));
|
|
2884
2916
|
}
|
|
2885
|
-
|
|
2917
|
+
const previousIndex = this._items.indexOf(existingItem);
|
|
2918
|
+
existingItem._setParentLink(this, op.parentKey);
|
|
2886
2919
|
this._sortItems();
|
|
2887
|
-
const newIndex = this._items.indexOf(
|
|
2888
|
-
if (
|
|
2920
|
+
const newIndex = this._items.indexOf(existingItem);
|
|
2921
|
+
if (newIndex !== previousIndex) {
|
|
2922
|
+
delta.push(moveDelta(previousIndex, newIndex, existingItem));
|
|
2923
|
+
}
|
|
2924
|
+
return {
|
|
2925
|
+
modified: delta.length > 0 ? makeUpdate(this, delta) : false,
|
|
2926
|
+
reverse: []
|
|
2927
|
+
};
|
|
2928
|
+
} else {
|
|
2929
|
+
const orphan = this._pool.getNode(op.id);
|
|
2930
|
+
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
2931
|
+
orphan._setParentLink(this, op.parentKey);
|
|
2932
|
+
this._implicitlyDeletedItems.delete(orphan);
|
|
2933
|
+
this._insertAndSort(orphan);
|
|
2934
|
+
const recreatedItemIndex = this._items.indexOf(orphan);
|
|
2889
2935
|
return {
|
|
2890
|
-
modified:
|
|
2936
|
+
modified: makeUpdate(this, [
|
|
2937
|
+
// If there is an item at this position, update is a set, else it's an insert
|
|
2938
|
+
indexOfItemWithSamePosition === -1 ? insertDelta(recreatedItemIndex, orphan) : setDelta(recreatedItemIndex, orphan),
|
|
2939
|
+
...delta
|
|
2940
|
+
]),
|
|
2941
|
+
reverse: []
|
|
2891
2942
|
};
|
|
2892
2943
|
} else {
|
|
2944
|
+
if (indexOfItemWithSamePosition !== -1) {
|
|
2945
|
+
this._items.splice(indexOfItemWithSamePosition, 1);
|
|
2946
|
+
}
|
|
2947
|
+
const { newItem, newIndex } = this._createAttachItemAndSort(
|
|
2948
|
+
op,
|
|
2949
|
+
op.parentKey
|
|
2950
|
+
);
|
|
2893
2951
|
return {
|
|
2894
2952
|
modified: makeUpdate(this, [
|
|
2895
|
-
|
|
2953
|
+
// If there is an item at this position, update is a set, else it's an insert
|
|
2954
|
+
indexOfItemWithSamePosition === -1 ? insertDelta(newIndex, newItem) : setDelta(newIndex, newItem),
|
|
2955
|
+
...delta
|
|
2896
2956
|
]),
|
|
2897
2957
|
reverse: []
|
|
2898
2958
|
};
|
|
2899
2959
|
}
|
|
2900
2960
|
}
|
|
2901
2961
|
}
|
|
2962
|
+
/**
|
|
2963
|
+
* Returns the update delta of the deletion or null
|
|
2964
|
+
* @internal
|
|
2965
|
+
*/
|
|
2966
|
+
_detachItemAssociatedToSetOperation(deletedId) {
|
|
2967
|
+
if (deletedId === void 0 || this._pool === void 0) {
|
|
2968
|
+
return null;
|
|
2969
|
+
}
|
|
2970
|
+
const deletedItem = this._pool.getNode(deletedId);
|
|
2971
|
+
if (deletedItem === void 0) {
|
|
2972
|
+
return null;
|
|
2973
|
+
}
|
|
2974
|
+
const result = this._detachChild(deletedItem);
|
|
2975
|
+
if (result.modified === false) {
|
|
2976
|
+
return null;
|
|
2977
|
+
}
|
|
2978
|
+
return result.modified.updates[0];
|
|
2979
|
+
}
|
|
2902
2980
|
/** @internal */
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2981
|
+
_applyRemoteInsert(op) {
|
|
2982
|
+
if (this._pool === void 0) {
|
|
2983
|
+
throw new Error("Can't attach child if managed pool is not present");
|
|
2984
|
+
}
|
|
2985
|
+
const key = asPos(op.parentKey);
|
|
2986
|
+
const existingItemIndex = this._indexOfPosition(key);
|
|
2907
2987
|
if (existingItemIndex !== -1) {
|
|
2908
|
-
this.
|
|
2909
|
-
this,
|
|
2910
|
-
makePosition(newKey, this._items[existingItemIndex + 1]?._parentPos)
|
|
2911
|
-
);
|
|
2912
|
-
}
|
|
2913
|
-
child._setParentLink(this, newKey);
|
|
2914
|
-
this._sortItems();
|
|
2915
|
-
const newIndex = this._items.indexOf(child);
|
|
2916
|
-
if (previousIndex === newIndex) {
|
|
2917
|
-
return {
|
|
2918
|
-
modified: false
|
|
2919
|
-
};
|
|
2988
|
+
this._shiftItemPosition(existingItemIndex, key);
|
|
2920
2989
|
}
|
|
2990
|
+
const { newItem, newIndex } = this._createAttachItemAndSort(op, key);
|
|
2921
2991
|
return {
|
|
2922
|
-
modified: makeUpdate(this, [
|
|
2923
|
-
reverse: [
|
|
2924
|
-
{
|
|
2925
|
-
type: 1 /* SET_PARENT_KEY */,
|
|
2926
|
-
id: nn(child._id),
|
|
2927
|
-
parentKey: previousKey
|
|
2928
|
-
}
|
|
2929
|
-
]
|
|
2992
|
+
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
2993
|
+
reverse: []
|
|
2930
2994
|
};
|
|
2931
2995
|
}
|
|
2932
2996
|
/** @internal */
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2997
|
+
_applyInsertAck(op) {
|
|
2998
|
+
const existingItem = this._items.find((item) => item._id === op.id);
|
|
2999
|
+
const key = asPos(op.parentKey);
|
|
3000
|
+
const itemIndexAtPosition = this._indexOfPosition(key);
|
|
3001
|
+
if (existingItem) {
|
|
3002
|
+
if (existingItem._parentKey === key) {
|
|
3003
|
+
return {
|
|
3004
|
+
modified: false
|
|
3005
|
+
};
|
|
3006
|
+
} else {
|
|
3007
|
+
const oldPositionIndex = this._items.indexOf(existingItem);
|
|
3008
|
+
if (itemIndexAtPosition !== -1) {
|
|
3009
|
+
this._shiftItemPosition(itemIndexAtPosition, key);
|
|
3010
|
+
}
|
|
3011
|
+
existingItem._setParentLink(this, key);
|
|
3012
|
+
this._sortItems();
|
|
3013
|
+
const newIndex = this._indexOfPosition(key);
|
|
3014
|
+
if (newIndex === oldPositionIndex) {
|
|
3015
|
+
return { modified: false };
|
|
3016
|
+
}
|
|
3017
|
+
return {
|
|
3018
|
+
modified: makeUpdate(this, [
|
|
3019
|
+
moveDelta(oldPositionIndex, newIndex, existingItem)
|
|
3020
|
+
]),
|
|
3021
|
+
reverse: []
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
2938
3024
|
} else {
|
|
2939
|
-
|
|
3025
|
+
const orphan = nn(this._pool).getNode(op.id);
|
|
3026
|
+
if (orphan && this._implicitlyDeletedItems.has(orphan)) {
|
|
3027
|
+
orphan._setParentLink(this, key);
|
|
3028
|
+
this._implicitlyDeletedItems.delete(orphan);
|
|
3029
|
+
this._insertAndSort(orphan);
|
|
3030
|
+
const newIndex = this._indexOfPosition(key);
|
|
3031
|
+
return {
|
|
3032
|
+
modified: makeUpdate(this, [insertDelta(newIndex, orphan)]),
|
|
3033
|
+
reverse: []
|
|
3034
|
+
};
|
|
3035
|
+
} else {
|
|
3036
|
+
if (itemIndexAtPosition !== -1) {
|
|
3037
|
+
this._shiftItemPosition(itemIndexAtPosition, key);
|
|
3038
|
+
}
|
|
3039
|
+
const { newItem, newIndex } = this._createAttachItemAndSort(op, key);
|
|
3040
|
+
return {
|
|
3041
|
+
modified: makeUpdate(this, [insertDelta(newIndex, newItem)]),
|
|
3042
|
+
reverse: []
|
|
3043
|
+
};
|
|
3044
|
+
}
|
|
2940
3045
|
}
|
|
2941
3046
|
}
|
|
2942
3047
|
/** @internal */
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
3048
|
+
_applyInsertUndoRedo(op) {
|
|
3049
|
+
const { id, parentKey: key } = op;
|
|
3050
|
+
const child = creationOpToLiveNode(op);
|
|
3051
|
+
if (this._pool?.getNode(id) !== void 0) {
|
|
3052
|
+
return { modified: false };
|
|
3053
|
+
}
|
|
3054
|
+
child._attach(id, nn(this._pool));
|
|
3055
|
+
child._setParentLink(this, key);
|
|
3056
|
+
const existingItemIndex = this._indexOfPosition(key);
|
|
3057
|
+
let newKey = key;
|
|
3058
|
+
if (existingItemIndex !== -1) {
|
|
3059
|
+
const before2 = this._items[existingItemIndex]?._parentPos;
|
|
3060
|
+
const after2 = this._items[existingItemIndex + 1]?._parentPos;
|
|
3061
|
+
newKey = makePosition(before2, after2);
|
|
3062
|
+
child._setParentLink(this, newKey);
|
|
2950
3063
|
}
|
|
3064
|
+
this._insertAndSort(child);
|
|
3065
|
+
const newIndex = this._indexOfPosition(newKey);
|
|
2951
3066
|
return {
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
parentKey: this.parent.key
|
|
3067
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
3068
|
+
reverse: [{ type: 5 /* DELETE_CRDT */, id }]
|
|
2955
3069
|
};
|
|
2956
3070
|
}
|
|
2957
|
-
/**
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
/**
|
|
2964
|
-
* Adds one element to the end of the LiveList.
|
|
2965
|
-
* @param element The element to add to the end of the LiveList.
|
|
2966
|
-
*/
|
|
2967
|
-
push(element) {
|
|
2968
|
-
this._pool?.assertStorageIsWritable();
|
|
2969
|
-
return this.insert(element, this.length);
|
|
2970
|
-
}
|
|
2971
|
-
/**
|
|
2972
|
-
* Inserts one element at a specified index.
|
|
2973
|
-
* @param element The element to insert.
|
|
2974
|
-
* @param index The index at which you want to insert the element.
|
|
2975
|
-
*/
|
|
2976
|
-
insert(element, index) {
|
|
2977
|
-
this._pool?.assertStorageIsWritable();
|
|
2978
|
-
if (index < 0 || index > this._items.length) {
|
|
2979
|
-
throw new Error(
|
|
2980
|
-
`Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
|
|
2981
|
-
);
|
|
3071
|
+
/** @internal */
|
|
3072
|
+
_applySetUndoRedo(op) {
|
|
3073
|
+
const { id, parentKey: key } = op;
|
|
3074
|
+
const child = creationOpToLiveNode(op);
|
|
3075
|
+
if (this._pool?.getNode(id) !== void 0) {
|
|
3076
|
+
return { modified: false };
|
|
2982
3077
|
}
|
|
2983
|
-
|
|
2984
|
-
const
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
/* @__PURE__ */ new Map([
|
|
2996
|
-
[this._id, makeUpdate(this, [insertDelta(index, value)])]
|
|
2997
|
-
])
|
|
3078
|
+
this._unacknowledgedSets.set(key, nn(op.opId));
|
|
3079
|
+
const indexOfItemWithSameKey = this._indexOfPosition(key);
|
|
3080
|
+
child._attach(id, nn(this._pool));
|
|
3081
|
+
child._setParentLink(this, key);
|
|
3082
|
+
const newKey = key;
|
|
3083
|
+
if (indexOfItemWithSameKey !== -1) {
|
|
3084
|
+
const existingItem = this._items[indexOfItemWithSameKey];
|
|
3085
|
+
existingItem._detach();
|
|
3086
|
+
this._items[indexOfItemWithSameKey] = child;
|
|
3087
|
+
const reverse = HACK_addIntentAndDeletedIdToOperation(
|
|
3088
|
+
existingItem._toOps(nn(this._id), key, this._pool),
|
|
3089
|
+
op.id
|
|
2998
3090
|
);
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
* Move one element from one index to another.
|
|
3003
|
-
* @param index The index of the element to move
|
|
3004
|
-
* @param targetIndex The index where the element should be after moving.
|
|
3005
|
-
*/
|
|
3006
|
-
move(index, targetIndex) {
|
|
3007
|
-
this._pool?.assertStorageIsWritable();
|
|
3008
|
-
if (targetIndex < 0) {
|
|
3009
|
-
throw new Error("targetIndex cannot be less than 0");
|
|
3010
|
-
}
|
|
3011
|
-
if (targetIndex >= this._items.length) {
|
|
3012
|
-
throw new Error(
|
|
3013
|
-
"targetIndex cannot be greater or equal than the list length"
|
|
3091
|
+
const delta = [setDelta(indexOfItemWithSameKey, child)];
|
|
3092
|
+
const deletedDelta = this._detachItemAssociatedToSetOperation(
|
|
3093
|
+
op.deletedId
|
|
3014
3094
|
);
|
|
3095
|
+
if (deletedDelta) {
|
|
3096
|
+
delta.push(deletedDelta);
|
|
3097
|
+
}
|
|
3098
|
+
return {
|
|
3099
|
+
modified: makeUpdate(this, delta),
|
|
3100
|
+
reverse
|
|
3101
|
+
};
|
|
3102
|
+
} else {
|
|
3103
|
+
this._insertAndSort(child);
|
|
3104
|
+
this._detachItemAssociatedToSetOperation(op.deletedId);
|
|
3105
|
+
const newIndex = this._indexOfPosition(newKey);
|
|
3106
|
+
return {
|
|
3107
|
+
reverse: [{ type: 5 /* DELETE_CRDT */, id }],
|
|
3108
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)])
|
|
3109
|
+
};
|
|
3015
3110
|
}
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
if (
|
|
3020
|
-
throw new Error("
|
|
3111
|
+
}
|
|
3112
|
+
/** @internal */
|
|
3113
|
+
_attachChild(op, source) {
|
|
3114
|
+
if (this._pool === void 0) {
|
|
3115
|
+
throw new Error("Can't attach child if managed pool is not present");
|
|
3021
3116
|
}
|
|
3022
|
-
let
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3117
|
+
let result;
|
|
3118
|
+
if (op.intent === "set") {
|
|
3119
|
+
if (source === 1 /* REMOTE */) {
|
|
3120
|
+
result = this._applySetRemote(op);
|
|
3121
|
+
} else if (source === 2 /* ACK */) {
|
|
3122
|
+
result = this._applySetAck(op);
|
|
3123
|
+
} else {
|
|
3124
|
+
result = this._applySetUndoRedo(op);
|
|
3125
|
+
}
|
|
3027
3126
|
} else {
|
|
3028
|
-
|
|
3029
|
-
|
|
3127
|
+
if (source === 1 /* REMOTE */) {
|
|
3128
|
+
result = this._applyRemoteInsert(op);
|
|
3129
|
+
} else if (source === 2 /* ACK */) {
|
|
3130
|
+
result = this._applyInsertAck(op);
|
|
3131
|
+
} else {
|
|
3132
|
+
result = this._applyInsertUndoRedo(op);
|
|
3133
|
+
}
|
|
3030
3134
|
}
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
const previousPosition = item._getParentKeyOrThrow();
|
|
3034
|
-
item._setParentLink(this, position);
|
|
3035
|
-
this._sortItems();
|
|
3036
|
-
if (this._pool && this._id) {
|
|
3037
|
-
const storageUpdates = /* @__PURE__ */ new Map([
|
|
3038
|
-
[this._id, makeUpdate(this, [moveDelta(index, targetIndex, item)])]
|
|
3039
|
-
]);
|
|
3040
|
-
this._pool.dispatch(
|
|
3041
|
-
[
|
|
3042
|
-
{
|
|
3043
|
-
type: 1 /* SET_PARENT_KEY */,
|
|
3044
|
-
id: nn(item._id),
|
|
3045
|
-
opId: this._pool.generateOpId(),
|
|
3046
|
-
parentKey: position
|
|
3047
|
-
}
|
|
3048
|
-
],
|
|
3049
|
-
[
|
|
3050
|
-
{
|
|
3051
|
-
type: 1 /* SET_PARENT_KEY */,
|
|
3052
|
-
id: nn(item._id),
|
|
3053
|
-
parentKey: previousPosition
|
|
3054
|
-
}
|
|
3055
|
-
],
|
|
3056
|
-
storageUpdates
|
|
3057
|
-
);
|
|
3135
|
+
if (result.modified !== false) {
|
|
3136
|
+
this.invalidate();
|
|
3058
3137
|
}
|
|
3138
|
+
return result;
|
|
3059
3139
|
}
|
|
3060
|
-
/**
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3140
|
+
/** @internal */
|
|
3141
|
+
_detachChild(child) {
|
|
3142
|
+
if (child) {
|
|
3143
|
+
const parentKey = nn(child._parentKey);
|
|
3144
|
+
const reverse = child._toOps(nn(this._id), parentKey, this._pool);
|
|
3145
|
+
const indexToDelete = this._items.indexOf(child);
|
|
3146
|
+
if (indexToDelete === -1) {
|
|
3147
|
+
return {
|
|
3148
|
+
modified: false
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
this._items.splice(indexToDelete, 1);
|
|
3152
|
+
this.invalidate();
|
|
3153
|
+
child._detach();
|
|
3154
|
+
return {
|
|
3155
|
+
modified: makeUpdate(this, [deleteDelta(indexToDelete)]),
|
|
3156
|
+
reverse
|
|
3157
|
+
};
|
|
3158
|
+
}
|
|
3159
|
+
return { modified: false };
|
|
3160
|
+
}
|
|
3161
|
+
/** @internal */
|
|
3162
|
+
_applySetChildKeyRemote(newKey, child) {
|
|
3163
|
+
if (this._implicitlyDeletedItems.has(child)) {
|
|
3164
|
+
this._implicitlyDeletedItems.delete(child);
|
|
3165
|
+
child._setParentLink(this, newKey);
|
|
3166
|
+
this._insertAndSort(child);
|
|
3167
|
+
const newIndex = this._items.indexOf(child);
|
|
3168
|
+
return {
|
|
3169
|
+
modified: makeUpdate(this, [insertDelta(newIndex, child)]),
|
|
3170
|
+
reverse: []
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
3173
|
+
const previousKey = child._parentKey;
|
|
3174
|
+
if (newKey === previousKey) {
|
|
3175
|
+
return {
|
|
3176
|
+
modified: false
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
3180
|
+
if (existingItemIndex === -1) {
|
|
3181
|
+
const previousIndex = this._items.indexOf(child);
|
|
3182
|
+
child._setParentLink(this, newKey);
|
|
3183
|
+
this._sortItems();
|
|
3184
|
+
const newIndex = this._items.indexOf(child);
|
|
3185
|
+
if (newIndex === previousIndex) {
|
|
3186
|
+
return {
|
|
3187
|
+
modified: false
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
return {
|
|
3191
|
+
modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
|
|
3192
|
+
reverse: []
|
|
3193
|
+
};
|
|
3194
|
+
} else {
|
|
3195
|
+
this._items[existingItemIndex]._setParentLink(
|
|
3196
|
+
this,
|
|
3197
|
+
makePosition(newKey, this._items[existingItemIndex + 1]?._parentPos)
|
|
3069
3198
|
);
|
|
3199
|
+
const previousIndex = this._items.indexOf(child);
|
|
3200
|
+
child._setParentLink(this, newKey);
|
|
3201
|
+
this._sortItems();
|
|
3202
|
+
const newIndex = this._items.indexOf(child);
|
|
3203
|
+
if (newIndex === previousIndex) {
|
|
3204
|
+
return {
|
|
3205
|
+
modified: false
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
return {
|
|
3209
|
+
modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
|
|
3210
|
+
reverse: []
|
|
3211
|
+
};
|
|
3070
3212
|
}
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
if (this.
|
|
3076
|
-
const
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3213
|
+
}
|
|
3214
|
+
/** @internal */
|
|
3215
|
+
_applySetChildKeyAck(newKey, child) {
|
|
3216
|
+
const previousKey = nn(child._parentKey);
|
|
3217
|
+
if (this._implicitlyDeletedItems.has(child)) {
|
|
3218
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
3219
|
+
this._implicitlyDeletedItems.delete(child);
|
|
3220
|
+
if (existingItemIndex !== -1) {
|
|
3221
|
+
this._items[existingItemIndex]._setParentLink(
|
|
3222
|
+
this,
|
|
3223
|
+
makePosition(newKey, this._items[existingItemIndex + 1]?._parentPos)
|
|
3082
3224
|
);
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3225
|
+
}
|
|
3226
|
+
child._setParentLink(this, newKey);
|
|
3227
|
+
this._insertAndSort(child);
|
|
3228
|
+
return {
|
|
3229
|
+
modified: false
|
|
3230
|
+
};
|
|
3231
|
+
} else {
|
|
3232
|
+
if (newKey === previousKey) {
|
|
3233
|
+
return {
|
|
3234
|
+
modified: false
|
|
3235
|
+
};
|
|
3236
|
+
}
|
|
3237
|
+
const previousIndex = this._items.indexOf(child);
|
|
3238
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
3239
|
+
if (existingItemIndex !== -1) {
|
|
3240
|
+
this._items[existingItemIndex]._setParentLink(
|
|
3241
|
+
this,
|
|
3242
|
+
makePosition(newKey, this._items[existingItemIndex + 1]?._parentPos)
|
|
3093
3243
|
);
|
|
3094
3244
|
}
|
|
3245
|
+
child._setParentLink(this, newKey);
|
|
3246
|
+
this._sortItems();
|
|
3247
|
+
const newIndex = this._items.indexOf(child);
|
|
3248
|
+
if (previousIndex === newIndex) {
|
|
3249
|
+
return {
|
|
3250
|
+
modified: false
|
|
3251
|
+
};
|
|
3252
|
+
} else {
|
|
3253
|
+
return {
|
|
3254
|
+
modified: makeUpdate(this, [
|
|
3255
|
+
moveDelta(previousIndex, newIndex, child)
|
|
3256
|
+
]),
|
|
3257
|
+
reverse: []
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3095
3260
|
}
|
|
3096
3261
|
}
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3262
|
+
/** @internal */
|
|
3263
|
+
_applySetChildKeyUndoRedo(newKey, child) {
|
|
3264
|
+
const previousKey = nn(child._parentKey);
|
|
3265
|
+
const previousIndex = this._items.indexOf(child);
|
|
3266
|
+
const existingItemIndex = this._indexOfPosition(newKey);
|
|
3267
|
+
if (existingItemIndex !== -1) {
|
|
3268
|
+
this._items[existingItemIndex]._setParentLink(
|
|
3269
|
+
this,
|
|
3270
|
+
makePosition(newKey, this._items[existingItemIndex + 1]?._parentPos)
|
|
3271
|
+
);
|
|
3272
|
+
}
|
|
3273
|
+
child._setParentLink(this, newKey);
|
|
3274
|
+
this._sortItems();
|
|
3275
|
+
const newIndex = this._items.indexOf(child);
|
|
3276
|
+
if (previousIndex === newIndex) {
|
|
3277
|
+
return {
|
|
3278
|
+
modified: false
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
return {
|
|
3282
|
+
modified: makeUpdate(this, [moveDelta(previousIndex, newIndex, child)]),
|
|
3283
|
+
reverse: [
|
|
3284
|
+
{
|
|
3285
|
+
type: 1 /* SET_PARENT_KEY */,
|
|
3286
|
+
id: nn(child._id),
|
|
3287
|
+
parentKey: previousKey
|
|
3116
3288
|
}
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3289
|
+
]
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
/** @internal */
|
|
3293
|
+
_setChildKey(newKey, child, source) {
|
|
3294
|
+
if (source === 1 /* REMOTE */) {
|
|
3295
|
+
return this._applySetChildKeyRemote(newKey, child);
|
|
3296
|
+
} else if (source === 2 /* ACK */) {
|
|
3297
|
+
return this._applySetChildKeyAck(newKey, child);
|
|
3123
3298
|
} else {
|
|
3124
|
-
|
|
3125
|
-
item._detach();
|
|
3126
|
-
}
|
|
3127
|
-
this._items = [];
|
|
3128
|
-
this.invalidate();
|
|
3299
|
+
return this._applySetChildKeyUndoRedo(newKey, child);
|
|
3129
3300
|
}
|
|
3130
3301
|
}
|
|
3131
|
-
|
|
3302
|
+
/** @internal */
|
|
3303
|
+
_apply(op, isLocal) {
|
|
3304
|
+
return super._apply(op, isLocal);
|
|
3305
|
+
}
|
|
3306
|
+
/** @internal */
|
|
3307
|
+
_serialize() {
|
|
3308
|
+
if (this.parent.type !== "HasParent") {
|
|
3309
|
+
throw new Error("Cannot serialize LiveList if parent is missing");
|
|
3310
|
+
}
|
|
3311
|
+
return {
|
|
3312
|
+
type: 1 /* LIST */,
|
|
3313
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
3314
|
+
parentKey: this.parent.key
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
/**
|
|
3318
|
+
* Returns the number of elements.
|
|
3319
|
+
*/
|
|
3320
|
+
get length() {
|
|
3321
|
+
return this._items.length;
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Adds one element to the end of the LiveList.
|
|
3325
|
+
* @param element The element to add to the end of the LiveList.
|
|
3326
|
+
*/
|
|
3327
|
+
push(element) {
|
|
3132
3328
|
this._pool?.assertStorageIsWritable();
|
|
3133
|
-
|
|
3329
|
+
return this.insert(element, this.length);
|
|
3330
|
+
}
|
|
3331
|
+
/**
|
|
3332
|
+
* Inserts one element at a specified index.
|
|
3333
|
+
* @param element The element to insert.
|
|
3334
|
+
* @param index The index at which you want to insert the element.
|
|
3335
|
+
*/
|
|
3336
|
+
insert(element, index) {
|
|
3337
|
+
this._pool?.assertStorageIsWritable();
|
|
3338
|
+
if (index < 0 || index > this._items.length) {
|
|
3134
3339
|
throw new Error(
|
|
3135
|
-
`Cannot
|
|
3340
|
+
`Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
|
|
3136
3341
|
);
|
|
3137
3342
|
}
|
|
3138
|
-
const
|
|
3139
|
-
const
|
|
3140
|
-
const
|
|
3141
|
-
|
|
3142
|
-
const value = lsonToLiveNode(item);
|
|
3343
|
+
const before2 = this._items[index - 1] ? this._items[index - 1]._parentPos : void 0;
|
|
3344
|
+
const after2 = this._items[index] ? this._items[index]._parentPos : void 0;
|
|
3345
|
+
const position = makePosition(before2, after2);
|
|
3346
|
+
const value = lsonToLiveNode(element);
|
|
3143
3347
|
value._setParentLink(this, position);
|
|
3144
|
-
this.
|
|
3145
|
-
this.
|
|
3348
|
+
this._insertAndSort(value);
|
|
3349
|
+
if (this._pool && this._id) {
|
|
3350
|
+
const id = this._pool.generateId();
|
|
3351
|
+
value._attach(id, this._pool);
|
|
3352
|
+
this._pool.dispatch(
|
|
3353
|
+
value._toOps(this._id, position, this._pool),
|
|
3354
|
+
[{ type: 5 /* DELETE_CRDT */, id }],
|
|
3355
|
+
/* @__PURE__ */ new Map([
|
|
3356
|
+
[this._id, makeUpdate(this, [insertDelta(index, value)])]
|
|
3357
|
+
])
|
|
3358
|
+
);
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
/**
|
|
3362
|
+
* Move one element from one index to another.
|
|
3363
|
+
* @param index The index of the element to move
|
|
3364
|
+
* @param targetIndex The index where the element should be after moving.
|
|
3365
|
+
*/
|
|
3366
|
+
move(index, targetIndex) {
|
|
3367
|
+
this._pool?.assertStorageIsWritable();
|
|
3368
|
+
if (targetIndex < 0) {
|
|
3369
|
+
throw new Error("targetIndex cannot be less than 0");
|
|
3370
|
+
}
|
|
3371
|
+
if (targetIndex >= this._items.length) {
|
|
3372
|
+
throw new Error(
|
|
3373
|
+
"targetIndex cannot be greater or equal than the list length"
|
|
3374
|
+
);
|
|
3375
|
+
}
|
|
3376
|
+
if (index < 0) {
|
|
3377
|
+
throw new Error("index cannot be less than 0");
|
|
3378
|
+
}
|
|
3379
|
+
if (index >= this._items.length) {
|
|
3380
|
+
throw new Error("index cannot be greater or equal than the list length");
|
|
3381
|
+
}
|
|
3382
|
+
let beforePosition = null;
|
|
3383
|
+
let afterPosition = null;
|
|
3384
|
+
if (index < targetIndex) {
|
|
3385
|
+
afterPosition = targetIndex === this._items.length - 1 ? void 0 : this._items[targetIndex + 1]._parentPos;
|
|
3386
|
+
beforePosition = this._items[targetIndex]._parentPos;
|
|
3387
|
+
} else {
|
|
3388
|
+
afterPosition = this._items[targetIndex]._parentPos;
|
|
3389
|
+
beforePosition = targetIndex === 0 ? void 0 : this._items[targetIndex - 1]._parentPos;
|
|
3390
|
+
}
|
|
3391
|
+
const position = makePosition(beforePosition, afterPosition);
|
|
3392
|
+
const item = this._items[index];
|
|
3393
|
+
const previousPosition = item._getParentKeyOrThrow();
|
|
3394
|
+
item._setParentLink(this, position);
|
|
3395
|
+
this._sortItems();
|
|
3396
|
+
if (this._pool && this._id) {
|
|
3397
|
+
const storageUpdates = /* @__PURE__ */ new Map([
|
|
3398
|
+
[this._id, makeUpdate(this, [moveDelta(index, targetIndex, item)])]
|
|
3399
|
+
]);
|
|
3400
|
+
this._pool.dispatch(
|
|
3401
|
+
[
|
|
3402
|
+
{
|
|
3403
|
+
type: 1 /* SET_PARENT_KEY */,
|
|
3404
|
+
id: nn(item._id),
|
|
3405
|
+
opId: this._pool.generateOpId(),
|
|
3406
|
+
parentKey: position
|
|
3407
|
+
}
|
|
3408
|
+
],
|
|
3409
|
+
[
|
|
3410
|
+
{
|
|
3411
|
+
type: 1 /* SET_PARENT_KEY */,
|
|
3412
|
+
id: nn(item._id),
|
|
3413
|
+
parentKey: previousPosition
|
|
3414
|
+
}
|
|
3415
|
+
],
|
|
3416
|
+
storageUpdates
|
|
3417
|
+
);
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
/**
|
|
3421
|
+
* Deletes an element at the specified index
|
|
3422
|
+
* @param index The index of the element to delete
|
|
3423
|
+
*/
|
|
3424
|
+
delete(index) {
|
|
3425
|
+
this._pool?.assertStorageIsWritable();
|
|
3426
|
+
if (index < 0 || index >= this._items.length) {
|
|
3427
|
+
throw new Error(
|
|
3428
|
+
`Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
|
|
3429
|
+
);
|
|
3430
|
+
}
|
|
3431
|
+
const item = this._items[index];
|
|
3432
|
+
item._detach();
|
|
3433
|
+
this._items.splice(index, 1);
|
|
3434
|
+
this.invalidate();
|
|
3435
|
+
if (this._pool) {
|
|
3436
|
+
const childRecordId = item._id;
|
|
3437
|
+
if (childRecordId) {
|
|
3438
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
3439
|
+
storageUpdates.set(
|
|
3440
|
+
nn(this._id),
|
|
3441
|
+
makeUpdate(this, [deleteDelta(index)])
|
|
3442
|
+
);
|
|
3443
|
+
this._pool.dispatch(
|
|
3444
|
+
[
|
|
3445
|
+
{
|
|
3446
|
+
id: childRecordId,
|
|
3447
|
+
opId: this._pool.generateOpId(),
|
|
3448
|
+
type: 5 /* DELETE_CRDT */
|
|
3449
|
+
}
|
|
3450
|
+
],
|
|
3451
|
+
item._toOps(nn(this._id), item._getParentKeyOrThrow()),
|
|
3452
|
+
storageUpdates
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
clear() {
|
|
3458
|
+
this._pool?.assertStorageIsWritable();
|
|
3459
|
+
if (this._pool) {
|
|
3460
|
+
const ops = [];
|
|
3461
|
+
const reverseOps = [];
|
|
3462
|
+
const updateDelta = [];
|
|
3463
|
+
for (const item of this._items) {
|
|
3464
|
+
item._detach();
|
|
3465
|
+
const childId = item._id;
|
|
3466
|
+
if (childId) {
|
|
3467
|
+
ops.push({
|
|
3468
|
+
type: 5 /* DELETE_CRDT */,
|
|
3469
|
+
id: childId,
|
|
3470
|
+
opId: this._pool.generateOpId()
|
|
3471
|
+
});
|
|
3472
|
+
reverseOps.push(
|
|
3473
|
+
...item._toOps(nn(this._id), item._getParentKeyOrThrow())
|
|
3474
|
+
);
|
|
3475
|
+
updateDelta.push(deleteDelta(0));
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
this._items = [];
|
|
3479
|
+
this.invalidate();
|
|
3480
|
+
const storageUpdates = /* @__PURE__ */ new Map();
|
|
3481
|
+
storageUpdates.set(nn(this._id), makeUpdate(this, updateDelta));
|
|
3482
|
+
this._pool.dispatch(ops, reverseOps, storageUpdates);
|
|
3483
|
+
} else {
|
|
3484
|
+
for (const item of this._items) {
|
|
3485
|
+
item._detach();
|
|
3486
|
+
}
|
|
3487
|
+
this._items = [];
|
|
3488
|
+
this.invalidate();
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
set(index, item) {
|
|
3492
|
+
this._pool?.assertStorageIsWritable();
|
|
3493
|
+
if (index < 0 || index >= this._items.length) {
|
|
3494
|
+
throw new Error(
|
|
3495
|
+
`Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
|
|
3496
|
+
);
|
|
3497
|
+
}
|
|
3498
|
+
const existingItem = this._items[index];
|
|
3499
|
+
const position = existingItem._getParentKeyOrThrow();
|
|
3500
|
+
const existingId = existingItem._id;
|
|
3501
|
+
existingItem._detach();
|
|
3502
|
+
const value = lsonToLiveNode(item);
|
|
3503
|
+
value._setParentLink(this, position);
|
|
3504
|
+
this._items[index] = value;
|
|
3505
|
+
this.invalidate();
|
|
3146
3506
|
if (this._pool && this._id) {
|
|
3147
3507
|
const id = this._pool.generateId();
|
|
3148
3508
|
value._attach(id, this._pool);
|
|
@@ -4995,9 +5355,13 @@ function createRoom(options, config) {
|
|
|
4995
5355
|
ydoc: makeEventSource(),
|
|
4996
5356
|
comments: makeEventSource()
|
|
4997
5357
|
};
|
|
4998
|
-
async function
|
|
5358
|
+
async function httpPostToRoom(endpoint, body) {
|
|
5359
|
+
if (!managedSocket.authValue) {
|
|
5360
|
+
throw new Error("Not authorized");
|
|
5361
|
+
}
|
|
5362
|
+
const authTokenOrPublicApiKey = managedSocket.authValue.type === "public" ? managedSocket.authValue.publicApiKey : managedSocket.authValue.token.raw;
|
|
4999
5363
|
const url = new URL(
|
|
5000
|
-
`/v2/c/rooms/${encodeURIComponent(roomId)}
|
|
5364
|
+
`/v2/c/rooms/${encodeURIComponent(config.roomId)}${endpoint}`,
|
|
5001
5365
|
config.baseUrl
|
|
5002
5366
|
).toString();
|
|
5003
5367
|
const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
|
|
@@ -5008,25 +5372,22 @@ function createRoom(options, config) {
|
|
|
5008
5372
|
"Content-Type": "application/json",
|
|
5009
5373
|
Authorization: `Bearer ${authTokenOrPublicApiKey}`
|
|
5010
5374
|
},
|
|
5011
|
-
body: JSON.stringify(
|
|
5375
|
+
body: JSON.stringify(body)
|
|
5012
5376
|
});
|
|
5013
5377
|
}
|
|
5014
5378
|
function sendMessages(messages) {
|
|
5015
5379
|
const serializedPayload = JSON.stringify(messages);
|
|
5016
5380
|
const nonce = context.dynamicSessionInfo.current?.nonce;
|
|
5017
|
-
if (config.unstable_fallbackToHTTP &&
|
|
5381
|
+
if (config.unstable_fallbackToHTTP && nonce) {
|
|
5018
5382
|
const size = new TextEncoder().encode(serializedPayload).length;
|
|
5019
5383
|
if (size > MAX_SOCKET_MESSAGE_SIZE) {
|
|
5020
|
-
void
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
).then((resp) => {
|
|
5026
|
-
if (!resp.ok && resp.status === 403) {
|
|
5027
|
-
managedSocket.reconnect();
|
|
5384
|
+
void httpPostToRoom("/send-message", { nonce, messages }).then(
|
|
5385
|
+
(resp) => {
|
|
5386
|
+
if (!resp.ok && resp.status === 403) {
|
|
5387
|
+
managedSocket.reconnect();
|
|
5388
|
+
}
|
|
5028
5389
|
}
|
|
5029
|
-
|
|
5390
|
+
);
|
|
5030
5391
|
warn(
|
|
5031
5392
|
"Message was too large for websockets and sent over HTTP instead"
|
|
5032
5393
|
);
|
|
@@ -5539,7 +5900,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
5539
5900
|
}
|
|
5540
5901
|
const now = Date.now();
|
|
5541
5902
|
const elapsedMillis = now - context.buffer.lastFlushedAt;
|
|
5542
|
-
if (elapsedMillis
|
|
5903
|
+
if (elapsedMillis >= config.throttleDelay) {
|
|
5543
5904
|
const messagesToFlush = serializeBuffer();
|
|
5544
5905
|
if (messagesToFlush.length === 0) {
|
|
5545
5906
|
return;
|
|
@@ -5906,1161 +6267,852 @@ function makeClassicSubscribeFn(events) {
|
|
|
5906
6267
|
const cb = callback;
|
|
5907
6268
|
return events.others.subscribe((event) => {
|
|
5908
6269
|
const { others, ...internalEvent } = event;
|
|
5909
|
-
return cb(others, internalEvent);
|
|
5910
|
-
});
|
|
5911
|
-
}
|
|
5912
|
-
case "error":
|
|
5913
|
-
return events.error.subscribe(callback);
|
|
5914
|
-
case "connection": {
|
|
5915
|
-
const cb = callback;
|
|
5916
|
-
return events.status.subscribe(
|
|
5917
|
-
(status) => cb(newToLegacyStatus(status))
|
|
5918
|
-
);
|
|
5919
|
-
}
|
|
5920
|
-
case "status":
|
|
5921
|
-
return events.status.subscribe(callback);
|
|
5922
|
-
case "lost-connection":
|
|
5923
|
-
return events.lostConnection.subscribe(
|
|
5924
|
-
callback
|
|
5925
|
-
);
|
|
5926
|
-
case "history":
|
|
5927
|
-
return events.history.subscribe(callback);
|
|
5928
|
-
case "storage-status":
|
|
5929
|
-
return events.storageStatus.subscribe(
|
|
5930
|
-
callback
|
|
5931
|
-
);
|
|
5932
|
-
default:
|
|
5933
|
-
return assertNever(
|
|
5934
|
-
first,
|
|
5935
|
-
`"${String(first)}" is not a valid event name`
|
|
5936
|
-
);
|
|
5937
|
-
}
|
|
5938
|
-
}
|
|
5939
|
-
if (second === void 0 || typeof first === "function") {
|
|
5940
|
-
if (typeof first === "function") {
|
|
5941
|
-
const storageCallback = first;
|
|
5942
|
-
return events.storage.subscribe(storageCallback);
|
|
5943
|
-
} else {
|
|
5944
|
-
throw new Error("Please specify a listener callback");
|
|
5945
|
-
}
|
|
5946
|
-
}
|
|
5947
|
-
if (isLiveNode(first)) {
|
|
5948
|
-
const node = first;
|
|
5949
|
-
if (options?.isDeep) {
|
|
5950
|
-
const storageCallback = second;
|
|
5951
|
-
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
5952
|
-
} else {
|
|
5953
|
-
const nodeCallback = second;
|
|
5954
|
-
return subscribeToLiveStructureShallowly(node, nodeCallback);
|
|
5955
|
-
}
|
|
5956
|
-
}
|
|
5957
|
-
throw new Error(
|
|
5958
|
-
`${String(first)} is not a value that can be subscribed to.`
|
|
5959
|
-
);
|
|
5960
|
-
}
|
|
5961
|
-
return subscribe;
|
|
5962
|
-
}
|
|
5963
|
-
function isRoomEventName(value) {
|
|
5964
|
-
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "history" || value === "status" || value === "storage-status" || value === "lost-connection" || value === "connection";
|
|
5965
|
-
}
|
|
5966
|
-
function makeAuthDelegateForRoom(roomId, authManager) {
|
|
5967
|
-
return async () => {
|
|
5968
|
-
return authManager.getAuthValue("room:read", roomId);
|
|
5969
|
-
};
|
|
5970
|
-
}
|
|
5971
|
-
function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
|
|
5972
|
-
return (authValue) => {
|
|
5973
|
-
const ws = WebSocketPolyfill ?? (typeof WebSocket === "undefined" ? void 0 : WebSocket);
|
|
5974
|
-
if (ws === void 0) {
|
|
5975
|
-
throw new StopRetrying(
|
|
5976
|
-
"To use Liveblocks client in a non-DOM environment, you need to provide a WebSocket polyfill."
|
|
5977
|
-
);
|
|
5978
|
-
}
|
|
5979
|
-
const url = new URL(baseUrl);
|
|
5980
|
-
url.protocol = url.protocol === "http:" ? "ws" : "wss";
|
|
5981
|
-
url.pathname = "/v7";
|
|
5982
|
-
url.searchParams.set("roomId", roomId);
|
|
5983
|
-
if (authValue.type === "secret") {
|
|
5984
|
-
url.searchParams.set("tok", authValue.token.raw);
|
|
5985
|
-
} else if (authValue.type === "public") {
|
|
5986
|
-
url.searchParams.set("pubkey", authValue.publicApiKey);
|
|
5987
|
-
} else {
|
|
5988
|
-
return assertNever(authValue, "Unhandled case");
|
|
5989
|
-
}
|
|
5990
|
-
url.searchParams.set("version", PKG_VERSION || "dev");
|
|
5991
|
-
return new ws(url.toString());
|
|
5992
|
-
};
|
|
5993
|
-
}
|
|
5994
|
-
|
|
5995
|
-
// src/client.ts
|
|
5996
|
-
var MIN_THROTTLE = 16;
|
|
5997
|
-
var MAX_THROTTLE = 1e3;
|
|
5998
|
-
var DEFAULT_THROTTLE = 100;
|
|
5999
|
-
var MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT = 15e3;
|
|
6000
|
-
var MIN_LOST_CONNECTION_TIMEOUT = 200;
|
|
6001
|
-
var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
|
|
6002
|
-
var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
|
|
6003
|
-
var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
|
|
6004
|
-
function getBaseUrlFromClientOptions(clientOptions) {
|
|
6005
|
-
if ("liveblocksServer" in clientOptions) {
|
|
6006
|
-
throw new Error("Client option no longer supported");
|
|
6007
|
-
}
|
|
6008
|
-
if (typeof clientOptions.baseUrl === "string" && clientOptions.baseUrl.startsWith("http")) {
|
|
6009
|
-
return clientOptions.baseUrl;
|
|
6010
|
-
} else {
|
|
6011
|
-
return DEFAULT_BASE_URL;
|
|
6012
|
-
}
|
|
6013
|
-
}
|
|
6014
|
-
function createClient(options) {
|
|
6015
|
-
const clientOptions = options;
|
|
6016
|
-
const throttleDelay = getThrottle(clientOptions.throttle ?? DEFAULT_THROTTLE);
|
|
6017
|
-
const lostConnectionTimeout = getLostConnectionTimeout(
|
|
6018
|
-
clientOptions.lostConnectionTimeout ?? DEFAULT_LOST_CONNECTION_TIMEOUT
|
|
6019
|
-
);
|
|
6020
|
-
const backgroundKeepAliveTimeout = getBackgroundKeepAliveTimeout(
|
|
6021
|
-
clientOptions.backgroundKeepAliveTimeout
|
|
6022
|
-
);
|
|
6023
|
-
const authManager = createAuthManager(options);
|
|
6024
|
-
const roomsById = /* @__PURE__ */ new Map();
|
|
6025
|
-
function teardownRoom(room) {
|
|
6026
|
-
unlinkDevTools(room.id);
|
|
6027
|
-
roomsById.delete(room.id);
|
|
6028
|
-
room.destroy();
|
|
6029
|
-
}
|
|
6030
|
-
function leaseRoom(info) {
|
|
6031
|
-
const leave = () => {
|
|
6032
|
-
const self = leave;
|
|
6033
|
-
if (!info.unsubs.delete(self)) {
|
|
6034
|
-
warn(
|
|
6035
|
-
"This leave function was already called. Calling it more than once has no effect."
|
|
6036
|
-
);
|
|
6037
|
-
} else {
|
|
6038
|
-
if (info.unsubs.size === 0) {
|
|
6039
|
-
teardownRoom(info.room);
|
|
6040
|
-
}
|
|
6041
|
-
}
|
|
6042
|
-
};
|
|
6043
|
-
info.unsubs.add(leave);
|
|
6044
|
-
return {
|
|
6045
|
-
room: info.room,
|
|
6046
|
-
leave
|
|
6047
|
-
};
|
|
6048
|
-
}
|
|
6049
|
-
function enterRoom(roomId, options2) {
|
|
6050
|
-
const existing = roomsById.get(roomId);
|
|
6051
|
-
if (existing !== void 0) {
|
|
6052
|
-
return leaseRoom(existing);
|
|
6053
|
-
}
|
|
6054
|
-
deprecateIf(
|
|
6055
|
-
options2.initialPresence === null || options2.initialPresence === void 0,
|
|
6056
|
-
"Please provide an initial presence value for the current user when entering the room."
|
|
6057
|
-
);
|
|
6058
|
-
const baseUrl = getBaseUrlFromClientOptions(clientOptions);
|
|
6059
|
-
const newRoom = createRoom(
|
|
6060
|
-
{
|
|
6061
|
-
initialPresence: options2.initialPresence ?? {},
|
|
6062
|
-
initialStorage: options2.initialStorage
|
|
6063
|
-
},
|
|
6064
|
-
{
|
|
6065
|
-
roomId,
|
|
6066
|
-
throttleDelay,
|
|
6067
|
-
lostConnectionTimeout,
|
|
6068
|
-
backgroundKeepAliveTimeout,
|
|
6069
|
-
polyfills: clientOptions.polyfills,
|
|
6070
|
-
delegates: clientOptions.mockedDelegates ?? {
|
|
6071
|
-
createSocket: makeCreateSocketDelegateForRoom(
|
|
6072
|
-
roomId,
|
|
6073
|
-
baseUrl,
|
|
6074
|
-
clientOptions.polyfills?.WebSocket
|
|
6075
|
-
),
|
|
6076
|
-
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
6077
|
-
},
|
|
6078
|
-
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
6079
|
-
unstable_batchedUpdates: options2?.unstable_batchedUpdates,
|
|
6080
|
-
baseUrl,
|
|
6081
|
-
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP
|
|
6082
|
-
}
|
|
6083
|
-
);
|
|
6084
|
-
const newRoomInfo = {
|
|
6085
|
-
room: newRoom,
|
|
6086
|
-
unsubs: /* @__PURE__ */ new Set()
|
|
6087
|
-
};
|
|
6088
|
-
roomsById.set(roomId, newRoomInfo);
|
|
6089
|
-
setupDevTools(() => Array.from(roomsById.keys()));
|
|
6090
|
-
linkDevTools(roomId, newRoom);
|
|
6091
|
-
const shouldConnect = options2.autoConnect ?? options2.shouldInitiallyConnect ?? true;
|
|
6092
|
-
if (shouldConnect) {
|
|
6093
|
-
if (typeof atob === "undefined") {
|
|
6094
|
-
if (clientOptions.polyfills?.atob === void 0) {
|
|
6095
|
-
throw new Error(
|
|
6096
|
-
"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"
|
|
6097
|
-
);
|
|
6098
|
-
}
|
|
6099
|
-
global.atob = clientOptions.polyfills.atob;
|
|
6100
|
-
}
|
|
6101
|
-
newRoom.connect();
|
|
6102
|
-
}
|
|
6103
|
-
return leaseRoom(newRoomInfo);
|
|
6104
|
-
}
|
|
6105
|
-
function enter(roomId, options2) {
|
|
6106
|
-
const { room, leave: _ } = enterRoom(roomId, options2);
|
|
6107
|
-
return room;
|
|
6108
|
-
}
|
|
6109
|
-
function getRoom(roomId) {
|
|
6110
|
-
const room = roomsById.get(roomId)?.room;
|
|
6111
|
-
return room ? room : null;
|
|
6112
|
-
}
|
|
6113
|
-
function forceLeave(roomId) {
|
|
6114
|
-
const unsubs = roomsById.get(roomId)?.unsubs ?? /* @__PURE__ */ new Set();
|
|
6115
|
-
for (const unsub of unsubs) {
|
|
6116
|
-
unsub();
|
|
6117
|
-
}
|
|
6118
|
-
}
|
|
6119
|
-
function logout() {
|
|
6120
|
-
authManager.reset();
|
|
6121
|
-
for (const { room } of roomsById.values()) {
|
|
6122
|
-
if (!isIdle(room.getStatus())) {
|
|
6123
|
-
room.reconnect();
|
|
6124
|
-
}
|
|
6125
|
-
}
|
|
6126
|
-
}
|
|
6127
|
-
return {
|
|
6128
|
-
logout,
|
|
6129
|
-
// Old, deprecated APIs
|
|
6130
|
-
enter,
|
|
6131
|
-
getRoom,
|
|
6132
|
-
leave: forceLeave,
|
|
6133
|
-
// New, preferred API
|
|
6134
|
-
enterRoom
|
|
6135
|
-
};
|
|
6136
|
-
}
|
|
6137
|
-
function checkBounds(option, value, min, max, recommendedMin) {
|
|
6138
|
-
if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
|
|
6139
|
-
throw new Error(
|
|
6140
|
-
max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
|
|
6141
|
-
);
|
|
6142
|
-
}
|
|
6143
|
-
return value;
|
|
6144
|
-
}
|
|
6145
|
-
function getBackgroundKeepAliveTimeout(value) {
|
|
6146
|
-
if (value === void 0)
|
|
6147
|
-
return void 0;
|
|
6148
|
-
return checkBounds(
|
|
6149
|
-
"backgroundKeepAliveTimeout",
|
|
6150
|
-
value,
|
|
6151
|
-
MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
|
|
6152
|
-
);
|
|
6153
|
-
}
|
|
6154
|
-
function getThrottle(value) {
|
|
6155
|
-
return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
|
|
6156
|
-
}
|
|
6157
|
-
function getLostConnectionTimeout(value) {
|
|
6158
|
-
return checkBounds(
|
|
6159
|
-
"lostConnectionTimeout",
|
|
6160
|
-
value,
|
|
6161
|
-
MIN_LOST_CONNECTION_TIMEOUT,
|
|
6162
|
-
MAX_LOST_CONNECTION_TIMEOUT,
|
|
6163
|
-
RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
|
|
6164
|
-
);
|
|
6165
|
-
}
|
|
6166
|
-
|
|
6167
|
-
// src/crdts/utils.ts
|
|
6168
|
-
function toPlainLson(lson) {
|
|
6169
|
-
if (lson instanceof LiveObject) {
|
|
6170
|
-
return {
|
|
6171
|
-
liveblocksType: "LiveObject",
|
|
6172
|
-
data: Object.fromEntries(
|
|
6173
|
-
Object.entries(lson.toObject()).flatMap(
|
|
6174
|
-
([key, value]) => value !== void 0 ? [[key, toPlainLson(value)]] : []
|
|
6175
|
-
)
|
|
6176
|
-
)
|
|
6177
|
-
};
|
|
6178
|
-
} else if (lson instanceof LiveMap) {
|
|
6179
|
-
return {
|
|
6180
|
-
liveblocksType: "LiveMap",
|
|
6181
|
-
data: Object.fromEntries(
|
|
6182
|
-
[...lson].map(([key, value]) => [key, toPlainLson(value)])
|
|
6183
|
-
)
|
|
6184
|
-
};
|
|
6185
|
-
} else if (lson instanceof LiveList) {
|
|
6186
|
-
return {
|
|
6187
|
-
liveblocksType: "LiveList",
|
|
6188
|
-
data: [...lson].map((item) => toPlainLson(item))
|
|
6189
|
-
};
|
|
6190
|
-
} else {
|
|
6191
|
-
return lson;
|
|
6192
|
-
}
|
|
6193
|
-
}
|
|
6194
|
-
|
|
6195
|
-
// src/immutable.ts
|
|
6196
|
-
function lsonObjectToJson(obj) {
|
|
6197
|
-
const result = {};
|
|
6198
|
-
for (const key in obj) {
|
|
6199
|
-
const val = obj[key];
|
|
6200
|
-
if (val !== void 0) {
|
|
6201
|
-
result[key] = lsonToJson(val);
|
|
6202
|
-
}
|
|
6203
|
-
}
|
|
6204
|
-
return result;
|
|
6205
|
-
}
|
|
6206
|
-
function liveObjectToJson(liveObject) {
|
|
6207
|
-
return lsonObjectToJson(liveObject.toObject());
|
|
6208
|
-
}
|
|
6209
|
-
function liveMapToJson(map) {
|
|
6210
|
-
const result = {};
|
|
6211
|
-
for (const [key, value] of map.entries()) {
|
|
6212
|
-
result[key] = lsonToJson(value);
|
|
6213
|
-
}
|
|
6214
|
-
return result;
|
|
6215
|
-
}
|
|
6216
|
-
function lsonListToJson(value) {
|
|
6217
|
-
return value.map(lsonToJson);
|
|
6218
|
-
}
|
|
6219
|
-
function liveListToJson(value) {
|
|
6220
|
-
return lsonListToJson(value.toArray());
|
|
6221
|
-
}
|
|
6222
|
-
function lsonToJson(value) {
|
|
6223
|
-
if (value instanceof LiveObject) {
|
|
6224
|
-
return liveObjectToJson(value);
|
|
6225
|
-
} else if (value instanceof LiveList) {
|
|
6226
|
-
return liveListToJson(value);
|
|
6227
|
-
} else if (value instanceof LiveMap) {
|
|
6228
|
-
return liveMapToJson(value);
|
|
6229
|
-
} else if (value instanceof LiveRegister) {
|
|
6230
|
-
return value.data;
|
|
6231
|
-
}
|
|
6232
|
-
if (Array.isArray(value)) {
|
|
6233
|
-
return lsonListToJson(value);
|
|
6234
|
-
} else if (isPlainObject(value)) {
|
|
6235
|
-
return lsonObjectToJson(value);
|
|
6236
|
-
}
|
|
6237
|
-
return value;
|
|
6238
|
-
}
|
|
6239
|
-
function deepLiveify(value) {
|
|
6240
|
-
if (Array.isArray(value)) {
|
|
6241
|
-
return new LiveList(value.map(deepLiveify));
|
|
6242
|
-
} else if (isPlainObject(value)) {
|
|
6243
|
-
const init = {};
|
|
6244
|
-
for (const key in value) {
|
|
6245
|
-
const val = value[key];
|
|
6246
|
-
if (val === void 0) {
|
|
6247
|
-
continue;
|
|
6248
|
-
}
|
|
6249
|
-
init[key] = deepLiveify(val);
|
|
6250
|
-
}
|
|
6251
|
-
return new LiveObject(init);
|
|
6252
|
-
} else {
|
|
6253
|
-
return value;
|
|
6254
|
-
}
|
|
6255
|
-
}
|
|
6256
|
-
function patchLiveList(liveList, prev, next) {
|
|
6257
|
-
let i = 0;
|
|
6258
|
-
let prevEnd = prev.length - 1;
|
|
6259
|
-
let nextEnd = next.length - 1;
|
|
6260
|
-
let prevNode = prev[0];
|
|
6261
|
-
let nextNode = next[0];
|
|
6262
|
-
outer: {
|
|
6263
|
-
while (prevNode === nextNode) {
|
|
6264
|
-
++i;
|
|
6265
|
-
if (i > prevEnd || i > nextEnd) {
|
|
6266
|
-
break outer;
|
|
6267
|
-
}
|
|
6268
|
-
prevNode = prev[i];
|
|
6269
|
-
nextNode = next[i];
|
|
6270
|
-
}
|
|
6271
|
-
prevNode = prev[prevEnd];
|
|
6272
|
-
nextNode = next[nextEnd];
|
|
6273
|
-
while (prevNode === nextNode) {
|
|
6274
|
-
prevEnd--;
|
|
6275
|
-
nextEnd--;
|
|
6276
|
-
if (i > prevEnd || i > nextEnd) {
|
|
6277
|
-
break outer;
|
|
6278
|
-
}
|
|
6279
|
-
prevNode = prev[prevEnd];
|
|
6280
|
-
nextNode = next[nextEnd];
|
|
6281
|
-
}
|
|
6282
|
-
}
|
|
6283
|
-
if (i > prevEnd) {
|
|
6284
|
-
if (i <= nextEnd) {
|
|
6285
|
-
while (i <= nextEnd) {
|
|
6286
|
-
liveList.insert(deepLiveify(next[i]), i);
|
|
6287
|
-
i++;
|
|
6288
|
-
}
|
|
6289
|
-
}
|
|
6290
|
-
} else if (i > nextEnd) {
|
|
6291
|
-
let localI = i;
|
|
6292
|
-
while (localI <= prevEnd) {
|
|
6293
|
-
liveList.delete(i);
|
|
6294
|
-
localI++;
|
|
6295
|
-
}
|
|
6296
|
-
} else {
|
|
6297
|
-
while (i <= prevEnd && i <= nextEnd) {
|
|
6298
|
-
prevNode = prev[i];
|
|
6299
|
-
nextNode = next[i];
|
|
6300
|
-
const liveListNode = liveList.get(i);
|
|
6301
|
-
if (isLiveObject(liveListNode) && isPlainObject(prevNode) && isPlainObject(nextNode)) {
|
|
6302
|
-
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
6303
|
-
} else {
|
|
6304
|
-
liveList.set(i, deepLiveify(nextNode));
|
|
6305
|
-
}
|
|
6306
|
-
i++;
|
|
6307
|
-
}
|
|
6308
|
-
while (i <= nextEnd) {
|
|
6309
|
-
liveList.insert(deepLiveify(next[i]), i);
|
|
6310
|
-
i++;
|
|
6311
|
-
}
|
|
6312
|
-
let localI = i;
|
|
6313
|
-
while (localI <= prevEnd) {
|
|
6314
|
-
liveList.delete(i);
|
|
6315
|
-
localI++;
|
|
6316
|
-
}
|
|
6317
|
-
}
|
|
6318
|
-
}
|
|
6319
|
-
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
6320
|
-
if (process.env.NODE_ENV !== "production") {
|
|
6321
|
-
const nonSerializableValue = findNonSerializableValue(next);
|
|
6322
|
-
if (nonSerializableValue) {
|
|
6323
|
-
error2(
|
|
6324
|
-
`New state path: '${nonSerializableValue.path}' value: '${String(
|
|
6325
|
-
nonSerializableValue.value
|
|
6326
|
-
)}' is not serializable.
|
|
6327
|
-
Only serializable value can be synced with Liveblocks.`
|
|
6328
|
-
);
|
|
6329
|
-
return;
|
|
6330
|
-
}
|
|
6331
|
-
}
|
|
6332
|
-
const value = liveObject.get(key);
|
|
6333
|
-
if (next === void 0) {
|
|
6334
|
-
liveObject.delete(key);
|
|
6335
|
-
} else if (value === void 0) {
|
|
6336
|
-
liveObject.set(key, deepLiveify(next));
|
|
6337
|
-
} else if (prev === next) {
|
|
6338
|
-
return;
|
|
6339
|
-
} else if (isLiveList(value) && Array.isArray(prev) && Array.isArray(next)) {
|
|
6340
|
-
patchLiveList(value, prev, next);
|
|
6341
|
-
} else if (isLiveObject(value) && isPlainObject(prev) && isPlainObject(next)) {
|
|
6342
|
-
patchLiveObject(value, prev, next);
|
|
6343
|
-
} else {
|
|
6344
|
-
liveObject.set(key, deepLiveify(next));
|
|
6345
|
-
}
|
|
6346
|
-
}
|
|
6347
|
-
function patchLiveObject(root, prev, next) {
|
|
6348
|
-
const updates = {};
|
|
6349
|
-
for (const key in next) {
|
|
6350
|
-
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
6351
|
-
}
|
|
6352
|
-
for (const key in prev) {
|
|
6353
|
-
if (next[key] === void 0) {
|
|
6354
|
-
root.delete(key);
|
|
6355
|
-
}
|
|
6356
|
-
}
|
|
6357
|
-
if (Object.keys(updates).length > 0) {
|
|
6358
|
-
root.update(updates);
|
|
6359
|
-
}
|
|
6360
|
-
}
|
|
6361
|
-
function getParentsPath(node) {
|
|
6362
|
-
const path = [];
|
|
6363
|
-
while (node.parent.type === "HasParent") {
|
|
6364
|
-
if (isLiveList(node.parent.node)) {
|
|
6365
|
-
path.push(node.parent.node._indexOfPosition(node.parent.key));
|
|
6366
|
-
} else {
|
|
6367
|
-
path.push(node.parent.key);
|
|
6368
|
-
}
|
|
6369
|
-
node = node.parent.node;
|
|
6370
|
-
}
|
|
6371
|
-
return path;
|
|
6372
|
-
}
|
|
6373
|
-
function legacy_patchImmutableObject(state, updates) {
|
|
6374
|
-
return updates.reduce(
|
|
6375
|
-
(state2, update) => legacy_patchImmutableObjectWithUpdate(state2, update),
|
|
6376
|
-
state
|
|
6377
|
-
);
|
|
6378
|
-
}
|
|
6379
|
-
function legacy_patchImmutableObjectWithUpdate(state, update) {
|
|
6380
|
-
const path = getParentsPath(update.node);
|
|
6381
|
-
return legacy_patchImmutableNode(state, path, update);
|
|
6382
|
-
}
|
|
6383
|
-
function legacy_patchImmutableNode(state, path, update) {
|
|
6384
|
-
const pathItem = path.pop();
|
|
6385
|
-
if (pathItem === void 0) {
|
|
6386
|
-
switch (update.type) {
|
|
6387
|
-
case "LiveObject": {
|
|
6388
|
-
if (!isJsonObject(state)) {
|
|
6389
|
-
throw new Error(
|
|
6390
|
-
"Internal: received update on LiveObject but state was not an object"
|
|
6391
|
-
);
|
|
6392
|
-
}
|
|
6393
|
-
const newState = Object.assign({}, state);
|
|
6394
|
-
for (const key in update.updates) {
|
|
6395
|
-
if (update.updates[key]?.type === "update") {
|
|
6396
|
-
const val = update.node.get(key);
|
|
6397
|
-
if (val !== void 0) {
|
|
6398
|
-
newState[key] = lsonToJson(val);
|
|
6399
|
-
}
|
|
6400
|
-
} else if (update.updates[key]?.type === "delete") {
|
|
6401
|
-
delete newState[key];
|
|
6402
|
-
}
|
|
6403
|
-
}
|
|
6404
|
-
return newState;
|
|
6405
|
-
}
|
|
6406
|
-
case "LiveList": {
|
|
6407
|
-
if (!Array.isArray(state)) {
|
|
6408
|
-
throw new Error(
|
|
6409
|
-
"Internal: received update on LiveList but state was not an array"
|
|
6410
|
-
);
|
|
6411
|
-
}
|
|
6412
|
-
let newState = state.map((x) => x);
|
|
6413
|
-
for (const listUpdate of update.updates) {
|
|
6414
|
-
if (listUpdate.type === "set") {
|
|
6415
|
-
newState = newState.map(
|
|
6416
|
-
(item, index) => index === listUpdate.index ? lsonToJson(listUpdate.item) : item
|
|
6417
|
-
);
|
|
6418
|
-
} else if (listUpdate.type === "insert") {
|
|
6419
|
-
if (listUpdate.index === newState.length) {
|
|
6420
|
-
newState.push(lsonToJson(listUpdate.item));
|
|
6421
|
-
} else {
|
|
6422
|
-
newState = [
|
|
6423
|
-
...newState.slice(0, listUpdate.index),
|
|
6424
|
-
lsonToJson(listUpdate.item),
|
|
6425
|
-
...newState.slice(listUpdate.index)
|
|
6426
|
-
];
|
|
6427
|
-
}
|
|
6428
|
-
} else if (listUpdate.type === "delete") {
|
|
6429
|
-
newState.splice(listUpdate.index, 1);
|
|
6430
|
-
} else if (listUpdate.type === "move") {
|
|
6431
|
-
if (listUpdate.previousIndex > listUpdate.index) {
|
|
6432
|
-
newState = [
|
|
6433
|
-
...newState.slice(0, listUpdate.index),
|
|
6434
|
-
lsonToJson(listUpdate.item),
|
|
6435
|
-
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
6436
|
-
...newState.slice(listUpdate.previousIndex + 1)
|
|
6437
|
-
];
|
|
6438
|
-
} else {
|
|
6439
|
-
newState = [
|
|
6440
|
-
...newState.slice(0, listUpdate.previousIndex),
|
|
6441
|
-
...newState.slice(
|
|
6442
|
-
listUpdate.previousIndex + 1,
|
|
6443
|
-
listUpdate.index + 1
|
|
6444
|
-
),
|
|
6445
|
-
lsonToJson(listUpdate.item),
|
|
6446
|
-
...newState.slice(listUpdate.index + 1)
|
|
6447
|
-
];
|
|
6448
|
-
}
|
|
6449
|
-
}
|
|
6450
|
-
}
|
|
6451
|
-
return newState;
|
|
6452
|
-
}
|
|
6453
|
-
case "LiveMap": {
|
|
6454
|
-
if (!isJsonObject(state)) {
|
|
6455
|
-
throw new Error(
|
|
6456
|
-
"Internal: received update on LiveMap but state was not an object"
|
|
6457
|
-
);
|
|
6270
|
+
return cb(others, internalEvent);
|
|
6271
|
+
});
|
|
6458
6272
|
}
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
} else if (update.updates[key]?.type === "delete") {
|
|
6467
|
-
delete newState[key];
|
|
6468
|
-
}
|
|
6273
|
+
case "error":
|
|
6274
|
+
return events.error.subscribe(callback);
|
|
6275
|
+
case "connection": {
|
|
6276
|
+
const cb = callback;
|
|
6277
|
+
return events.status.subscribe(
|
|
6278
|
+
(status) => cb(newToLegacyStatus(status))
|
|
6279
|
+
);
|
|
6469
6280
|
}
|
|
6470
|
-
|
|
6281
|
+
case "status":
|
|
6282
|
+
return events.status.subscribe(callback);
|
|
6283
|
+
case "lost-connection":
|
|
6284
|
+
return events.lostConnection.subscribe(
|
|
6285
|
+
callback
|
|
6286
|
+
);
|
|
6287
|
+
case "history":
|
|
6288
|
+
return events.history.subscribe(callback);
|
|
6289
|
+
case "storage-status":
|
|
6290
|
+
return events.storageStatus.subscribe(
|
|
6291
|
+
callback
|
|
6292
|
+
);
|
|
6293
|
+
default:
|
|
6294
|
+
return assertNever(
|
|
6295
|
+
first,
|
|
6296
|
+
`"${String(first)}" is not a valid event name`
|
|
6297
|
+
);
|
|
6471
6298
|
}
|
|
6472
6299
|
}
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
);
|
|
6481
|
-
return newArray;
|
|
6482
|
-
} else if (isJsonObject(state)) {
|
|
6483
|
-
const node = state[pathItem];
|
|
6484
|
-
if (node === void 0) {
|
|
6485
|
-
return state;
|
|
6486
|
-
} else {
|
|
6487
|
-
const stateAsObj = state;
|
|
6488
|
-
return {
|
|
6489
|
-
...stateAsObj,
|
|
6490
|
-
[pathItem]: legacy_patchImmutableNode(node, path, update)
|
|
6491
|
-
};
|
|
6300
|
+
if (second === void 0 || typeof first === "function") {
|
|
6301
|
+
if (typeof first === "function") {
|
|
6302
|
+
const storageCallback = first;
|
|
6303
|
+
return events.storage.subscribe(storageCallback);
|
|
6304
|
+
} else {
|
|
6305
|
+
throw new Error("Please specify a listener callback");
|
|
6306
|
+
}
|
|
6492
6307
|
}
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
}
|
|
6503
|
-
for (let i = 0; i < xs.length; i++) {
|
|
6504
|
-
if (!Object.is(xs[i], ys[i])) {
|
|
6505
|
-
return false;
|
|
6308
|
+
if (isLiveNode(first)) {
|
|
6309
|
+
const node = first;
|
|
6310
|
+
if (options?.isDeep) {
|
|
6311
|
+
const storageCallback = second;
|
|
6312
|
+
return subscribeToLiveStructureDeeply(node, storageCallback);
|
|
6313
|
+
} else {
|
|
6314
|
+
const nodeCallback = second;
|
|
6315
|
+
return subscribeToLiveStructureShallowly(node, nodeCallback);
|
|
6316
|
+
}
|
|
6506
6317
|
}
|
|
6318
|
+
throw new Error(
|
|
6319
|
+
`${String(first)} is not a value that can be subscribed to.`
|
|
6320
|
+
);
|
|
6507
6321
|
}
|
|
6508
|
-
return
|
|
6322
|
+
return subscribe;
|
|
6509
6323
|
}
|
|
6510
|
-
function
|
|
6511
|
-
|
|
6512
|
-
return false;
|
|
6513
|
-
}
|
|
6514
|
-
const keysA = Object.keys(objA);
|
|
6515
|
-
if (keysA.length !== Object.keys(objB).length) {
|
|
6516
|
-
return false;
|
|
6517
|
-
}
|
|
6518
|
-
return keysA.every(
|
|
6519
|
-
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
6520
|
-
);
|
|
6324
|
+
function isRoomEventName(value) {
|
|
6325
|
+
return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "history" || value === "status" || value === "storage-status" || value === "lost-connection" || value === "connection";
|
|
6521
6326
|
}
|
|
6522
|
-
function
|
|
6523
|
-
|
|
6524
|
-
return
|
|
6525
|
-
}
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6327
|
+
function makeAuthDelegateForRoom(roomId, authManager) {
|
|
6328
|
+
return async () => {
|
|
6329
|
+
return authManager.getAuthValue("room:read", roomId);
|
|
6330
|
+
};
|
|
6331
|
+
}
|
|
6332
|
+
function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
|
|
6333
|
+
return (authValue) => {
|
|
6334
|
+
const ws = WebSocketPolyfill ?? (typeof WebSocket === "undefined" ? void 0 : WebSocket);
|
|
6335
|
+
if (ws === void 0) {
|
|
6336
|
+
throw new StopRetrying(
|
|
6337
|
+
"To use Liveblocks client in a non-DOM environment, you need to provide a WebSocket polyfill."
|
|
6338
|
+
);
|
|
6531
6339
|
}
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6340
|
+
const url = new URL(baseUrl);
|
|
6341
|
+
url.protocol = url.protocol === "http:" ? "ws" : "wss";
|
|
6342
|
+
url.pathname = "/v7";
|
|
6343
|
+
url.searchParams.set("roomId", roomId);
|
|
6344
|
+
if (authValue.type === "secret") {
|
|
6345
|
+
url.searchParams.set("tok", authValue.token.raw);
|
|
6346
|
+
} else if (authValue.type === "public") {
|
|
6347
|
+
url.searchParams.set("pubkey", authValue.publicApiKey);
|
|
6348
|
+
} else {
|
|
6349
|
+
return assertNever(authValue, "Unhandled case");
|
|
6350
|
+
}
|
|
6351
|
+
url.searchParams.set("version", PKG_VERSION || "dev");
|
|
6352
|
+
return new ws(url.toString());
|
|
6353
|
+
};
|
|
6535
6354
|
}
|
|
6536
6355
|
|
|
6537
|
-
// src/
|
|
6538
|
-
var
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6356
|
+
// src/client.ts
|
|
6357
|
+
var MIN_THROTTLE = 16;
|
|
6358
|
+
var MAX_THROTTLE = 1e3;
|
|
6359
|
+
var DEFAULT_THROTTLE = 100;
|
|
6360
|
+
var MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT = 15e3;
|
|
6361
|
+
var MIN_LOST_CONNECTION_TIMEOUT = 200;
|
|
6362
|
+
var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
|
|
6363
|
+
var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
|
|
6364
|
+
var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
|
|
6365
|
+
function getBaseUrlFromClientOptions(clientOptions) {
|
|
6366
|
+
if ("liveblocksServer" in clientOptions) {
|
|
6367
|
+
throw new Error("Client option no longer supported");
|
|
6368
|
+
}
|
|
6369
|
+
if (typeof clientOptions.baseUrl === "string" && clientOptions.baseUrl.startsWith("http")) {
|
|
6370
|
+
return clientOptions.baseUrl;
|
|
6543
6371
|
} else {
|
|
6544
|
-
return
|
|
6372
|
+
return DEFAULT_BASE_URL;
|
|
6545
6373
|
}
|
|
6546
6374
|
}
|
|
6547
|
-
function
|
|
6548
|
-
const
|
|
6549
|
-
const
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6375
|
+
function createClient(options) {
|
|
6376
|
+
const clientOptions = options;
|
|
6377
|
+
const throttleDelay = getThrottle(clientOptions.throttle ?? DEFAULT_THROTTLE);
|
|
6378
|
+
const lostConnectionTimeout = getLostConnectionTimeout(
|
|
6379
|
+
clientOptions.lostConnectionTimeout ?? DEFAULT_LOST_CONNECTION_TIMEOUT
|
|
6380
|
+
);
|
|
6381
|
+
const backgroundKeepAliveTimeout = getBackgroundKeepAliveTimeout(
|
|
6382
|
+
clientOptions.backgroundKeepAliveTimeout
|
|
6383
|
+
);
|
|
6384
|
+
const authManager = createAuthManager(options);
|
|
6385
|
+
const roomsById = /* @__PURE__ */ new Map();
|
|
6386
|
+
function teardownRoom(room) {
|
|
6387
|
+
unlinkDevTools(room.id);
|
|
6388
|
+
roomsById.delete(room.id);
|
|
6389
|
+
room.destroy();
|
|
6390
|
+
}
|
|
6391
|
+
function leaseRoom(info) {
|
|
6392
|
+
const leave = () => {
|
|
6393
|
+
const self = leave;
|
|
6394
|
+
if (!info.unsubs.delete(self)) {
|
|
6395
|
+
warn(
|
|
6396
|
+
"This leave function was already called. Calling it more than once has no effect."
|
|
6397
|
+
);
|
|
6398
|
+
} else {
|
|
6399
|
+
if (info.unsubs.size === 0) {
|
|
6400
|
+
teardownRoom(info.room);
|
|
6401
|
+
}
|
|
6402
|
+
}
|
|
6403
|
+
};
|
|
6404
|
+
info.unsubs.add(leave);
|
|
6405
|
+
return {
|
|
6406
|
+
room: info.room,
|
|
6407
|
+
leave
|
|
6408
|
+
};
|
|
6409
|
+
}
|
|
6410
|
+
function enterRoom(roomId, options2) {
|
|
6411
|
+
const existing = roomsById.get(roomId);
|
|
6412
|
+
if (existing !== void 0) {
|
|
6413
|
+
return leaseRoom(existing);
|
|
6414
|
+
}
|
|
6415
|
+
deprecateIf(
|
|
6416
|
+
options2.initialPresence === null || options2.initialPresence === void 0,
|
|
6417
|
+
"Please provide an initial presence value for the current user when entering the room."
|
|
6418
|
+
);
|
|
6419
|
+
const baseUrl = getBaseUrlFromClientOptions(clientOptions);
|
|
6420
|
+
const newRoom = createRoom(
|
|
6421
|
+
{
|
|
6422
|
+
initialPresence: options2.initialPresence ?? {},
|
|
6423
|
+
initialStorage: options2.initialStorage
|
|
6424
|
+
},
|
|
6425
|
+
{
|
|
6426
|
+
roomId,
|
|
6427
|
+
throttleDelay,
|
|
6428
|
+
lostConnectionTimeout,
|
|
6429
|
+
backgroundKeepAliveTimeout,
|
|
6430
|
+
polyfills: clientOptions.polyfills,
|
|
6431
|
+
delegates: clientOptions.mockedDelegates ?? {
|
|
6432
|
+
createSocket: makeCreateSocketDelegateForRoom(
|
|
6433
|
+
roomId,
|
|
6434
|
+
baseUrl,
|
|
6435
|
+
clientOptions.polyfills?.WebSocket
|
|
6436
|
+
),
|
|
6437
|
+
authenticate: makeAuthDelegateForRoom(roomId, authManager)
|
|
6438
|
+
},
|
|
6439
|
+
enableDebugLogging: clientOptions.enableDebugLogging,
|
|
6440
|
+
unstable_batchedUpdates: options2?.unstable_batchedUpdates,
|
|
6441
|
+
baseUrl,
|
|
6442
|
+
unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP
|
|
6443
|
+
}
|
|
6444
|
+
);
|
|
6445
|
+
const newRoomInfo = {
|
|
6446
|
+
room: newRoom,
|
|
6447
|
+
unsubs: /* @__PURE__ */ new Set()
|
|
6448
|
+
};
|
|
6449
|
+
roomsById.set(roomId, newRoomInfo);
|
|
6450
|
+
setupDevTools(() => Array.from(roomsById.keys()));
|
|
6451
|
+
linkDevTools(roomId, newRoom);
|
|
6452
|
+
const shouldConnect = options2.autoConnect ?? options2.shouldInitiallyConnect ?? true;
|
|
6453
|
+
if (shouldConnect) {
|
|
6454
|
+
if (typeof atob === "undefined") {
|
|
6455
|
+
if (clientOptions.polyfills?.atob === void 0) {
|
|
6456
|
+
throw new Error(
|
|
6457
|
+
"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"
|
|
6458
|
+
);
|
|
6459
|
+
}
|
|
6460
|
+
global.atob = clientOptions.polyfills.atob;
|
|
6461
|
+
}
|
|
6462
|
+
newRoom.connect();
|
|
6560
6463
|
}
|
|
6464
|
+
return leaseRoom(newRoomInfo);
|
|
6561
6465
|
}
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
}
|
|
6566
|
-
try {
|
|
6567
|
-
const data = await context.promise;
|
|
6568
|
-
context.isInvalid = false;
|
|
6569
|
-
state = {
|
|
6570
|
-
isLoading: false,
|
|
6571
|
-
data
|
|
6572
|
-
};
|
|
6573
|
-
} catch (error3) {
|
|
6574
|
-
state = {
|
|
6575
|
-
isLoading: false,
|
|
6576
|
-
data: state.data,
|
|
6577
|
-
error: error3
|
|
6578
|
-
};
|
|
6579
|
-
}
|
|
6580
|
-
context.promise = void 0;
|
|
6581
|
-
notify();
|
|
6466
|
+
function enter(roomId, options2) {
|
|
6467
|
+
const { room, leave: _ } = enterRoom(roomId, options2);
|
|
6468
|
+
return room;
|
|
6582
6469
|
}
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
return
|
|
6470
|
+
function getRoom(roomId) {
|
|
6471
|
+
const room = roomsById.get(roomId)?.room;
|
|
6472
|
+
return room ? room : null;
|
|
6586
6473
|
}
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
context.promise = $asyncFunction();
|
|
6592
|
-
state = { isLoading: true, data: state.data };
|
|
6593
|
-
notify();
|
|
6594
|
-
}
|
|
6595
|
-
await resolve();
|
|
6474
|
+
function forceLeave(roomId) {
|
|
6475
|
+
const unsubs = roomsById.get(roomId)?.unsubs ?? /* @__PURE__ */ new Set();
|
|
6476
|
+
for (const unsub of unsubs) {
|
|
6477
|
+
unsub();
|
|
6596
6478
|
}
|
|
6597
|
-
return getState();
|
|
6598
6479
|
}
|
|
6599
|
-
function
|
|
6600
|
-
|
|
6480
|
+
function logout() {
|
|
6481
|
+
authManager.reset();
|
|
6482
|
+
for (const { room } of roomsById.values()) {
|
|
6483
|
+
if (!isIdle(room.getStatus())) {
|
|
6484
|
+
room.reconnect();
|
|
6485
|
+
}
|
|
6486
|
+
}
|
|
6601
6487
|
}
|
|
6602
6488
|
return {
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6489
|
+
logout,
|
|
6490
|
+
// Old, deprecated APIs
|
|
6491
|
+
enter,
|
|
6492
|
+
getRoom,
|
|
6493
|
+
leave: forceLeave,
|
|
6494
|
+
// New, preferred API
|
|
6495
|
+
enterRoom
|
|
6607
6496
|
};
|
|
6608
6497
|
}
|
|
6609
|
-
function
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
return cacheItem;
|
|
6615
|
-
}
|
|
6616
|
-
cacheItem = createCacheItem(key, asyncFunction, options);
|
|
6617
|
-
cache.set(key, cacheItem);
|
|
6618
|
-
return cacheItem;
|
|
6619
|
-
}
|
|
6620
|
-
function get(key) {
|
|
6621
|
-
return create(key).get();
|
|
6498
|
+
function checkBounds(option, value, min, max, recommendedMin) {
|
|
6499
|
+
if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
|
|
6500
|
+
throw new Error(
|
|
6501
|
+
max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
|
|
6502
|
+
);
|
|
6622
6503
|
}
|
|
6623
|
-
|
|
6624
|
-
|
|
6504
|
+
return value;
|
|
6505
|
+
}
|
|
6506
|
+
function getBackgroundKeepAliveTimeout(value) {
|
|
6507
|
+
if (value === void 0)
|
|
6508
|
+
return void 0;
|
|
6509
|
+
return checkBounds(
|
|
6510
|
+
"backgroundKeepAliveTimeout",
|
|
6511
|
+
value,
|
|
6512
|
+
MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
|
|
6513
|
+
);
|
|
6514
|
+
}
|
|
6515
|
+
function getThrottle(value) {
|
|
6516
|
+
return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
|
|
6517
|
+
}
|
|
6518
|
+
function getLostConnectionTimeout(value) {
|
|
6519
|
+
return checkBounds(
|
|
6520
|
+
"lostConnectionTimeout",
|
|
6521
|
+
value,
|
|
6522
|
+
MIN_LOST_CONNECTION_TIMEOUT,
|
|
6523
|
+
MAX_LOST_CONNECTION_TIMEOUT,
|
|
6524
|
+
RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
|
|
6525
|
+
);
|
|
6526
|
+
}
|
|
6527
|
+
|
|
6528
|
+
// src/crdts/utils.ts
|
|
6529
|
+
function toPlainLson(lson) {
|
|
6530
|
+
if (lson instanceof LiveObject) {
|
|
6531
|
+
return {
|
|
6532
|
+
liveblocksType: "LiveObject",
|
|
6533
|
+
data: Object.fromEntries(
|
|
6534
|
+
Object.entries(lson.toObject()).flatMap(
|
|
6535
|
+
([key, value]) => value !== void 0 ? [[key, toPlainLson(value)]] : []
|
|
6536
|
+
)
|
|
6537
|
+
)
|
|
6538
|
+
};
|
|
6539
|
+
} else if (lson instanceof LiveMap) {
|
|
6540
|
+
return {
|
|
6541
|
+
liveblocksType: "LiveMap",
|
|
6542
|
+
data: Object.fromEntries(
|
|
6543
|
+
[...lson].map(([key, value]) => [key, toPlainLson(value)])
|
|
6544
|
+
)
|
|
6545
|
+
};
|
|
6546
|
+
} else if (lson instanceof LiveList) {
|
|
6547
|
+
return {
|
|
6548
|
+
liveblocksType: "LiveList",
|
|
6549
|
+
data: [...lson].map((item) => toPlainLson(item))
|
|
6550
|
+
};
|
|
6551
|
+
} else {
|
|
6552
|
+
return lson;
|
|
6625
6553
|
}
|
|
6626
|
-
|
|
6627
|
-
|
|
6554
|
+
}
|
|
6555
|
+
|
|
6556
|
+
// src/immutable.ts
|
|
6557
|
+
function lsonObjectToJson(obj) {
|
|
6558
|
+
const result = {};
|
|
6559
|
+
for (const key in obj) {
|
|
6560
|
+
const val = obj[key];
|
|
6561
|
+
if (val !== void 0) {
|
|
6562
|
+
result[key] = lsonToJson(val);
|
|
6563
|
+
}
|
|
6628
6564
|
}
|
|
6629
|
-
|
|
6630
|
-
|
|
6565
|
+
return result;
|
|
6566
|
+
}
|
|
6567
|
+
function liveObjectToJson(liveObject) {
|
|
6568
|
+
return lsonObjectToJson(liveObject.toObject());
|
|
6569
|
+
}
|
|
6570
|
+
function liveMapToJson(map) {
|
|
6571
|
+
const result = {};
|
|
6572
|
+
for (const [key, value] of map.entries()) {
|
|
6573
|
+
result[key] = lsonToJson(value);
|
|
6631
6574
|
}
|
|
6632
|
-
|
|
6633
|
-
|
|
6575
|
+
return result;
|
|
6576
|
+
}
|
|
6577
|
+
function lsonListToJson(value) {
|
|
6578
|
+
return value.map(lsonToJson);
|
|
6579
|
+
}
|
|
6580
|
+
function liveListToJson(value) {
|
|
6581
|
+
return lsonListToJson(value.toArray());
|
|
6582
|
+
}
|
|
6583
|
+
function lsonToJson(value) {
|
|
6584
|
+
if (value instanceof LiveObject) {
|
|
6585
|
+
return liveObjectToJson(value);
|
|
6586
|
+
} else if (value instanceof LiveList) {
|
|
6587
|
+
return liveListToJson(value);
|
|
6588
|
+
} else if (value instanceof LiveMap) {
|
|
6589
|
+
return liveMapToJson(value);
|
|
6590
|
+
} else if (value instanceof LiveRegister) {
|
|
6591
|
+
return value.data;
|
|
6634
6592
|
}
|
|
6635
|
-
|
|
6636
|
-
return
|
|
6593
|
+
if (Array.isArray(value)) {
|
|
6594
|
+
return lsonListToJson(value);
|
|
6595
|
+
} else if (isPlainObject(value)) {
|
|
6596
|
+
return lsonObjectToJson(value);
|
|
6637
6597
|
}
|
|
6638
|
-
|
|
6639
|
-
|
|
6598
|
+
return value;
|
|
6599
|
+
}
|
|
6600
|
+
function deepLiveify(value) {
|
|
6601
|
+
if (Array.isArray(value)) {
|
|
6602
|
+
return new LiveList(value.map(deepLiveify));
|
|
6603
|
+
} else if (isPlainObject(value)) {
|
|
6604
|
+
const init = {};
|
|
6605
|
+
for (const key in value) {
|
|
6606
|
+
const val = value[key];
|
|
6607
|
+
if (val === void 0) {
|
|
6608
|
+
continue;
|
|
6609
|
+
}
|
|
6610
|
+
init[key] = deepLiveify(val);
|
|
6611
|
+
}
|
|
6612
|
+
return new LiveObject(init);
|
|
6613
|
+
} else {
|
|
6614
|
+
return value;
|
|
6640
6615
|
}
|
|
6641
|
-
return {
|
|
6642
|
-
create,
|
|
6643
|
-
get,
|
|
6644
|
-
getState,
|
|
6645
|
-
revalidate,
|
|
6646
|
-
subscribe,
|
|
6647
|
-
subscribeOnce,
|
|
6648
|
-
has,
|
|
6649
|
-
clear
|
|
6650
|
-
};
|
|
6651
6616
|
}
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
let
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6617
|
+
function patchLiveList(liveList, prev, next) {
|
|
6618
|
+
let i = 0;
|
|
6619
|
+
let prevEnd = prev.length - 1;
|
|
6620
|
+
let nextEnd = next.length - 1;
|
|
6621
|
+
let prevNode = prev[0];
|
|
6622
|
+
let nextNode = next[0];
|
|
6623
|
+
outer: {
|
|
6624
|
+
while (prevNode === nextNode) {
|
|
6625
|
+
++i;
|
|
6626
|
+
if (i > prevEnd || i > nextEnd) {
|
|
6627
|
+
break outer;
|
|
6628
|
+
}
|
|
6629
|
+
prevNode = prev[i];
|
|
6630
|
+
nextNode = next[i];
|
|
6631
|
+
}
|
|
6632
|
+
prevNode = prev[prevEnd];
|
|
6633
|
+
nextNode = next[nextEnd];
|
|
6634
|
+
while (prevNode === nextNode) {
|
|
6635
|
+
prevEnd--;
|
|
6636
|
+
nextEnd--;
|
|
6637
|
+
if (i > prevEnd || i > nextEnd) {
|
|
6638
|
+
break outer;
|
|
6639
|
+
}
|
|
6640
|
+
prevNode = prev[prevEnd];
|
|
6641
|
+
nextNode = next[nextEnd];
|
|
6665
6642
|
}
|
|
6666
|
-
void callback();
|
|
6667
|
-
}
|
|
6668
|
-
function schedule(interval) {
|
|
6669
|
-
context = {
|
|
6670
|
-
state: "running",
|
|
6671
|
-
interval: context.state !== "stopped" ? context.interval : interval,
|
|
6672
|
-
lastScheduledAt: performance.now(),
|
|
6673
|
-
timeoutHandle: setTimeout(poll, interval),
|
|
6674
|
-
remainingInterval: null
|
|
6675
|
-
};
|
|
6676
6643
|
}
|
|
6677
|
-
|
|
6678
|
-
if (
|
|
6679
|
-
|
|
6644
|
+
if (i > prevEnd) {
|
|
6645
|
+
if (i <= nextEnd) {
|
|
6646
|
+
while (i <= nextEnd) {
|
|
6647
|
+
liveList.insert(deepLiveify(next[i]), i);
|
|
6648
|
+
i++;
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
} else if (i > nextEnd) {
|
|
6652
|
+
let localI = i;
|
|
6653
|
+
while (localI <= prevEnd) {
|
|
6654
|
+
liveList.delete(i);
|
|
6655
|
+
localI++;
|
|
6656
|
+
}
|
|
6657
|
+
} else {
|
|
6658
|
+
while (i <= prevEnd && i <= nextEnd) {
|
|
6659
|
+
prevNode = prev[i];
|
|
6660
|
+
nextNode = next[i];
|
|
6661
|
+
const liveListNode = liveList.get(i);
|
|
6662
|
+
if (isLiveObject(liveListNode) && isPlainObject(prevNode) && isPlainObject(nextNode)) {
|
|
6663
|
+
patchLiveObject(liveListNode, prevNode, nextNode);
|
|
6664
|
+
} else {
|
|
6665
|
+
liveList.set(i, deepLiveify(nextNode));
|
|
6666
|
+
}
|
|
6667
|
+
i++;
|
|
6668
|
+
}
|
|
6669
|
+
while (i <= nextEnd) {
|
|
6670
|
+
liveList.insert(deepLiveify(next[i]), i);
|
|
6671
|
+
i++;
|
|
6672
|
+
}
|
|
6673
|
+
let localI = i;
|
|
6674
|
+
while (localI <= prevEnd) {
|
|
6675
|
+
liveList.delete(i);
|
|
6676
|
+
localI++;
|
|
6680
6677
|
}
|
|
6681
|
-
context = {
|
|
6682
|
-
state: "running",
|
|
6683
|
-
interval: context.interval,
|
|
6684
|
-
lastScheduledAt: context.lastScheduledAt,
|
|
6685
|
-
timeoutHandle: setTimeout(poll, remaining),
|
|
6686
|
-
remainingInterval: null
|
|
6687
|
-
};
|
|
6688
6678
|
}
|
|
6689
|
-
|
|
6690
|
-
|
|
6679
|
+
}
|
|
6680
|
+
function patchLiveObjectKey(liveObject, key, prev, next) {
|
|
6681
|
+
if (process.env.NODE_ENV !== "production") {
|
|
6682
|
+
const nonSerializableValue = findNonSerializableValue(next);
|
|
6683
|
+
if (nonSerializableValue) {
|
|
6684
|
+
error2(
|
|
6685
|
+
`New state path: '${nonSerializableValue.path}' value: '${String(
|
|
6686
|
+
nonSerializableValue.value
|
|
6687
|
+
)}' is not serializable.
|
|
6688
|
+
Only serializable value can be synced with Liveblocks.`
|
|
6689
|
+
);
|
|
6691
6690
|
return;
|
|
6692
6691
|
}
|
|
6693
|
-
schedule(interval);
|
|
6694
6692
|
}
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6693
|
+
const value = liveObject.get(key);
|
|
6694
|
+
if (next === void 0) {
|
|
6695
|
+
liveObject.delete(key);
|
|
6696
|
+
} else if (value === void 0) {
|
|
6697
|
+
liveObject.set(key, deepLiveify(next));
|
|
6698
|
+
} else if (prev === next) {
|
|
6699
|
+
return;
|
|
6700
|
+
} else if (isLiveList(value) && Array.isArray(prev) && Array.isArray(next)) {
|
|
6701
|
+
patchLiveList(value, prev, next);
|
|
6702
|
+
} else if (isLiveObject(value) && isPlainObject(prev) && isPlainObject(next)) {
|
|
6703
|
+
patchLiveObject(value, prev, next);
|
|
6704
|
+
} else {
|
|
6705
|
+
liveObject.set(key, deepLiveify(next));
|
|
6698
6706
|
}
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
context = {
|
|
6705
|
-
state: "paused",
|
|
6706
|
-
interval: context.interval,
|
|
6707
|
-
lastScheduledAt: context.lastScheduledAt,
|
|
6708
|
-
timeoutHandle: null,
|
|
6709
|
-
remainingInterval: context.interval - (performance.now() - context.lastScheduledAt)
|
|
6710
|
-
};
|
|
6707
|
+
}
|
|
6708
|
+
function patchLiveObject(root, prev, next) {
|
|
6709
|
+
const updates = {};
|
|
6710
|
+
for (const key in next) {
|
|
6711
|
+
patchLiveObjectKey(root, key, prev[key], next[key]);
|
|
6711
6712
|
}
|
|
6712
|
-
|
|
6713
|
-
if (
|
|
6714
|
-
|
|
6713
|
+
for (const key in prev) {
|
|
6714
|
+
if (next[key] === void 0) {
|
|
6715
|
+
root.delete(key);
|
|
6715
6716
|
}
|
|
6716
|
-
scheduleRemaining(context.remainingInterval);
|
|
6717
6717
|
}
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6718
|
+
if (Object.keys(updates).length > 0) {
|
|
6719
|
+
root.update(updates);
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
function getParentsPath(node) {
|
|
6723
|
+
const path = [];
|
|
6724
|
+
while (node.parent.type === "HasParent") {
|
|
6725
|
+
if (isLiveList(node.parent.node)) {
|
|
6726
|
+
path.push(node.parent.node._indexOfPosition(node.parent.key));
|
|
6727
|
+
} else {
|
|
6728
|
+
path.push(node.parent.key);
|
|
6724
6729
|
}
|
|
6725
|
-
|
|
6726
|
-
state: "stopped",
|
|
6727
|
-
interval: null,
|
|
6728
|
-
lastScheduledAt: null,
|
|
6729
|
-
timeoutHandle: null,
|
|
6730
|
-
remainingInterval: null
|
|
6731
|
-
};
|
|
6730
|
+
node = node.parent.node;
|
|
6732
6731
|
}
|
|
6733
|
-
return
|
|
6734
|
-
start,
|
|
6735
|
-
restart,
|
|
6736
|
-
pause,
|
|
6737
|
-
resume,
|
|
6738
|
-
stop
|
|
6739
|
-
};
|
|
6732
|
+
return path;
|
|
6740
6733
|
}
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6734
|
+
function legacy_patchImmutableObject(state, updates) {
|
|
6735
|
+
return updates.reduce(
|
|
6736
|
+
(state2, update) => legacy_patchImmutableObjectWithUpdate(state2, update),
|
|
6737
|
+
state
|
|
6738
|
+
);
|
|
6739
|
+
}
|
|
6740
|
+
function legacy_patchImmutableObjectWithUpdate(state, update) {
|
|
6741
|
+
const path = getParentsPath(update.node);
|
|
6742
|
+
return legacy_patchImmutableNode(state, path, update);
|
|
6743
|
+
}
|
|
6744
|
+
function legacy_patchImmutableNode(state, path, update) {
|
|
6745
|
+
const pathItem = path.pop();
|
|
6746
|
+
if (pathItem === void 0) {
|
|
6747
|
+
switch (update.type) {
|
|
6748
|
+
case "LiveObject": {
|
|
6749
|
+
if (!isJsonObject(state)) {
|
|
6750
|
+
throw new Error(
|
|
6751
|
+
"Internal: received update on LiveObject but state was not an object"
|
|
6752
|
+
);
|
|
6753
|
+
}
|
|
6754
|
+
const newState = Object.assign({}, state);
|
|
6755
|
+
for (const key in update.updates) {
|
|
6756
|
+
if (update.updates[key]?.type === "update") {
|
|
6757
|
+
const val = update.node.get(key);
|
|
6758
|
+
if (val !== void 0) {
|
|
6759
|
+
newState[key] = lsonToJson(val);
|
|
6760
|
+
}
|
|
6761
|
+
} else if (update.updates[key]?.type === "delete") {
|
|
6762
|
+
delete newState[key];
|
|
6763
|
+
}
|
|
6764
|
+
}
|
|
6765
|
+
return newState;
|
|
6766
|
+
}
|
|
6767
|
+
case "LiveList": {
|
|
6768
|
+
if (!Array.isArray(state)) {
|
|
6769
|
+
throw new Error(
|
|
6770
|
+
"Internal: received update on LiveList but state was not an array"
|
|
6771
|
+
);
|
|
6772
|
+
}
|
|
6773
|
+
let newState = state.map((x) => x);
|
|
6774
|
+
for (const listUpdate of update.updates) {
|
|
6775
|
+
if (listUpdate.type === "set") {
|
|
6776
|
+
newState = newState.map(
|
|
6777
|
+
(item, index) => index === listUpdate.index ? lsonToJson(listUpdate.item) : item
|
|
6778
|
+
);
|
|
6779
|
+
} else if (listUpdate.type === "insert") {
|
|
6780
|
+
if (listUpdate.index === newState.length) {
|
|
6781
|
+
newState.push(lsonToJson(listUpdate.item));
|
|
6782
|
+
} else {
|
|
6783
|
+
newState = [
|
|
6784
|
+
...newState.slice(0, listUpdate.index),
|
|
6785
|
+
lsonToJson(listUpdate.item),
|
|
6786
|
+
...newState.slice(listUpdate.index)
|
|
6787
|
+
];
|
|
6788
|
+
}
|
|
6789
|
+
} else if (listUpdate.type === "delete") {
|
|
6790
|
+
newState.splice(listUpdate.index, 1);
|
|
6791
|
+
} else if (listUpdate.type === "move") {
|
|
6792
|
+
if (listUpdate.previousIndex > listUpdate.index) {
|
|
6793
|
+
newState = [
|
|
6794
|
+
...newState.slice(0, listUpdate.index),
|
|
6795
|
+
lsonToJson(listUpdate.item),
|
|
6796
|
+
...newState.slice(listUpdate.index, listUpdate.previousIndex),
|
|
6797
|
+
...newState.slice(listUpdate.previousIndex + 1)
|
|
6798
|
+
];
|
|
6799
|
+
} else {
|
|
6800
|
+
newState = [
|
|
6801
|
+
...newState.slice(0, listUpdate.previousIndex),
|
|
6802
|
+
...newState.slice(
|
|
6803
|
+
listUpdate.previousIndex + 1,
|
|
6804
|
+
listUpdate.index + 1
|
|
6805
|
+
),
|
|
6806
|
+
lsonToJson(listUpdate.item),
|
|
6807
|
+
...newState.slice(listUpdate.index + 1)
|
|
6808
|
+
];
|
|
6809
|
+
}
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6812
|
+
return newState;
|
|
6813
|
+
}
|
|
6814
|
+
case "LiveMap": {
|
|
6815
|
+
if (!isJsonObject(state)) {
|
|
6816
|
+
throw new Error(
|
|
6817
|
+
"Internal: received update on LiveMap but state was not an object"
|
|
6818
|
+
);
|
|
6819
|
+
}
|
|
6820
|
+
const newState = Object.assign({}, state);
|
|
6821
|
+
for (const key in update.updates) {
|
|
6822
|
+
if (update.updates[key]?.type === "update") {
|
|
6823
|
+
const value = update.node.get(key);
|
|
6824
|
+
if (value !== void 0) {
|
|
6825
|
+
newState[key] = lsonToJson(value);
|
|
6826
|
+
}
|
|
6827
|
+
} else if (update.updates[key]?.type === "delete") {
|
|
6828
|
+
delete newState[key];
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6831
|
+
return newState;
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
if (Array.isArray(state)) {
|
|
6836
|
+
const newArray = [...state];
|
|
6837
|
+
newArray[pathItem] = legacy_patchImmutableNode(
|
|
6838
|
+
state[pathItem],
|
|
6839
|
+
path,
|
|
6840
|
+
update
|
|
6841
|
+
);
|
|
6842
|
+
return newArray;
|
|
6843
|
+
} else if (isJsonObject(state)) {
|
|
6844
|
+
const node = state[pathItem];
|
|
6845
|
+
if (node === void 0) {
|
|
6846
|
+
return state;
|
|
6847
|
+
} else {
|
|
6848
|
+
const stateAsObj = state;
|
|
6849
|
+
return {
|
|
6850
|
+
...stateAsObj,
|
|
6851
|
+
[pathItem]: legacy_patchImmutableNode(node, path, update)
|
|
6852
|
+
};
|
|
6853
|
+
}
|
|
6854
|
+
} else {
|
|
6855
|
+
return state;
|
|
6746
6856
|
}
|
|
6747
|
-
const sortedObject = Object.keys(object).sort().reduce(
|
|
6748
|
-
(sortedObject2, key) => {
|
|
6749
|
-
sortedObject2[key] = object[key];
|
|
6750
|
-
return sortedObject2;
|
|
6751
|
-
},
|
|
6752
|
-
{}
|
|
6753
|
-
);
|
|
6754
|
-
return JSON.stringify(sortedObject, ...args);
|
|
6755
6857
|
}
|
|
6756
6858
|
|
|
6757
|
-
// src/
|
|
6758
|
-
function
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
function isCommentBodyText(element) {
|
|
6762
|
-
return "text" in element && typeof element.text === "string";
|
|
6763
|
-
}
|
|
6764
|
-
function isCommentBodyMention(element) {
|
|
6765
|
-
return "type" in element && element.type === "mention";
|
|
6766
|
-
}
|
|
6767
|
-
function isCommentBodyLink(element) {
|
|
6768
|
-
return "type" in element && element.type === "link";
|
|
6769
|
-
}
|
|
6770
|
-
var commentBodyElementsGuards = {
|
|
6771
|
-
paragraph: isCommentBodyParagraph,
|
|
6772
|
-
text: isCommentBodyText,
|
|
6773
|
-
link: isCommentBodyLink,
|
|
6774
|
-
mention: isCommentBodyMention
|
|
6775
|
-
};
|
|
6776
|
-
var commentBodyElementsTypes = {
|
|
6777
|
-
paragraph: "block",
|
|
6778
|
-
text: "inline",
|
|
6779
|
-
link: "inline",
|
|
6780
|
-
mention: "inline"
|
|
6781
|
-
};
|
|
6782
|
-
function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
6783
|
-
if (!body || !body?.content) {
|
|
6784
|
-
return;
|
|
6859
|
+
// src/lib/shallow.ts
|
|
6860
|
+
function shallowArray(xs, ys) {
|
|
6861
|
+
if (xs.length !== ys.length) {
|
|
6862
|
+
return false;
|
|
6785
6863
|
}
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
const visitor = typeof elementOrVisitor === "function" ? elementOrVisitor : possiblyVisitor;
|
|
6790
|
-
for (const block of body.content) {
|
|
6791
|
-
if (type === "all" || type === "block") {
|
|
6792
|
-
if (guard(block)) {
|
|
6793
|
-
visitor?.(block);
|
|
6794
|
-
}
|
|
6795
|
-
}
|
|
6796
|
-
if (type === "all" || type === "inline") {
|
|
6797
|
-
for (const inline of block.children) {
|
|
6798
|
-
if (guard(inline)) {
|
|
6799
|
-
visitor?.(inline);
|
|
6800
|
-
}
|
|
6801
|
-
}
|
|
6864
|
+
for (let i = 0; i < xs.length; i++) {
|
|
6865
|
+
if (!Object.is(xs[i], ys[i])) {
|
|
6866
|
+
return false;
|
|
6802
6867
|
}
|
|
6803
6868
|
}
|
|
6869
|
+
return true;
|
|
6804
6870
|
}
|
|
6805
|
-
function
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6871
|
+
function shallowObj(objA, objB) {
|
|
6872
|
+
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null || Object.prototype.toString.call(objA) !== "[object Object]" || Object.prototype.toString.call(objB) !== "[object Object]") {
|
|
6873
|
+
return false;
|
|
6874
|
+
}
|
|
6875
|
+
const keysA = Object.keys(objA);
|
|
6876
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
6877
|
+
return false;
|
|
6878
|
+
}
|
|
6879
|
+
return keysA.every(
|
|
6880
|
+
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
6811
6881
|
);
|
|
6812
|
-
return Array.from(mentionedIds);
|
|
6813
6882
|
}
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
return resolvedUsers;
|
|
6883
|
+
function shallow(a, b) {
|
|
6884
|
+
if (Object.is(a, b)) {
|
|
6885
|
+
return true;
|
|
6818
6886
|
}
|
|
6819
|
-
const
|
|
6820
|
-
const
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
const user = users?.[index];
|
|
6825
|
-
if (user) {
|
|
6826
|
-
resolvedUsers.set(userId, user);
|
|
6887
|
+
const isArrayA = Array.isArray(a);
|
|
6888
|
+
const isArrayB = Array.isArray(b);
|
|
6889
|
+
if (isArrayA || isArrayB) {
|
|
6890
|
+
if (!isArrayA || !isArrayB) {
|
|
6891
|
+
return false;
|
|
6827
6892
|
}
|
|
6893
|
+
return shallowArray(a, b);
|
|
6828
6894
|
}
|
|
6829
|
-
return
|
|
6895
|
+
return shallowObj(a, b);
|
|
6830
6896
|
}
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
">": ">",
|
|
6835
|
-
'"': """,
|
|
6836
|
-
"'": "'"
|
|
6897
|
+
|
|
6898
|
+
// src/lib/AsyncCache.ts
|
|
6899
|
+
var noop = () => {
|
|
6837
6900
|
};
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
return new HtmlSafeString([String(value)], []);
|
|
6844
|
-
}
|
|
6845
|
-
function joinHtml(strings) {
|
|
6846
|
-
if (strings.length <= 0) {
|
|
6847
|
-
return new HtmlSafeString([""], []);
|
|
6901
|
+
function isShallowEqual(a, b) {
|
|
6902
|
+
if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
|
|
6903
|
+
return false;
|
|
6904
|
+
} else {
|
|
6905
|
+
return shallow(a.data, b.data) && shallow(a.error, b.error);
|
|
6848
6906
|
}
|
|
6849
|
-
return new HtmlSafeString(
|
|
6850
|
-
["", ...Array(strings.length - 1).fill(""), ""],
|
|
6851
|
-
strings
|
|
6852
|
-
);
|
|
6853
6907
|
}
|
|
6854
|
-
function
|
|
6855
|
-
|
|
6856
|
-
|
|
6908
|
+
function createCacheItem(key, asyncFunction, options) {
|
|
6909
|
+
const $asyncFunction = async () => asyncFunction(key);
|
|
6910
|
+
const context = {
|
|
6911
|
+
isInvalid: true
|
|
6912
|
+
};
|
|
6913
|
+
let state = { isLoading: false };
|
|
6914
|
+
let previousState = { isLoading: false };
|
|
6915
|
+
const eventSource2 = makeEventSource();
|
|
6916
|
+
function notify() {
|
|
6917
|
+
const isEqual = options?.isStateEqual ?? isShallowEqual;
|
|
6918
|
+
if (!isEqual(previousState, state)) {
|
|
6919
|
+
previousState = state;
|
|
6920
|
+
eventSource2.notify(state);
|
|
6921
|
+
}
|
|
6857
6922
|
}
|
|
6858
|
-
|
|
6859
|
-
|
|
6923
|
+
async function resolve() {
|
|
6924
|
+
if (!context.promise) {
|
|
6925
|
+
return;
|
|
6926
|
+
}
|
|
6927
|
+
try {
|
|
6928
|
+
const data = await context.promise;
|
|
6929
|
+
context.isInvalid = false;
|
|
6930
|
+
state = {
|
|
6931
|
+
isLoading: false,
|
|
6932
|
+
data
|
|
6933
|
+
};
|
|
6934
|
+
} catch (error3) {
|
|
6935
|
+
state = {
|
|
6936
|
+
isLoading: false,
|
|
6937
|
+
data: state.data,
|
|
6938
|
+
error: error3
|
|
6939
|
+
};
|
|
6940
|
+
}
|
|
6941
|
+
context.promise = void 0;
|
|
6942
|
+
notify();
|
|
6860
6943
|
}
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
(
|
|
6864
|
-
);
|
|
6865
|
-
}
|
|
6866
|
-
var HtmlSafeString = class {
|
|
6867
|
-
constructor(strings, values) {
|
|
6868
|
-
this._strings = strings;
|
|
6869
|
-
this._values = values;
|
|
6944
|
+
async function revalidate() {
|
|
6945
|
+
context.isInvalid = true;
|
|
6946
|
+
return get();
|
|
6870
6947
|
}
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6948
|
+
async function get() {
|
|
6949
|
+
if (context.isInvalid) {
|
|
6950
|
+
if (!context.promise) {
|
|
6951
|
+
context.isInvalid = true;
|
|
6952
|
+
context.promise = $asyncFunction();
|
|
6953
|
+
state = { isLoading: true, data: state.data };
|
|
6954
|
+
notify();
|
|
6955
|
+
}
|
|
6956
|
+
await resolve();
|
|
6957
|
+
}
|
|
6958
|
+
return getState();
|
|
6875
6959
|
}
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6960
|
+
function getState() {
|
|
6961
|
+
return state;
|
|
6962
|
+
}
|
|
6963
|
+
return {
|
|
6964
|
+
...eventSource2.observable,
|
|
6965
|
+
get,
|
|
6966
|
+
getState,
|
|
6967
|
+
revalidate
|
|
6968
|
+
};
|
|
6879
6969
|
}
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
6897
|
-
"g"
|
|
6898
|
-
);
|
|
6899
|
-
function joinMarkdown(strings) {
|
|
6900
|
-
if (strings.length <= 0) {
|
|
6901
|
-
return new MarkdownSafeString([""], []);
|
|
6970
|
+
function createAsyncCache(asyncFunction, options) {
|
|
6971
|
+
const cache = /* @__PURE__ */ new Map();
|
|
6972
|
+
function create(key) {
|
|
6973
|
+
let cacheItem = cache.get(key);
|
|
6974
|
+
if (cacheItem) {
|
|
6975
|
+
return cacheItem;
|
|
6976
|
+
}
|
|
6977
|
+
cacheItem = createCacheItem(key, asyncFunction, options);
|
|
6978
|
+
cache.set(key, cacheItem);
|
|
6979
|
+
return cacheItem;
|
|
6980
|
+
}
|
|
6981
|
+
function get(key) {
|
|
6982
|
+
return create(key).get();
|
|
6983
|
+
}
|
|
6984
|
+
function getState(key) {
|
|
6985
|
+
return cache.get(key)?.getState();
|
|
6902
6986
|
}
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
strings
|
|
6906
|
-
);
|
|
6907
|
-
}
|
|
6908
|
-
function escapeMarkdown(value) {
|
|
6909
|
-
if (value instanceof MarkdownSafeString) {
|
|
6910
|
-
return value.toString();
|
|
6987
|
+
function revalidate(key) {
|
|
6988
|
+
return create(key).revalidate();
|
|
6911
6989
|
}
|
|
6912
|
-
|
|
6913
|
-
return
|
|
6990
|
+
function subscribe(key, callback) {
|
|
6991
|
+
return create(key).subscribe(callback) ?? noop;
|
|
6914
6992
|
}
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
(character) => markdownEscapables[character]
|
|
6918
|
-
);
|
|
6919
|
-
}
|
|
6920
|
-
var MarkdownSafeString = class {
|
|
6921
|
-
constructor(strings, values) {
|
|
6922
|
-
this._strings = strings;
|
|
6923
|
-
this._values = values;
|
|
6993
|
+
function subscribeOnce(key, callback) {
|
|
6994
|
+
return create(key).subscribeOnce(callback) ?? noop;
|
|
6924
6995
|
}
|
|
6925
|
-
|
|
6926
|
-
return
|
|
6927
|
-
return result + escapeMarkdown(nn(this._values[i - 1])) + str;
|
|
6928
|
-
});
|
|
6996
|
+
function has(key) {
|
|
6997
|
+
return cache.has(key);
|
|
6929
6998
|
}
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
return new MarkdownSafeString(strings, values);
|
|
6933
|
-
}
|
|
6934
|
-
function toAbsoluteUrl(url) {
|
|
6935
|
-
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
6936
|
-
return url;
|
|
6937
|
-
} else if (url.startsWith("www.")) {
|
|
6938
|
-
return "https://" + url;
|
|
6999
|
+
function clear() {
|
|
7000
|
+
cache.clear();
|
|
6939
7001
|
}
|
|
6940
|
-
return
|
|
7002
|
+
return {
|
|
7003
|
+
create,
|
|
7004
|
+
get,
|
|
7005
|
+
getState,
|
|
7006
|
+
revalidate,
|
|
7007
|
+
subscribe,
|
|
7008
|
+
subscribeOnce,
|
|
7009
|
+
has,
|
|
7010
|
+
clear
|
|
7011
|
+
};
|
|
6941
7012
|
}
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
let children = element.text;
|
|
6956
|
-
if (!children) {
|
|
6957
|
-
return children;
|
|
6958
|
-
}
|
|
6959
|
-
if (element.bold) {
|
|
6960
|
-
children = html`<strong>${children}</strong>`;
|
|
6961
|
-
}
|
|
6962
|
-
if (element.italic) {
|
|
6963
|
-
children = html`<em>${children}</em>`;
|
|
6964
|
-
}
|
|
6965
|
-
if (element.strikethrough) {
|
|
6966
|
-
children = html`<s>${children}</s>`;
|
|
7013
|
+
|
|
7014
|
+
// src/lib/Poller.ts
|
|
7015
|
+
function makePoller(callback) {
|
|
7016
|
+
let context = {
|
|
7017
|
+
state: "stopped",
|
|
7018
|
+
timeoutHandle: null,
|
|
7019
|
+
interval: null,
|
|
7020
|
+
lastScheduledAt: null,
|
|
7021
|
+
remainingInterval: null
|
|
7022
|
+
};
|
|
7023
|
+
function poll() {
|
|
7024
|
+
if (context.state === "running") {
|
|
7025
|
+
schedule(context.interval);
|
|
6967
7026
|
}
|
|
6968
|
-
|
|
6969
|
-
|
|
7027
|
+
void callback();
|
|
7028
|
+
}
|
|
7029
|
+
function schedule(interval) {
|
|
7030
|
+
context = {
|
|
7031
|
+
state: "running",
|
|
7032
|
+
interval: context.state !== "stopped" ? context.interval : interval,
|
|
7033
|
+
lastScheduledAt: performance.now(),
|
|
7034
|
+
timeoutHandle: setTimeout(poll, interval),
|
|
7035
|
+
remainingInterval: null
|
|
7036
|
+
};
|
|
7037
|
+
}
|
|
7038
|
+
function scheduleRemaining(remaining) {
|
|
7039
|
+
if (context.state !== "paused") {
|
|
7040
|
+
return;
|
|
6970
7041
|
}
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
7042
|
+
context = {
|
|
7043
|
+
state: "running",
|
|
7044
|
+
interval: context.interval,
|
|
7045
|
+
lastScheduledAt: context.lastScheduledAt,
|
|
7046
|
+
timeoutHandle: setTimeout(poll, remaining),
|
|
7047
|
+
remainingInterval: null
|
|
7048
|
+
};
|
|
6978
7049
|
}
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
return children;
|
|
6983
|
-
},
|
|
6984
|
-
text: ({ element }) => {
|
|
6985
|
-
let children = element.text;
|
|
6986
|
-
if (!children) {
|
|
6987
|
-
return children;
|
|
7050
|
+
function start(interval) {
|
|
7051
|
+
if (context.state === "running") {
|
|
7052
|
+
return;
|
|
6988
7053
|
}
|
|
6989
|
-
|
|
6990
|
-
|
|
7054
|
+
schedule(interval);
|
|
7055
|
+
}
|
|
7056
|
+
function restart(interval) {
|
|
7057
|
+
stop();
|
|
7058
|
+
start(interval);
|
|
7059
|
+
}
|
|
7060
|
+
function pause() {
|
|
7061
|
+
if (context.state !== "running") {
|
|
7062
|
+
return;
|
|
6991
7063
|
}
|
|
6992
|
-
|
|
6993
|
-
|
|
7064
|
+
clearTimeout(context.timeoutHandle);
|
|
7065
|
+
context = {
|
|
7066
|
+
state: "paused",
|
|
7067
|
+
interval: context.interval,
|
|
7068
|
+
lastScheduledAt: context.lastScheduledAt,
|
|
7069
|
+
timeoutHandle: null,
|
|
7070
|
+
remainingInterval: context.interval - (performance.now() - context.lastScheduledAt)
|
|
7071
|
+
};
|
|
7072
|
+
}
|
|
7073
|
+
function resume() {
|
|
7074
|
+
if (context.state !== "paused") {
|
|
7075
|
+
return;
|
|
6994
7076
|
}
|
|
6995
|
-
|
|
6996
|
-
|
|
7077
|
+
scheduleRemaining(context.remainingInterval);
|
|
7078
|
+
}
|
|
7079
|
+
function stop() {
|
|
7080
|
+
if (context.state === "stopped") {
|
|
7081
|
+
return;
|
|
6997
7082
|
}
|
|
6998
|
-
if (
|
|
6999
|
-
|
|
7083
|
+
if (context.timeoutHandle) {
|
|
7084
|
+
clearTimeout(context.timeoutHandle);
|
|
7000
7085
|
}
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7086
|
+
context = {
|
|
7087
|
+
state: "stopped",
|
|
7088
|
+
interval: null,
|
|
7089
|
+
lastScheduledAt: null,
|
|
7090
|
+
timeoutHandle: null,
|
|
7091
|
+
remainingInterval: null
|
|
7092
|
+
};
|
|
7008
7093
|
}
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
...options?.elements
|
|
7094
|
+
return {
|
|
7095
|
+
start,
|
|
7096
|
+
restart,
|
|
7097
|
+
pause,
|
|
7098
|
+
resume,
|
|
7099
|
+
stop
|
|
7016
7100
|
};
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7101
|
+
}
|
|
7102
|
+
|
|
7103
|
+
// src/lib/stringify.ts
|
|
7104
|
+
function stringify(object, ...args) {
|
|
7105
|
+
if (typeof object !== "object" || object === null || Array.isArray(object)) {
|
|
7106
|
+
return JSON.stringify(object, ...args);
|
|
7107
|
+
}
|
|
7108
|
+
const sortedObject = Object.keys(object).sort().reduce(
|
|
7109
|
+
(sortedObject2, key) => {
|
|
7110
|
+
sortedObject2[key] = object[key];
|
|
7111
|
+
return sortedObject2;
|
|
7112
|
+
},
|
|
7113
|
+
{}
|
|
7020
7114
|
);
|
|
7021
|
-
|
|
7022
|
-
switch (block.type) {
|
|
7023
|
-
case "paragraph": {
|
|
7024
|
-
const inlines = block.children.flatMap((inline, inlineIndex) => {
|
|
7025
|
-
if (isCommentBodyMention(inline)) {
|
|
7026
|
-
return inline.id ? [
|
|
7027
|
-
elements.mention(
|
|
7028
|
-
{
|
|
7029
|
-
element: inline,
|
|
7030
|
-
user: resolvedUsers.get(inline.id)
|
|
7031
|
-
},
|
|
7032
|
-
inlineIndex
|
|
7033
|
-
)
|
|
7034
|
-
] : [];
|
|
7035
|
-
}
|
|
7036
|
-
if (isCommentBodyLink(inline)) {
|
|
7037
|
-
return [
|
|
7038
|
-
elements.link(
|
|
7039
|
-
{
|
|
7040
|
-
element: inline,
|
|
7041
|
-
href: toAbsoluteUrl(inline.url) ?? inline.url
|
|
7042
|
-
},
|
|
7043
|
-
inlineIndex
|
|
7044
|
-
)
|
|
7045
|
-
];
|
|
7046
|
-
}
|
|
7047
|
-
if (isCommentBodyText(inline)) {
|
|
7048
|
-
return [elements.text({ element: inline }, inlineIndex)];
|
|
7049
|
-
}
|
|
7050
|
-
return [];
|
|
7051
|
-
});
|
|
7052
|
-
return [
|
|
7053
|
-
elements.paragraph(
|
|
7054
|
-
{ element: block, children: inlines.join("") },
|
|
7055
|
-
blockIndex
|
|
7056
|
-
)
|
|
7057
|
-
];
|
|
7058
|
-
}
|
|
7059
|
-
default:
|
|
7060
|
-
return [];
|
|
7061
|
-
}
|
|
7062
|
-
});
|
|
7063
|
-
return blocks.join(separator);
|
|
7115
|
+
return JSON.stringify(sortedObject, ...args);
|
|
7064
7116
|
}
|
|
7065
7117
|
|
|
7066
7118
|
// src/index.ts
|
|
@@ -7081,6 +7133,9 @@ export {
|
|
|
7081
7133
|
b64decode,
|
|
7082
7134
|
cloneLson,
|
|
7083
7135
|
fancy_console_exports as console,
|
|
7136
|
+
convertToCommentData,
|
|
7137
|
+
convertToCommentUserReaction,
|
|
7138
|
+
convertToThreadData,
|
|
7084
7139
|
createAsyncCache,
|
|
7085
7140
|
createClient,
|
|
7086
7141
|
createCommentsApi,
|