@liveblocks/core 1.9.7 → 1.10.0-beta1
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 +964 -782
- package/dist/index.d.ts +964 -782
- package/dist/index.js +1944 -1295
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1898 -1249
- 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.10.0-beta1";
|
|
10
10
|
var PKG_FORMAT = "esm";
|
|
11
11
|
|
|
12
12
|
// src/dupe-detection.ts
|
|
@@ -1325,7 +1325,7 @@ function createAuthManager(authOptions) {
|
|
|
1325
1325
|
}
|
|
1326
1326
|
return false;
|
|
1327
1327
|
}
|
|
1328
|
-
function getCachedToken(
|
|
1328
|
+
function getCachedToken(roomOptions) {
|
|
1329
1329
|
const now = Math.ceil(Date.now() / 1e3);
|
|
1330
1330
|
for (let i = tokens.length - 1; i >= 0; i--) {
|
|
1331
1331
|
const token = tokens[i];
|
|
@@ -1338,8 +1338,11 @@ function createAuthManager(authOptions) {
|
|
|
1338
1338
|
if (token.parsed.k === "id" /* ID_TOKEN */) {
|
|
1339
1339
|
return token;
|
|
1340
1340
|
} else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
|
|
1341
|
+
if (!roomOptions) {
|
|
1342
|
+
return token;
|
|
1343
|
+
}
|
|
1341
1344
|
for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
|
|
1342
|
-
if (resource.includes("*") && roomId.startsWith(resource.replace("*", "")) || roomId === resource && hasCorrespondingScopes(requestedScope, scopes)) {
|
|
1345
|
+
if (resource.includes("*") && roomOptions.roomId.startsWith(resource.replace("*", "")) || roomOptions.roomId === resource && hasCorrespondingScopes(roomOptions.requestedScope, scopes)) {
|
|
1343
1346
|
return token;
|
|
1344
1347
|
}
|
|
1345
1348
|
}
|
|
@@ -1388,18 +1391,27 @@ function createAuthManager(authOptions) {
|
|
|
1388
1391
|
"Unexpected authentication type. Must be private or custom."
|
|
1389
1392
|
);
|
|
1390
1393
|
}
|
|
1391
|
-
async function getAuthValue(
|
|
1394
|
+
async function getAuthValue(roomOptions) {
|
|
1392
1395
|
if (authentication.type === "public") {
|
|
1393
1396
|
return { type: "public", publicApiKey: authentication.publicApiKey };
|
|
1394
1397
|
}
|
|
1395
|
-
const cachedToken = getCachedToken(
|
|
1398
|
+
const cachedToken = getCachedToken(roomOptions);
|
|
1396
1399
|
if (cachedToken !== void 0) {
|
|
1397
1400
|
return { type: "secret", token: cachedToken };
|
|
1398
1401
|
}
|
|
1399
|
-
let currentPromise
|
|
1400
|
-
if (
|
|
1401
|
-
currentPromise =
|
|
1402
|
-
|
|
1402
|
+
let currentPromise;
|
|
1403
|
+
if (roomOptions) {
|
|
1404
|
+
currentPromise = requestPromises.get(roomOptions.roomId);
|
|
1405
|
+
if (currentPromise === void 0) {
|
|
1406
|
+
currentPromise = makeAuthRequest(roomOptions.roomId);
|
|
1407
|
+
requestPromises.set(roomOptions.roomId, currentPromise);
|
|
1408
|
+
}
|
|
1409
|
+
} else {
|
|
1410
|
+
currentPromise = requestPromises.get("liveblocks-user-token");
|
|
1411
|
+
if (currentPromise === void 0) {
|
|
1412
|
+
currentPromise = makeAuthRequest();
|
|
1413
|
+
requestPromises.set("liveblocks-user-token", currentPromise);
|
|
1414
|
+
}
|
|
1403
1415
|
}
|
|
1404
1416
|
try {
|
|
1405
1417
|
const token = await currentPromise;
|
|
@@ -1412,7 +1424,11 @@ function createAuthManager(authOptions) {
|
|
|
1412
1424
|
}
|
|
1413
1425
|
return { type: "secret", token };
|
|
1414
1426
|
} finally {
|
|
1415
|
-
|
|
1427
|
+
if (roomOptions) {
|
|
1428
|
+
requestPromises.delete(roomOptions.roomId);
|
|
1429
|
+
} else {
|
|
1430
|
+
requestPromises.delete("liveblocks-user-token");
|
|
1431
|
+
}
|
|
1416
1432
|
}
|
|
1417
1433
|
}
|
|
1418
1434
|
return {
|
|
@@ -1501,6 +1517,9 @@ async function fetchAuthEndpoint(fetch2, endpoint, body) {
|
|
|
1501
1517
|
// src/constants.ts
|
|
1502
1518
|
var DEFAULT_BASE_URL = "https://api.liveblocks.io";
|
|
1503
1519
|
|
|
1520
|
+
// src/internal.ts
|
|
1521
|
+
var kInternal = Symbol();
|
|
1522
|
+
|
|
1504
1523
|
// src/devtools/bridge.ts
|
|
1505
1524
|
var _bridgeActive = false;
|
|
1506
1525
|
function activateBridge(allowed) {
|
|
@@ -1630,7 +1649,7 @@ function partialSyncStorage(room) {
|
|
|
1630
1649
|
}
|
|
1631
1650
|
}
|
|
1632
1651
|
function partialSyncMe(room) {
|
|
1633
|
-
const me = room.
|
|
1652
|
+
const me = room[kInternal].getSelf_forDevTools();
|
|
1634
1653
|
if (me) {
|
|
1635
1654
|
sendToPanel({
|
|
1636
1655
|
msg: "room::sync::partial",
|
|
@@ -1640,7 +1659,7 @@ function partialSyncMe(room) {
|
|
|
1640
1659
|
}
|
|
1641
1660
|
}
|
|
1642
1661
|
function partialSyncOthers(room) {
|
|
1643
|
-
const others = room.
|
|
1662
|
+
const others = room[kInternal].getOthers_forDevTools();
|
|
1644
1663
|
if (others) {
|
|
1645
1664
|
sendToPanel({
|
|
1646
1665
|
msg: "room::sync::partial",
|
|
@@ -1651,8 +1670,8 @@ function partialSyncOthers(room) {
|
|
|
1651
1670
|
}
|
|
1652
1671
|
function fullSync(room) {
|
|
1653
1672
|
const root = room.getStorageSnapshot();
|
|
1654
|
-
const me = room.
|
|
1655
|
-
const others = room.
|
|
1673
|
+
const me = room[kInternal].getSelf_forDevTools();
|
|
1674
|
+
const others = room[kInternal].getOthers_forDevTools();
|
|
1656
1675
|
room.fetchYDoc("");
|
|
1657
1676
|
sendToPanel({
|
|
1658
1677
|
msg: "room::sync::full",
|
|
@@ -1711,6 +1730,185 @@ function unlinkDevTools(roomId) {
|
|
|
1711
1730
|
});
|
|
1712
1731
|
}
|
|
1713
1732
|
|
|
1733
|
+
// src/lib/stringify.ts
|
|
1734
|
+
function stringify(object, ...args) {
|
|
1735
|
+
if (typeof object !== "object" || object === null || Array.isArray(object)) {
|
|
1736
|
+
return JSON.stringify(object, ...args);
|
|
1737
|
+
}
|
|
1738
|
+
const sortedObject = Object.keys(object).sort().reduce(
|
|
1739
|
+
(sortedObject2, key) => {
|
|
1740
|
+
sortedObject2[key] = object[key];
|
|
1741
|
+
return sortedObject2;
|
|
1742
|
+
},
|
|
1743
|
+
{}
|
|
1744
|
+
);
|
|
1745
|
+
return JSON.stringify(sortedObject, ...args);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// src/lib/batch.ts
|
|
1749
|
+
var DEFAULT_SIZE = 50;
|
|
1750
|
+
var DEFAULT_DELAY = 100;
|
|
1751
|
+
var noop = () => {
|
|
1752
|
+
};
|
|
1753
|
+
var BatchCall = class {
|
|
1754
|
+
constructor(args) {
|
|
1755
|
+
this.resolve = noop;
|
|
1756
|
+
this.reject = noop;
|
|
1757
|
+
this.promise = new Promise(noop);
|
|
1758
|
+
this.args = args;
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
var Batch = class {
|
|
1762
|
+
constructor(callback, options) {
|
|
1763
|
+
this.queue = [];
|
|
1764
|
+
this.error = false;
|
|
1765
|
+
this.callback = callback;
|
|
1766
|
+
this.size = options?.size ?? DEFAULT_SIZE;
|
|
1767
|
+
this.delay = options?.delay ?? DEFAULT_DELAY;
|
|
1768
|
+
}
|
|
1769
|
+
clearDelayTimeout() {
|
|
1770
|
+
if (this.delayTimeoutId !== void 0) {
|
|
1771
|
+
clearTimeout(this.delayTimeoutId);
|
|
1772
|
+
this.delayTimeoutId = void 0;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
schedule() {
|
|
1776
|
+
if (this.queue.length === this.size) {
|
|
1777
|
+
void this.flush();
|
|
1778
|
+
} else if (this.queue.length === 1) {
|
|
1779
|
+
this.clearDelayTimeout();
|
|
1780
|
+
this.delayTimeoutId = setTimeout(() => void this.flush(), this.delay);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
async flush() {
|
|
1784
|
+
if (this.queue.length === 0) {
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
const calls = this.queue.splice(0);
|
|
1788
|
+
const args = calls.map((call) => call.args);
|
|
1789
|
+
try {
|
|
1790
|
+
const results = await this.callback(args);
|
|
1791
|
+
this.error = false;
|
|
1792
|
+
calls.forEach((call, index) => {
|
|
1793
|
+
const result = results?.[index];
|
|
1794
|
+
if (result instanceof Error) {
|
|
1795
|
+
call.reject(result);
|
|
1796
|
+
} else if (result !== void 0) {
|
|
1797
|
+
call.resolve(result);
|
|
1798
|
+
} else {
|
|
1799
|
+
if (Array.isArray(results)) {
|
|
1800
|
+
call.reject(
|
|
1801
|
+
new Error(
|
|
1802
|
+
`Batch callback must return an array of the same length as the number of calls in the batch. Expected ${calls.length}, but got ${results.length}.`
|
|
1803
|
+
)
|
|
1804
|
+
);
|
|
1805
|
+
} else {
|
|
1806
|
+
call.reject(new Error("Batch callback must return an array."));
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
});
|
|
1810
|
+
} catch (error3) {
|
|
1811
|
+
this.error = true;
|
|
1812
|
+
calls.forEach((call) => {
|
|
1813
|
+
call.reject(error3);
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
get(...args) {
|
|
1818
|
+
const existingCall = this.queue.find(
|
|
1819
|
+
(call2) => stringify(call2.args) === stringify(args)
|
|
1820
|
+
);
|
|
1821
|
+
if (existingCall) {
|
|
1822
|
+
return existingCall.promise;
|
|
1823
|
+
}
|
|
1824
|
+
const call = new BatchCall(args);
|
|
1825
|
+
call.promise = new Promise((resolve, reject) => {
|
|
1826
|
+
call.resolve = resolve;
|
|
1827
|
+
call.reject = reject;
|
|
1828
|
+
});
|
|
1829
|
+
this.queue.push(call);
|
|
1830
|
+
this.schedule();
|
|
1831
|
+
return call.promise;
|
|
1832
|
+
}
|
|
1833
|
+
clear() {
|
|
1834
|
+
this.queue = [];
|
|
1835
|
+
this.error = false;
|
|
1836
|
+
this.clearDelayTimeout();
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
function createBatchStore(callback, options) {
|
|
1840
|
+
const batch = new Batch(callback, options);
|
|
1841
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1842
|
+
const eventSource2 = makeEventSource();
|
|
1843
|
+
function getCacheKey(args) {
|
|
1844
|
+
return stringify(args);
|
|
1845
|
+
}
|
|
1846
|
+
function setStateAndNotify(cacheKey, state) {
|
|
1847
|
+
if (state) {
|
|
1848
|
+
cache.set(cacheKey, state);
|
|
1849
|
+
} else {
|
|
1850
|
+
cache.delete(cacheKey);
|
|
1851
|
+
}
|
|
1852
|
+
eventSource2.notify(state);
|
|
1853
|
+
}
|
|
1854
|
+
async function get(...args) {
|
|
1855
|
+
const cacheKey = getCacheKey(args);
|
|
1856
|
+
if (cache.has(cacheKey)) {
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
try {
|
|
1860
|
+
setStateAndNotify(cacheKey, { isLoading: true });
|
|
1861
|
+
const result = await batch.get(...args);
|
|
1862
|
+
setStateAndNotify(cacheKey, { isLoading: false, data: result });
|
|
1863
|
+
} catch (error3) {
|
|
1864
|
+
setStateAndNotify(cacheKey, {
|
|
1865
|
+
isLoading: false,
|
|
1866
|
+
error: error3
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
function getState(...args) {
|
|
1871
|
+
const cacheKey = getCacheKey(args);
|
|
1872
|
+
return cache.get(cacheKey);
|
|
1873
|
+
}
|
|
1874
|
+
return {
|
|
1875
|
+
...eventSource2,
|
|
1876
|
+
get,
|
|
1877
|
+
getState
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// src/lib/create-store.ts
|
|
1882
|
+
function createStore(initialState) {
|
|
1883
|
+
let state = initialState;
|
|
1884
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
1885
|
+
function get() {
|
|
1886
|
+
return state;
|
|
1887
|
+
}
|
|
1888
|
+
function set(callback) {
|
|
1889
|
+
const newState = callback(state);
|
|
1890
|
+
if (state === newState) {
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
state = newState;
|
|
1894
|
+
for (const subscriber of subscribers) {
|
|
1895
|
+
subscriber(state);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
function subscribe(callback) {
|
|
1899
|
+
subscribers.add(callback);
|
|
1900
|
+
callback(state);
|
|
1901
|
+
return () => {
|
|
1902
|
+
subscribers.delete(callback);
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
return {
|
|
1906
|
+
get,
|
|
1907
|
+
set,
|
|
1908
|
+
subscribe
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1714
1912
|
// src/lib/deprecation.ts
|
|
1715
1913
|
var _emittedDeprecationWarnings = /* @__PURE__ */ new Set();
|
|
1716
1914
|
function deprecate(message, key = message) {
|
|
@@ -1744,1016 +1942,612 @@ function errorIf(condition, message) {
|
|
|
1744
1942
|
}
|
|
1745
1943
|
}
|
|
1746
1944
|
|
|
1747
|
-
// src/
|
|
1748
|
-
function
|
|
1749
|
-
|
|
1945
|
+
// src/convert-plain-data.ts
|
|
1946
|
+
function convertToCommentData(data) {
|
|
1947
|
+
const editedAt = data.editedAt ? new Date(data.editedAt) : void 0;
|
|
1948
|
+
const createdAt = new Date(data.createdAt);
|
|
1949
|
+
const reactions = data.reactions.map((reaction) => ({
|
|
1950
|
+
...reaction,
|
|
1951
|
+
createdAt: new Date(reaction.createdAt)
|
|
1952
|
+
}));
|
|
1953
|
+
if (data.body) {
|
|
1954
|
+
return {
|
|
1955
|
+
...data,
|
|
1956
|
+
reactions,
|
|
1957
|
+
createdAt,
|
|
1958
|
+
editedAt
|
|
1959
|
+
};
|
|
1960
|
+
} else {
|
|
1961
|
+
const deletedAt = new Date(data.deletedAt);
|
|
1962
|
+
return {
|
|
1963
|
+
...data,
|
|
1964
|
+
reactions,
|
|
1965
|
+
createdAt,
|
|
1966
|
+
editedAt,
|
|
1967
|
+
deletedAt
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
1750
1970
|
}
|
|
1751
|
-
function
|
|
1752
|
-
|
|
1971
|
+
function convertToThreadData(data) {
|
|
1972
|
+
const updatedAt = data.updatedAt ? new Date(data.updatedAt) : void 0;
|
|
1973
|
+
const createdAt = new Date(data.createdAt);
|
|
1974
|
+
const comments = data.comments.map(
|
|
1975
|
+
(comment) => convertToCommentData(comment)
|
|
1976
|
+
);
|
|
1977
|
+
return {
|
|
1978
|
+
...data,
|
|
1979
|
+
createdAt,
|
|
1980
|
+
updatedAt,
|
|
1981
|
+
comments
|
|
1982
|
+
};
|
|
1753
1983
|
}
|
|
1754
|
-
function
|
|
1755
|
-
return
|
|
1984
|
+
function convertToCommentUserReaction(data) {
|
|
1985
|
+
return {
|
|
1986
|
+
...data,
|
|
1987
|
+
createdAt: new Date(data.createdAt)
|
|
1988
|
+
};
|
|
1756
1989
|
}
|
|
1757
|
-
function
|
|
1758
|
-
|
|
1990
|
+
function convertToInboxNotificationData(data) {
|
|
1991
|
+
const notifiedAt = new Date(data.notifiedAt);
|
|
1992
|
+
const readAt = data.readAt ? new Date(data.readAt) : null;
|
|
1993
|
+
return {
|
|
1994
|
+
...data,
|
|
1995
|
+
notifiedAt,
|
|
1996
|
+
readAt
|
|
1997
|
+
};
|
|
1759
1998
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
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);
|
|
1784
|
-
}
|
|
1999
|
+
|
|
2000
|
+
// src/notifications.ts
|
|
2001
|
+
var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY = 50;
|
|
2002
|
+
function createInboxNotificationsApi({
|
|
2003
|
+
baseUrl,
|
|
2004
|
+
authManager,
|
|
2005
|
+
currentUserIdStore,
|
|
2006
|
+
fetcher
|
|
2007
|
+
}) {
|
|
2008
|
+
async function fetchJson(endpoint, options) {
|
|
2009
|
+
const authValue = await authManager.getAuthValue();
|
|
2010
|
+
if (authValue.type === "secret" && authValue.token.parsed.k === "acc" /* ACCESS_TOKEN */) {
|
|
2011
|
+
const userId = authValue.token.parsed.uid;
|
|
2012
|
+
currentUserIdStore.set(() => userId);
|
|
1785
2013
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
2014
|
+
const url = new URL(`/v2/c${endpoint}`, baseUrl);
|
|
2015
|
+
const response = await fetcher(url.toString(), {
|
|
2016
|
+
...options,
|
|
2017
|
+
headers: {
|
|
2018
|
+
...options?.headers,
|
|
2019
|
+
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
2020
|
+
}
|
|
2021
|
+
});
|
|
2022
|
+
if (!response.ok) {
|
|
2023
|
+
if (response.status >= 400 && response.status < 600) {
|
|
2024
|
+
let error3;
|
|
2025
|
+
try {
|
|
2026
|
+
const errorBody = await response.json();
|
|
2027
|
+
error3 = new NotificationsApiError(
|
|
2028
|
+
errorBody.message,
|
|
2029
|
+
response.status,
|
|
2030
|
+
errorBody
|
|
2031
|
+
);
|
|
2032
|
+
} catch {
|
|
2033
|
+
error3 = new NotificationsApiError(
|
|
2034
|
+
response.statusText,
|
|
2035
|
+
response.status
|
|
2036
|
+
);
|
|
1790
2037
|
}
|
|
2038
|
+
throw error3;
|
|
1791
2039
|
}
|
|
1792
2040
|
}
|
|
2041
|
+
let body;
|
|
2042
|
+
try {
|
|
2043
|
+
body = await response.json();
|
|
2044
|
+
} catch {
|
|
2045
|
+
body = {};
|
|
2046
|
+
}
|
|
2047
|
+
return body;
|
|
1793
2048
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
}
|
|
1804
|
-
async function resolveUsersInCommentBody(body, resolveUsers) {
|
|
1805
|
-
const resolvedUsers = /* @__PURE__ */ new Map();
|
|
1806
|
-
if (!resolveUsers) {
|
|
1807
|
-
return resolvedUsers;
|
|
2049
|
+
async function getInboxNotifications(options) {
|
|
2050
|
+
const queryParams = toURLSearchParams({ limit: options?.limit });
|
|
2051
|
+
const json = await fetchJson(`/inbox-notifications?${queryParams.toString()}`);
|
|
2052
|
+
return {
|
|
2053
|
+
threads: json.threads.map((thread) => convertToThreadData(thread)),
|
|
2054
|
+
inboxNotifications: json.inboxNotifications.map(
|
|
2055
|
+
(notification) => convertToInboxNotificationData(notification)
|
|
2056
|
+
)
|
|
2057
|
+
};
|
|
1808
2058
|
}
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
});
|
|
1813
|
-
for (const [index, userId] of userIds.entries()) {
|
|
1814
|
-
const user = users?.[index];
|
|
1815
|
-
if (user) {
|
|
1816
|
-
resolvedUsers.set(userId, user);
|
|
1817
|
-
}
|
|
2059
|
+
async function getUnreadInboxNotificationsCount() {
|
|
2060
|
+
const { count } = await fetchJson("/inbox-notifications/count");
|
|
2061
|
+
return count;
|
|
1818
2062
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
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([""], []);
|
|
2063
|
+
async function markAllInboxNotificationsAsRead() {
|
|
2064
|
+
await fetchJson("/inbox-notifications/read", {
|
|
2065
|
+
method: "POST",
|
|
2066
|
+
headers: {
|
|
2067
|
+
"Content-Type": "application/json"
|
|
2068
|
+
},
|
|
2069
|
+
body: JSON.stringify({ inboxNotificationIds: "all" })
|
|
2070
|
+
});
|
|
1838
2071
|
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2072
|
+
async function markInboxNotificationsAsRead(inboxNotificationIds) {
|
|
2073
|
+
await fetchJson("/inbox-notifications/read", {
|
|
2074
|
+
method: "POST",
|
|
2075
|
+
headers: {
|
|
2076
|
+
"Content-Type": "application/json"
|
|
2077
|
+
},
|
|
2078
|
+
body: JSON.stringify({ inboxNotificationIds })
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
const batchedMarkInboxNotificationsAsRead = new Batch(
|
|
2082
|
+
async (batchedInboxNotificationIds) => {
|
|
2083
|
+
const inboxNotificationIds = batchedInboxNotificationIds.flat();
|
|
2084
|
+
await markInboxNotificationsAsRead(inboxNotificationIds);
|
|
2085
|
+
return inboxNotificationIds;
|
|
2086
|
+
},
|
|
2087
|
+
{ delay: MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY }
|
|
1842
2088
|
);
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
if (value instanceof HtmlSafeString) {
|
|
1846
|
-
return value.toString();
|
|
2089
|
+
async function markInboxNotificationAsRead(inboxNotificationId) {
|
|
2090
|
+
await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
|
|
1847
2091
|
}
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
);
|
|
2092
|
+
return {
|
|
2093
|
+
getInboxNotifications,
|
|
2094
|
+
getUnreadInboxNotificationsCount,
|
|
2095
|
+
markAllInboxNotificationsAsRead,
|
|
2096
|
+
markInboxNotificationAsRead
|
|
2097
|
+
};
|
|
1855
2098
|
}
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
return this._strings.reduce((result, str, i) => {
|
|
1863
|
-
return result + escapeHtml(nn(this._values[i - 1])) + str;
|
|
1864
|
-
});
|
|
2099
|
+
function toURLSearchParams(params) {
|
|
2100
|
+
const result = new URLSearchParams();
|
|
2101
|
+
for (const [key, value] of Object.entries(params)) {
|
|
2102
|
+
if (value !== void 0 && value !== null) {
|
|
2103
|
+
result.set(key, value.toString());
|
|
2104
|
+
}
|
|
1865
2105
|
}
|
|
1866
|
-
|
|
1867
|
-
function html(strings, ...values) {
|
|
1868
|
-
return new HtmlSafeString(strings, values);
|
|
2106
|
+
return result;
|
|
1869
2107
|
}
|
|
1870
|
-
|
|
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([""], []);
|
|
2108
|
+
|
|
2109
|
+
// src/lib/position.ts
|
|
2110
|
+
var MIN_CODE = 32;
|
|
2111
|
+
var MAX_CODE = 126;
|
|
2112
|
+
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
2113
|
+
var ZERO = nthDigit(0);
|
|
2114
|
+
var ONE = nthDigit(1);
|
|
2115
|
+
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
2116
|
+
function nthDigit(n) {
|
|
2117
|
+
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
2118
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2119
|
+
throw new Error(`Invalid n value: ${n}`);
|
|
1892
2120
|
}
|
|
1893
|
-
return
|
|
1894
|
-
["", ...Array(strings.length - 1).fill(""), ""],
|
|
1895
|
-
strings
|
|
1896
|
-
);
|
|
2121
|
+
return String.fromCharCode(code);
|
|
1897
2122
|
}
|
|
1898
|
-
function
|
|
1899
|
-
if (
|
|
1900
|
-
return
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
|
|
2123
|
+
function makePosition(x, y) {
|
|
2124
|
+
if (x !== void 0 && y !== void 0) {
|
|
2125
|
+
return between(x, y);
|
|
2126
|
+
} else if (x !== void 0) {
|
|
2127
|
+
return after(x);
|
|
2128
|
+
} else if (y !== void 0) {
|
|
2129
|
+
return before(y);
|
|
2130
|
+
} else {
|
|
2131
|
+
return ONE;
|
|
1904
2132
|
}
|
|
1905
|
-
return String(value).replace(
|
|
1906
|
-
markdownEscapablesRegex,
|
|
1907
|
-
(character) => markdownEscapables[character]
|
|
1908
|
-
);
|
|
1909
2133
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
2134
|
+
function before(pos) {
|
|
2135
|
+
const lastIndex = pos.length - 1;
|
|
2136
|
+
for (let i = 0; i <= lastIndex; i++) {
|
|
2137
|
+
const code = pos.charCodeAt(i);
|
|
2138
|
+
if (code <= MIN_CODE) {
|
|
2139
|
+
continue;
|
|
2140
|
+
}
|
|
2141
|
+
if (i === lastIndex) {
|
|
2142
|
+
if (code === MIN_CODE + 1) {
|
|
2143
|
+
return pos.substring(0, i) + ZERO_NINE;
|
|
2144
|
+
} else {
|
|
2145
|
+
return pos.substring(0, i) + String.fromCharCode(code - 1);
|
|
2146
|
+
}
|
|
2147
|
+
} else {
|
|
2148
|
+
return pos.substring(0, i + 1);
|
|
2149
|
+
}
|
|
1919
2150
|
}
|
|
1920
|
-
|
|
1921
|
-
function markdown(strings, ...values) {
|
|
1922
|
-
return new MarkdownSafeString(strings, values);
|
|
2151
|
+
return ONE;
|
|
1923
2152
|
}
|
|
1924
|
-
function
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2153
|
+
function after(pos) {
|
|
2154
|
+
for (let i = 0; i <= pos.length - 1; i++) {
|
|
2155
|
+
const code = pos.charCodeAt(i);
|
|
2156
|
+
if (code >= MAX_CODE) {
|
|
2157
|
+
continue;
|
|
2158
|
+
}
|
|
2159
|
+
return pos.substring(0, i) + String.fromCharCode(code + 1);
|
|
1929
2160
|
}
|
|
1930
|
-
return;
|
|
2161
|
+
return pos + ONE;
|
|
1931
2162
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2163
|
+
function between(lo, hi) {
|
|
2164
|
+
if (lo < hi) {
|
|
2165
|
+
return _between(lo, hi);
|
|
2166
|
+
} else if (lo > hi) {
|
|
2167
|
+
return _between(hi, lo);
|
|
2168
|
+
} else {
|
|
2169
|
+
throw new Error("Cannot compute value between two equal positions");
|
|
1938
2170
|
}
|
|
1939
|
-
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
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>`;
|
|
2171
|
+
}
|
|
2172
|
+
function _between(lo, hi) {
|
|
2173
|
+
let index = 0;
|
|
2174
|
+
const loLen = lo.length;
|
|
2175
|
+
const hiLen = hi.length;
|
|
2176
|
+
while (true) {
|
|
2177
|
+
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
2178
|
+
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
2179
|
+
if (loCode === hiCode) {
|
|
2180
|
+
index++;
|
|
2181
|
+
continue;
|
|
1957
2182
|
}
|
|
1958
|
-
if (
|
|
1959
|
-
|
|
2183
|
+
if (hiCode - loCode === 1) {
|
|
2184
|
+
const size = index + 1;
|
|
2185
|
+
let prefix = lo.substring(0, size);
|
|
2186
|
+
if (prefix.length < size) {
|
|
2187
|
+
prefix += ZERO.repeat(size - prefix.length);
|
|
2188
|
+
}
|
|
2189
|
+
const suffix = lo.substring(size);
|
|
2190
|
+
const nines = "";
|
|
2191
|
+
return prefix + _between(suffix, nines);
|
|
2192
|
+
} else {
|
|
2193
|
+
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
1960
2194
|
}
|
|
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>`;
|
|
1968
2195
|
}
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
if (
|
|
1986
|
-
|
|
1987
|
-
}
|
|
1988
|
-
if (element.code) {
|
|
1989
|
-
children = markdown`\`${children}\``;
|
|
2196
|
+
}
|
|
2197
|
+
function takeN(pos, n) {
|
|
2198
|
+
return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
|
|
2199
|
+
}
|
|
2200
|
+
var MIN_NON_ZERO_CODE = MIN_CODE + 1;
|
|
2201
|
+
function isPos(str) {
|
|
2202
|
+
if (str === "") {
|
|
2203
|
+
return false;
|
|
2204
|
+
}
|
|
2205
|
+
const lastIdx = str.length - 1;
|
|
2206
|
+
const last = str.charCodeAt(lastIdx);
|
|
2207
|
+
if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
|
|
2208
|
+
return false;
|
|
2209
|
+
}
|
|
2210
|
+
for (let i = 0; i < lastIdx; i++) {
|
|
2211
|
+
const code = str.charCodeAt(i);
|
|
2212
|
+
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2213
|
+
return false;
|
|
1990
2214
|
}
|
|
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}`;
|
|
1998
2215
|
}
|
|
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
|
|
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);
|
|
2216
|
+
return true;
|
|
2054
2217
|
}
|
|
2055
|
-
function
|
|
2056
|
-
const
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
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
|
-
};
|
|
2218
|
+
function convertToPos(str) {
|
|
2219
|
+
const codes = [];
|
|
2220
|
+
for (let i = 0; i < str.length; i++) {
|
|
2221
|
+
const code = str.charCodeAt(i);
|
|
2222
|
+
codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
|
|
2078
2223
|
}
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2224
|
+
while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
|
|
2225
|
+
codes.length--;
|
|
2226
|
+
}
|
|
2227
|
+
return codes.length > 0 ? String.fromCharCode(...codes) : (
|
|
2228
|
+
// Edge case: the str was a 0-only string, which is invalid. Default back to .1
|
|
2229
|
+
ONE
|
|
2085
2230
|
);
|
|
2086
|
-
return {
|
|
2087
|
-
...data,
|
|
2088
|
-
createdAt,
|
|
2089
|
-
updatedAt,
|
|
2090
|
-
comments
|
|
2091
|
-
};
|
|
2092
2231
|
}
|
|
2093
|
-
function
|
|
2232
|
+
function asPos(str) {
|
|
2233
|
+
return isPos(str) ? str : convertToPos(str);
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
// src/protocol/Op.ts
|
|
2237
|
+
var OpCode = /* @__PURE__ */ ((OpCode2) => {
|
|
2238
|
+
OpCode2[OpCode2["INIT"] = 0] = "INIT";
|
|
2239
|
+
OpCode2[OpCode2["SET_PARENT_KEY"] = 1] = "SET_PARENT_KEY";
|
|
2240
|
+
OpCode2[OpCode2["CREATE_LIST"] = 2] = "CREATE_LIST";
|
|
2241
|
+
OpCode2[OpCode2["UPDATE_OBJECT"] = 3] = "UPDATE_OBJECT";
|
|
2242
|
+
OpCode2[OpCode2["CREATE_OBJECT"] = 4] = "CREATE_OBJECT";
|
|
2243
|
+
OpCode2[OpCode2["DELETE_CRDT"] = 5] = "DELETE_CRDT";
|
|
2244
|
+
OpCode2[OpCode2["DELETE_OBJECT_KEY"] = 6] = "DELETE_OBJECT_KEY";
|
|
2245
|
+
OpCode2[OpCode2["CREATE_MAP"] = 7] = "CREATE_MAP";
|
|
2246
|
+
OpCode2[OpCode2["CREATE_REGISTER"] = 8] = "CREATE_REGISTER";
|
|
2247
|
+
return OpCode2;
|
|
2248
|
+
})(OpCode || {});
|
|
2249
|
+
function ackOp(opId) {
|
|
2094
2250
|
return {
|
|
2095
|
-
|
|
2096
|
-
|
|
2251
|
+
type: 5 /* DELETE_CRDT */,
|
|
2252
|
+
id: "ACK",
|
|
2253
|
+
// (H)ACK
|
|
2254
|
+
opId
|
|
2097
2255
|
};
|
|
2098
2256
|
}
|
|
2257
|
+
function isAckOp(op) {
|
|
2258
|
+
return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
|
|
2259
|
+
}
|
|
2099
2260
|
|
|
2100
|
-
// src/
|
|
2101
|
-
function
|
|
2102
|
-
|
|
2103
|
-
return authValue.publicApiKey;
|
|
2104
|
-
} else {
|
|
2105
|
-
return authValue.token.raw;
|
|
2106
|
-
}
|
|
2261
|
+
// src/crdts/AbstractCrdt.ts
|
|
2262
|
+
function crdtAsLiveNode(value) {
|
|
2263
|
+
return value;
|
|
2107
2264
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2265
|
+
function HasParent(node, key, pos = asPos(key)) {
|
|
2266
|
+
return Object.freeze({ type: "HasParent", node, key, pos });
|
|
2267
|
+
}
|
|
2268
|
+
var NoParent = Object.freeze({ type: "NoParent" });
|
|
2269
|
+
function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
2270
|
+
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
2271
|
+
}
|
|
2272
|
+
var AbstractCrdt = class {
|
|
2273
|
+
constructor() {
|
|
2274
|
+
/** @internal */
|
|
2275
|
+
this._parent = NoParent;
|
|
2114
2276
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
response.status,
|
|
2127
|
-
errorBody
|
|
2128
|
-
);
|
|
2129
|
-
} catch {
|
|
2130
|
-
error3 = new CommentsApiError(response.statusText, response.status);
|
|
2131
|
-
}
|
|
2132
|
-
throw error3;
|
|
2133
|
-
}
|
|
2277
|
+
/** @internal */
|
|
2278
|
+
_getParentKeyOrThrow() {
|
|
2279
|
+
switch (this.parent.type) {
|
|
2280
|
+
case "HasParent":
|
|
2281
|
+
return this.parent.key;
|
|
2282
|
+
case "NoParent":
|
|
2283
|
+
throw new Error("Parent key is missing");
|
|
2284
|
+
case "Orphaned":
|
|
2285
|
+
return this.parent.oldKey;
|
|
2286
|
+
default:
|
|
2287
|
+
return assertNever(this.parent, "Unknown state");
|
|
2134
2288
|
}
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2289
|
+
}
|
|
2290
|
+
/** @internal */
|
|
2291
|
+
get _parentPos() {
|
|
2292
|
+
switch (this.parent.type) {
|
|
2293
|
+
case "HasParent":
|
|
2294
|
+
return this.parent.pos;
|
|
2295
|
+
case "NoParent":
|
|
2296
|
+
throw new Error("Parent key is missing");
|
|
2297
|
+
case "Orphaned":
|
|
2298
|
+
return this.parent.oldPos;
|
|
2299
|
+
default:
|
|
2300
|
+
return assertNever(this.parent, "Unknown state");
|
|
2140
2301
|
}
|
|
2141
|
-
return body;
|
|
2142
2302
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
`/v2/c/rooms/${encodeURIComponent(roomId2)}${endpoint}`,
|
|
2147
|
-
config.baseUrl
|
|
2148
|
-
);
|
|
2149
|
-
return await fetch(url.toString(), {
|
|
2150
|
-
...options,
|
|
2151
|
-
headers: {
|
|
2152
|
-
...options?.headers,
|
|
2153
|
-
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
2154
|
-
}
|
|
2155
|
-
});
|
|
2303
|
+
/** @internal */
|
|
2304
|
+
get _pool() {
|
|
2305
|
+
return this.__pool;
|
|
2156
2306
|
}
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
body: JSON.stringify({
|
|
2160
|
-
...options?.query?.metadata && { metadata: options.query.metadata }
|
|
2161
|
-
}),
|
|
2162
|
-
headers: {
|
|
2163
|
-
"Content-Type": "application/json"
|
|
2164
|
-
},
|
|
2165
|
-
method: "POST"
|
|
2166
|
-
});
|
|
2167
|
-
if (response.ok) {
|
|
2168
|
-
const json = await response.json();
|
|
2169
|
-
return json.data.map((thread) => convertToThreadData(thread));
|
|
2170
|
-
} else if (response.status === 404) {
|
|
2171
|
-
return [];
|
|
2172
|
-
} else {
|
|
2173
|
-
throw new Error("There was an error while getting threads.");
|
|
2174
|
-
}
|
|
2307
|
+
get roomId() {
|
|
2308
|
+
return this.__pool ? this.__pool.roomId : null;
|
|
2175
2309
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
commentId,
|
|
2180
|
-
threadId
|
|
2181
|
-
}) {
|
|
2182
|
-
const thread = await fetchJson(
|
|
2183
|
-
"/threads",
|
|
2184
|
-
{
|
|
2185
|
-
method: "POST",
|
|
2186
|
-
headers: {
|
|
2187
|
-
"Content-Type": "application/json"
|
|
2188
|
-
},
|
|
2189
|
-
body: JSON.stringify({
|
|
2190
|
-
id: threadId,
|
|
2191
|
-
comment: {
|
|
2192
|
-
id: commentId,
|
|
2193
|
-
body
|
|
2194
|
-
},
|
|
2195
|
-
metadata
|
|
2196
|
-
})
|
|
2197
|
-
}
|
|
2198
|
-
);
|
|
2199
|
-
return convertToThreadData(thread);
|
|
2310
|
+
/** @internal */
|
|
2311
|
+
get _id() {
|
|
2312
|
+
return this.__id;
|
|
2200
2313
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
}) {
|
|
2205
|
-
return await fetchJson(
|
|
2206
|
-
`/threads/${encodeURIComponent(threadId)}/metadata`,
|
|
2207
|
-
{
|
|
2208
|
-
method: "POST",
|
|
2209
|
-
headers: {
|
|
2210
|
-
"Content-Type": "application/json"
|
|
2211
|
-
},
|
|
2212
|
-
body: JSON.stringify(metadata)
|
|
2213
|
-
}
|
|
2214
|
-
);
|
|
2314
|
+
/** @internal */
|
|
2315
|
+
get parent() {
|
|
2316
|
+
return this._parent;
|
|
2215
2317
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
body: JSON.stringify({
|
|
2229
|
-
id: commentId,
|
|
2230
|
-
body
|
|
2231
|
-
})
|
|
2232
|
-
}
|
|
2233
|
-
);
|
|
2234
|
-
return convertToCommentData(comment);
|
|
2318
|
+
/** @internal */
|
|
2319
|
+
get _parentKey() {
|
|
2320
|
+
switch (this.parent.type) {
|
|
2321
|
+
case "HasParent":
|
|
2322
|
+
return this.parent.key;
|
|
2323
|
+
case "NoParent":
|
|
2324
|
+
return null;
|
|
2325
|
+
case "Orphaned":
|
|
2326
|
+
return this.parent.oldKey;
|
|
2327
|
+
default:
|
|
2328
|
+
return assertNever(this.parent, "Unknown state");
|
|
2329
|
+
}
|
|
2235
2330
|
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
)}`,
|
|
2245
|
-
{
|
|
2246
|
-
method: "POST",
|
|
2247
|
-
headers: {
|
|
2248
|
-
"Content-Type": "application/json"
|
|
2249
|
-
},
|
|
2250
|
-
body: JSON.stringify({
|
|
2251
|
-
body
|
|
2252
|
-
})
|
|
2331
|
+
/** @internal */
|
|
2332
|
+
_apply(op, _isLocal) {
|
|
2333
|
+
switch (op.type) {
|
|
2334
|
+
case 5 /* DELETE_CRDT */: {
|
|
2335
|
+
if (this.parent.type === "HasParent") {
|
|
2336
|
+
return this.parent.node._detachChild(crdtAsLiveNode(this));
|
|
2337
|
+
}
|
|
2338
|
+
return { modified: false };
|
|
2253
2339
|
}
|
|
2254
|
-
|
|
2255
|
-
return
|
|
2340
|
+
}
|
|
2341
|
+
return { modified: false };
|
|
2256
2342
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2343
|
+
/** @internal */
|
|
2344
|
+
_setParentLink(newParentNode, newParentKey) {
|
|
2345
|
+
switch (this.parent.type) {
|
|
2346
|
+
case "HasParent":
|
|
2347
|
+
if (this.parent.node !== newParentNode) {
|
|
2348
|
+
throw new Error("Cannot set parent: node already has a parent");
|
|
2349
|
+
} else {
|
|
2350
|
+
this._parent = HasParent(newParentNode, newParentKey);
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
case "Orphaned":
|
|
2354
|
+
case "NoParent": {
|
|
2355
|
+
this._parent = HasParent(newParentNode, newParentKey);
|
|
2356
|
+
return;
|
|
2267
2357
|
}
|
|
2268
|
-
|
|
2358
|
+
default:
|
|
2359
|
+
return assertNever(this.parent, "Unknown state");
|
|
2360
|
+
}
|
|
2269
2361
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
)}/reactions`,
|
|
2279
|
-
{
|
|
2280
|
-
method: "POST",
|
|
2281
|
-
headers: {
|
|
2282
|
-
"Content-Type": "application/json"
|
|
2283
|
-
},
|
|
2284
|
-
body: JSON.stringify({ emoji })
|
|
2285
|
-
}
|
|
2286
|
-
);
|
|
2287
|
-
return convertToCommentUserReaction(reaction);
|
|
2362
|
+
/** @internal */
|
|
2363
|
+
_attach(id, pool) {
|
|
2364
|
+
if (this.__id || this.__pool) {
|
|
2365
|
+
throw new Error("Cannot attach node: already attached");
|
|
2366
|
+
}
|
|
2367
|
+
pool.addNode(id, crdtAsLiveNode(this));
|
|
2368
|
+
this.__id = id;
|
|
2369
|
+
this.__pool = pool;
|
|
2288
2370
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
{
|
|
2299
|
-
method: "DELETE"
|
|
2371
|
+
/** @internal */
|
|
2372
|
+
_detach() {
|
|
2373
|
+
if (this.__pool && this.__id) {
|
|
2374
|
+
this.__pool.deleteNode(this.__id);
|
|
2375
|
+
}
|
|
2376
|
+
switch (this.parent.type) {
|
|
2377
|
+
case "HasParent": {
|
|
2378
|
+
this._parent = Orphaned(this.parent.key, this.parent.pos);
|
|
2379
|
+
break;
|
|
2300
2380
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
addReaction,
|
|
2311
|
-
removeReaction
|
|
2312
|
-
};
|
|
2313
|
-
}
|
|
2314
|
-
|
|
2315
|
-
// src/lib/position.ts
|
|
2316
|
-
var MIN_CODE = 32;
|
|
2317
|
-
var MAX_CODE = 126;
|
|
2318
|
-
var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
|
|
2319
|
-
var ZERO = nthDigit(0);
|
|
2320
|
-
var ONE = nthDigit(1);
|
|
2321
|
-
var ZERO_NINE = ZERO + nthDigit(-1);
|
|
2322
|
-
function nthDigit(n) {
|
|
2323
|
-
const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
|
|
2324
|
-
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2325
|
-
throw new Error(`Invalid n value: ${n}`);
|
|
2326
|
-
}
|
|
2327
|
-
return String.fromCharCode(code);
|
|
2328
|
-
}
|
|
2329
|
-
function makePosition(x, y) {
|
|
2330
|
-
if (x !== void 0 && y !== void 0) {
|
|
2331
|
-
return between(x, y);
|
|
2332
|
-
} else if (x !== void 0) {
|
|
2333
|
-
return after(x);
|
|
2334
|
-
} else if (y !== void 0) {
|
|
2335
|
-
return before(y);
|
|
2336
|
-
} else {
|
|
2337
|
-
return ONE;
|
|
2338
|
-
}
|
|
2339
|
-
}
|
|
2340
|
-
function before(pos) {
|
|
2341
|
-
const lastIndex = pos.length - 1;
|
|
2342
|
-
for (let i = 0; i <= lastIndex; i++) {
|
|
2343
|
-
const code = pos.charCodeAt(i);
|
|
2344
|
-
if (code <= MIN_CODE) {
|
|
2345
|
-
continue;
|
|
2381
|
+
case "NoParent": {
|
|
2382
|
+
this._parent = NoParent;
|
|
2383
|
+
break;
|
|
2384
|
+
}
|
|
2385
|
+
case "Orphaned": {
|
|
2386
|
+
break;
|
|
2387
|
+
}
|
|
2388
|
+
default:
|
|
2389
|
+
assertNever(this.parent, "Unknown state");
|
|
2346
2390
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2391
|
+
this.__pool = void 0;
|
|
2392
|
+
}
|
|
2393
|
+
/**
|
|
2394
|
+
* @internal
|
|
2395
|
+
*
|
|
2396
|
+
* Clear the Immutable cache, so that the next call to `.toImmutable()` will
|
|
2397
|
+
* recompute the equivalent Immutable value again. Call this after every
|
|
2398
|
+
* mutation to the Live node.
|
|
2399
|
+
*/
|
|
2400
|
+
invalidate() {
|
|
2401
|
+
if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
|
|
2402
|
+
this._cachedImmutable = void 0;
|
|
2403
|
+
this._cachedTreeNode = void 0;
|
|
2404
|
+
if (this.parent.type === "HasParent") {
|
|
2405
|
+
this.parent.node.invalidate();
|
|
2352
2406
|
}
|
|
2353
|
-
} else {
|
|
2354
|
-
return pos.substring(0, i + 1);
|
|
2355
2407
|
}
|
|
2356
2408
|
}
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2409
|
+
/**
|
|
2410
|
+
* @internal
|
|
2411
|
+
*
|
|
2412
|
+
* Return an snapshot of this Live tree for use in DevTools.
|
|
2413
|
+
*/
|
|
2414
|
+
toTreeNode(key) {
|
|
2415
|
+
if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
|
|
2416
|
+
this._cachedTreeNodeKey = key;
|
|
2417
|
+
this._cachedTreeNode = this._toTreeNode(key);
|
|
2364
2418
|
}
|
|
2365
|
-
return
|
|
2419
|
+
return this._cachedTreeNode;
|
|
2366
2420
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
throw new Error("Cannot compute value between two equal positions");
|
|
2421
|
+
/**
|
|
2422
|
+
* Return an immutable snapshot of this Live node and its children.
|
|
2423
|
+
*/
|
|
2424
|
+
toImmutable() {
|
|
2425
|
+
if (this._cachedImmutable === void 0) {
|
|
2426
|
+
this._cachedImmutable = this._toImmutable();
|
|
2427
|
+
}
|
|
2428
|
+
return this._cachedImmutable;
|
|
2376
2429
|
}
|
|
2430
|
+
};
|
|
2431
|
+
|
|
2432
|
+
// src/protocol/SerializedCrdt.ts
|
|
2433
|
+
var CrdtType = /* @__PURE__ */ ((CrdtType2) => {
|
|
2434
|
+
CrdtType2[CrdtType2["OBJECT"] = 0] = "OBJECT";
|
|
2435
|
+
CrdtType2[CrdtType2["LIST"] = 1] = "LIST";
|
|
2436
|
+
CrdtType2[CrdtType2["MAP"] = 2] = "MAP";
|
|
2437
|
+
CrdtType2[CrdtType2["REGISTER"] = 3] = "REGISTER";
|
|
2438
|
+
return CrdtType2;
|
|
2439
|
+
})(CrdtType || {});
|
|
2440
|
+
function isRootCrdt(crdt) {
|
|
2441
|
+
return crdt.type === 0 /* OBJECT */ && !isChildCrdt(crdt);
|
|
2377
2442
|
}
|
|
2378
|
-
function
|
|
2379
|
-
|
|
2380
|
-
const loLen = lo.length;
|
|
2381
|
-
const hiLen = hi.length;
|
|
2382
|
-
while (true) {
|
|
2383
|
-
const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
|
|
2384
|
-
const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
|
|
2385
|
-
if (loCode === hiCode) {
|
|
2386
|
-
index++;
|
|
2387
|
-
continue;
|
|
2388
|
-
}
|
|
2389
|
-
if (hiCode - loCode === 1) {
|
|
2390
|
-
const size = index + 1;
|
|
2391
|
-
let prefix = lo.substring(0, size);
|
|
2392
|
-
if (prefix.length < size) {
|
|
2393
|
-
prefix += ZERO.repeat(size - prefix.length);
|
|
2394
|
-
}
|
|
2395
|
-
const suffix = lo.substring(size);
|
|
2396
|
-
const nines = "";
|
|
2397
|
-
return prefix + _between(suffix, nines);
|
|
2398
|
-
} else {
|
|
2399
|
-
return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
}
|
|
2403
|
-
function takeN(pos, n) {
|
|
2404
|
-
return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
|
|
2405
|
-
}
|
|
2406
|
-
var MIN_NON_ZERO_CODE = MIN_CODE + 1;
|
|
2407
|
-
function isPos(str) {
|
|
2408
|
-
if (str === "") {
|
|
2409
|
-
return false;
|
|
2410
|
-
}
|
|
2411
|
-
const lastIdx = str.length - 1;
|
|
2412
|
-
const last = str.charCodeAt(lastIdx);
|
|
2413
|
-
if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
|
|
2414
|
-
return false;
|
|
2415
|
-
}
|
|
2416
|
-
for (let i = 0; i < lastIdx; i++) {
|
|
2417
|
-
const code = str.charCodeAt(i);
|
|
2418
|
-
if (code < MIN_CODE || code > MAX_CODE) {
|
|
2419
|
-
return false;
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
return true;
|
|
2423
|
-
}
|
|
2424
|
-
function convertToPos(str) {
|
|
2425
|
-
const codes = [];
|
|
2426
|
-
for (let i = 0; i < str.length; i++) {
|
|
2427
|
-
const code = str.charCodeAt(i);
|
|
2428
|
-
codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
|
|
2429
|
-
}
|
|
2430
|
-
while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
|
|
2431
|
-
codes.length--;
|
|
2432
|
-
}
|
|
2433
|
-
return codes.length > 0 ? String.fromCharCode(...codes) : (
|
|
2434
|
-
// Edge case: the str was a 0-only string, which is invalid. Default back to .1
|
|
2435
|
-
ONE
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
function asPos(str) {
|
|
2439
|
-
return isPos(str) ? str : convertToPos(str);
|
|
2443
|
+
function isChildCrdt(crdt) {
|
|
2444
|
+
return crdt.parentId !== void 0 && crdt.parentKey !== void 0;
|
|
2440
2445
|
}
|
|
2441
2446
|
|
|
2442
|
-
// src/
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
OpCode2[OpCode2["DELETE_OBJECT_KEY"] = 6] = "DELETE_OBJECT_KEY";
|
|
2451
|
-
OpCode2[OpCode2["CREATE_MAP"] = 7] = "CREATE_MAP";
|
|
2452
|
-
OpCode2[OpCode2["CREATE_REGISTER"] = 8] = "CREATE_REGISTER";
|
|
2453
|
-
return OpCode2;
|
|
2454
|
-
})(OpCode || {});
|
|
2455
|
-
function ackOp(opId) {
|
|
2456
|
-
return {
|
|
2457
|
-
type: 5 /* DELETE_CRDT */,
|
|
2458
|
-
id: "ACK",
|
|
2459
|
-
// (H)ACK
|
|
2460
|
-
opId
|
|
2461
|
-
};
|
|
2462
|
-
}
|
|
2463
|
-
function isAckOp(op) {
|
|
2464
|
-
return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
|
|
2447
|
+
// src/lib/nanoid.ts
|
|
2448
|
+
function nanoid(length = 7) {
|
|
2449
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,./;[]~!@#$%&*()_+=-";
|
|
2450
|
+
const len = alphabet.length;
|
|
2451
|
+
return Array.from(
|
|
2452
|
+
{ length },
|
|
2453
|
+
() => alphabet.charAt(Math.floor(Math.random() * len))
|
|
2454
|
+
).join("");
|
|
2465
2455
|
}
|
|
2466
2456
|
|
|
2467
|
-
// src/crdts/
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
function Orphaned(oldKey, oldPos = asPos(oldKey)) {
|
|
2476
|
-
return Object.freeze({ type: "Orphaned", oldKey, oldPos });
|
|
2477
|
-
}
|
|
2478
|
-
var AbstractCrdt = class {
|
|
2479
|
-
constructor() {
|
|
2480
|
-
/** @internal */
|
|
2481
|
-
this._parent = NoParent;
|
|
2457
|
+
// src/crdts/LiveRegister.ts
|
|
2458
|
+
var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
2459
|
+
constructor(data) {
|
|
2460
|
+
super();
|
|
2461
|
+
this._data = data;
|
|
2462
|
+
}
|
|
2463
|
+
get data() {
|
|
2464
|
+
return this._data;
|
|
2482
2465
|
}
|
|
2483
2466
|
/** @internal */
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
case "NoParent":
|
|
2489
|
-
throw new Error("Parent key is missing");
|
|
2490
|
-
case "Orphaned":
|
|
2491
|
-
return this.parent.oldKey;
|
|
2492
|
-
default:
|
|
2493
|
-
return assertNever(this.parent, "Unknown state");
|
|
2494
|
-
}
|
|
2467
|
+
static _deserialize([id, item], _parentToChildren, pool) {
|
|
2468
|
+
const register = new _LiveRegister(item.data);
|
|
2469
|
+
register._attach(id, pool);
|
|
2470
|
+
return register;
|
|
2495
2471
|
}
|
|
2496
2472
|
/** @internal */
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
throw new Error("Parent key is missing");
|
|
2503
|
-
case "Orphaned":
|
|
2504
|
-
return this.parent.oldPos;
|
|
2505
|
-
default:
|
|
2506
|
-
return assertNever(this.parent, "Unknown state");
|
|
2473
|
+
_toOps(parentId, parentKey, pool) {
|
|
2474
|
+
if (this._id === void 0) {
|
|
2475
|
+
throw new Error(
|
|
2476
|
+
"Cannot serialize register if parentId or parentKey is undefined"
|
|
2477
|
+
);
|
|
2507
2478
|
}
|
|
2479
|
+
return [
|
|
2480
|
+
{
|
|
2481
|
+
type: 8 /* CREATE_REGISTER */,
|
|
2482
|
+
opId: pool?.generateOpId(),
|
|
2483
|
+
id: this._id,
|
|
2484
|
+
parentId,
|
|
2485
|
+
parentKey,
|
|
2486
|
+
data: this.data
|
|
2487
|
+
}
|
|
2488
|
+
];
|
|
2508
2489
|
}
|
|
2509
2490
|
/** @internal */
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
return
|
|
2491
|
+
_serialize() {
|
|
2492
|
+
if (this.parent.type !== "HasParent") {
|
|
2493
|
+
throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
2494
|
+
}
|
|
2495
|
+
return {
|
|
2496
|
+
type: 3 /* REGISTER */,
|
|
2497
|
+
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
2498
|
+
parentKey: this.parent.key,
|
|
2499
|
+
data: this.data
|
|
2500
|
+
};
|
|
2515
2501
|
}
|
|
2516
2502
|
/** @internal */
|
|
2517
|
-
|
|
2518
|
-
|
|
2503
|
+
_attachChild(_op) {
|
|
2504
|
+
throw new Error("Method not implemented.");
|
|
2519
2505
|
}
|
|
2520
2506
|
/** @internal */
|
|
2521
|
-
|
|
2522
|
-
|
|
2507
|
+
_detachChild(_crdt) {
|
|
2508
|
+
throw new Error("Method not implemented.");
|
|
2523
2509
|
}
|
|
2524
2510
|
/** @internal */
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
case "HasParent":
|
|
2528
|
-
return this.parent.key;
|
|
2529
|
-
case "NoParent":
|
|
2530
|
-
return null;
|
|
2531
|
-
case "Orphaned":
|
|
2532
|
-
return this.parent.oldKey;
|
|
2533
|
-
default:
|
|
2534
|
-
return assertNever(this.parent, "Unknown state");
|
|
2535
|
-
}
|
|
2511
|
+
_apply(op, isLocal) {
|
|
2512
|
+
return super._apply(op, isLocal);
|
|
2536
2513
|
}
|
|
2537
2514
|
/** @internal */
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
return { modified: false };
|
|
2515
|
+
_toTreeNode(key) {
|
|
2516
|
+
return {
|
|
2517
|
+
type: "Json",
|
|
2518
|
+
id: this._id ?? nanoid(),
|
|
2519
|
+
key,
|
|
2520
|
+
payload: this._data
|
|
2521
|
+
};
|
|
2548
2522
|
}
|
|
2549
2523
|
/** @internal */
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
/** @internal */
|
|
2578
|
-
_detach() {
|
|
2579
|
-
if (this.__pool && this.__id) {
|
|
2580
|
-
this.__pool.deleteNode(this.__id);
|
|
2581
|
-
}
|
|
2582
|
-
switch (this.parent.type) {
|
|
2583
|
-
case "HasParent": {
|
|
2584
|
-
this._parent = Orphaned(this.parent.key, this.parent.pos);
|
|
2585
|
-
break;
|
|
2586
|
-
}
|
|
2587
|
-
case "NoParent": {
|
|
2588
|
-
this._parent = NoParent;
|
|
2589
|
-
break;
|
|
2590
|
-
}
|
|
2591
|
-
case "Orphaned": {
|
|
2592
|
-
break;
|
|
2593
|
-
}
|
|
2594
|
-
default:
|
|
2595
|
-
assertNever(this.parent, "Unknown state");
|
|
2596
|
-
}
|
|
2597
|
-
this.__pool = void 0;
|
|
2598
|
-
}
|
|
2599
|
-
/**
|
|
2600
|
-
* @internal
|
|
2601
|
-
*
|
|
2602
|
-
* Clear the Immutable cache, so that the next call to `.toImmutable()` will
|
|
2603
|
-
* recompute the equivalent Immutable value again. Call this after every
|
|
2604
|
-
* mutation to the Live node.
|
|
2605
|
-
*/
|
|
2606
|
-
invalidate() {
|
|
2607
|
-
if (this._cachedImmutable !== void 0 || this._cachedTreeNode !== void 0) {
|
|
2608
|
-
this._cachedImmutable = void 0;
|
|
2609
|
-
this._cachedTreeNode = void 0;
|
|
2610
|
-
if (this.parent.type === "HasParent") {
|
|
2611
|
-
this.parent.node.invalidate();
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2614
|
-
}
|
|
2615
|
-
/**
|
|
2616
|
-
* @internal
|
|
2617
|
-
*
|
|
2618
|
-
* Return an snapshot of this Live tree for use in DevTools.
|
|
2619
|
-
*/
|
|
2620
|
-
toTreeNode(key) {
|
|
2621
|
-
if (this._cachedTreeNode === void 0 || this._cachedTreeNodeKey !== key) {
|
|
2622
|
-
this._cachedTreeNodeKey = key;
|
|
2623
|
-
this._cachedTreeNode = this._toTreeNode(key);
|
|
2624
|
-
}
|
|
2625
|
-
return this._cachedTreeNode;
|
|
2626
|
-
}
|
|
2627
|
-
/**
|
|
2628
|
-
* Return an immutable snapshot of this Live node and its children.
|
|
2629
|
-
*/
|
|
2630
|
-
toImmutable() {
|
|
2631
|
-
if (this._cachedImmutable === void 0) {
|
|
2632
|
-
this._cachedImmutable = this._toImmutable();
|
|
2633
|
-
}
|
|
2634
|
-
return this._cachedImmutable;
|
|
2635
|
-
}
|
|
2636
|
-
};
|
|
2637
|
-
|
|
2638
|
-
// src/protocol/SerializedCrdt.ts
|
|
2639
|
-
var CrdtType = /* @__PURE__ */ ((CrdtType2) => {
|
|
2640
|
-
CrdtType2[CrdtType2["OBJECT"] = 0] = "OBJECT";
|
|
2641
|
-
CrdtType2[CrdtType2["LIST"] = 1] = "LIST";
|
|
2642
|
-
CrdtType2[CrdtType2["MAP"] = 2] = "MAP";
|
|
2643
|
-
CrdtType2[CrdtType2["REGISTER"] = 3] = "REGISTER";
|
|
2644
|
-
return CrdtType2;
|
|
2645
|
-
})(CrdtType || {});
|
|
2646
|
-
function isRootCrdt(crdt) {
|
|
2647
|
-
return crdt.type === 0 /* OBJECT */ && !isChildCrdt(crdt);
|
|
2648
|
-
}
|
|
2649
|
-
function isChildCrdt(crdt) {
|
|
2650
|
-
return crdt.parentId !== void 0 && crdt.parentKey !== void 0;
|
|
2651
|
-
}
|
|
2652
|
-
|
|
2653
|
-
// src/lib/nanoid.ts
|
|
2654
|
-
function nanoid(length = 7) {
|
|
2655
|
-
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,./;[]~!@#$%&*()_+=-";
|
|
2656
|
-
const len = alphabet.length;
|
|
2657
|
-
return Array.from(
|
|
2658
|
-
{ length },
|
|
2659
|
-
() => alphabet.charAt(Math.floor(Math.random() * len))
|
|
2660
|
-
).join("");
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
// src/crdts/LiveRegister.ts
|
|
2664
|
-
var LiveRegister = class _LiveRegister extends AbstractCrdt {
|
|
2665
|
-
constructor(data) {
|
|
2666
|
-
super();
|
|
2667
|
-
this._data = data;
|
|
2668
|
-
}
|
|
2669
|
-
get data() {
|
|
2670
|
-
return this._data;
|
|
2671
|
-
}
|
|
2672
|
-
/** @internal */
|
|
2673
|
-
static _deserialize([id, item], _parentToChildren, pool) {
|
|
2674
|
-
const register = new _LiveRegister(item.data);
|
|
2675
|
-
register._attach(id, pool);
|
|
2676
|
-
return register;
|
|
2677
|
-
}
|
|
2678
|
-
/** @internal */
|
|
2679
|
-
_toOps(parentId, parentKey, pool) {
|
|
2680
|
-
if (this._id === void 0) {
|
|
2681
|
-
throw new Error(
|
|
2682
|
-
"Cannot serialize register if parentId or parentKey is undefined"
|
|
2683
|
-
);
|
|
2684
|
-
}
|
|
2685
|
-
return [
|
|
2686
|
-
{
|
|
2687
|
-
type: 8 /* CREATE_REGISTER */,
|
|
2688
|
-
opId: pool?.generateOpId(),
|
|
2689
|
-
id: this._id,
|
|
2690
|
-
parentId,
|
|
2691
|
-
parentKey,
|
|
2692
|
-
data: this.data
|
|
2693
|
-
}
|
|
2694
|
-
];
|
|
2695
|
-
}
|
|
2696
|
-
/** @internal */
|
|
2697
|
-
_serialize() {
|
|
2698
|
-
if (this.parent.type !== "HasParent") {
|
|
2699
|
-
throw new Error("Cannot serialize LiveRegister if parent is missing");
|
|
2700
|
-
}
|
|
2701
|
-
return {
|
|
2702
|
-
type: 3 /* REGISTER */,
|
|
2703
|
-
parentId: nn(this.parent.node._id, "Parent node expected to have ID"),
|
|
2704
|
-
parentKey: this.parent.key,
|
|
2705
|
-
data: this.data
|
|
2706
|
-
};
|
|
2707
|
-
}
|
|
2708
|
-
/** @internal */
|
|
2709
|
-
_attachChild(_op) {
|
|
2710
|
-
throw new Error("Method not implemented.");
|
|
2711
|
-
}
|
|
2712
|
-
/** @internal */
|
|
2713
|
-
_detachChild(_crdt) {
|
|
2714
|
-
throw new Error("Method not implemented.");
|
|
2715
|
-
}
|
|
2716
|
-
/** @internal */
|
|
2717
|
-
_apply(op, isLocal) {
|
|
2718
|
-
return super._apply(op, isLocal);
|
|
2719
|
-
}
|
|
2720
|
-
/** @internal */
|
|
2721
|
-
_toTreeNode(key) {
|
|
2722
|
-
return {
|
|
2723
|
-
type: "Json",
|
|
2724
|
-
id: this._id ?? nanoid(),
|
|
2725
|
-
key,
|
|
2726
|
-
payload: this._data
|
|
2727
|
-
};
|
|
2728
|
-
}
|
|
2729
|
-
/** @internal */
|
|
2730
|
-
_toImmutable() {
|
|
2731
|
-
return this._data;
|
|
2732
|
-
}
|
|
2733
|
-
clone() {
|
|
2734
|
-
return deepClone(this.data);
|
|
2735
|
-
}
|
|
2736
|
-
};
|
|
2737
|
-
|
|
2738
|
-
// src/crdts/LiveList.ts
|
|
2739
|
-
function compareNodePosition(itemA, itemB) {
|
|
2740
|
-
const posA = itemA._parentPos;
|
|
2741
|
-
const posB = itemB._parentPos;
|
|
2742
|
-
return posA === posB ? 0 : posA < posB ? -1 : 1;
|
|
2743
|
-
}
|
|
2744
|
-
var LiveList = class _LiveList extends AbstractCrdt {
|
|
2745
|
-
constructor(items = []) {
|
|
2746
|
-
super();
|
|
2747
|
-
this._items = [];
|
|
2748
|
-
this._implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
|
|
2749
|
-
this._unacknowledgedSets = /* @__PURE__ */ new Map();
|
|
2750
|
-
let position = void 0;
|
|
2751
|
-
for (const item of items) {
|
|
2752
|
-
const newPosition = makePosition(position);
|
|
2753
|
-
const node = lsonToLiveNode(item);
|
|
2754
|
-
node._setParentLink(this, newPosition);
|
|
2755
|
-
this._items.push(node);
|
|
2756
|
-
position = newPosition;
|
|
2524
|
+
_toImmutable() {
|
|
2525
|
+
return this._data;
|
|
2526
|
+
}
|
|
2527
|
+
clone() {
|
|
2528
|
+
return deepClone(this.data);
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
|
|
2532
|
+
// src/crdts/LiveList.ts
|
|
2533
|
+
function compareNodePosition(itemA, itemB) {
|
|
2534
|
+
const posA = itemA._parentPos;
|
|
2535
|
+
const posB = itemB._parentPos;
|
|
2536
|
+
return posA === posB ? 0 : posA < posB ? -1 : 1;
|
|
2537
|
+
}
|
|
2538
|
+
var LiveList = class _LiveList extends AbstractCrdt {
|
|
2539
|
+
constructor(items = []) {
|
|
2540
|
+
super();
|
|
2541
|
+
this._items = [];
|
|
2542
|
+
this._implicitlyDeletedItems = /* @__PURE__ */ new WeakSet();
|
|
2543
|
+
this._unacknowledgedSets = /* @__PURE__ */ new Map();
|
|
2544
|
+
let position = void 0;
|
|
2545
|
+
for (const item of items) {
|
|
2546
|
+
const newPosition = makePosition(position);
|
|
2547
|
+
const node = lsonToLiveNode(item);
|
|
2548
|
+
node._setParentLink(this, newPosition);
|
|
2549
|
+
this._items.push(node);
|
|
2550
|
+
position = newPosition;
|
|
2757
2551
|
}
|
|
2758
2552
|
}
|
|
2759
2553
|
/** @internal */
|
|
@@ -5156,54 +4950,272 @@ function installBackgroundTabSpy() {
|
|
|
5156
4950
|
};
|
|
5157
4951
|
return [inBackgroundSince, unsub];
|
|
5158
4952
|
}
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
// Queue up the initial presence message as a Full Presence™ update
|
|
5187
|
-
{
|
|
5188
|
-
type: "full",
|
|
5189
|
-
data: initialPresence
|
|
4953
|
+
var CommentsApiError = class extends Error {
|
|
4954
|
+
constructor(message, status, details) {
|
|
4955
|
+
super(message);
|
|
4956
|
+
this.message = message;
|
|
4957
|
+
this.status = status;
|
|
4958
|
+
this.details = details;
|
|
4959
|
+
}
|
|
4960
|
+
};
|
|
4961
|
+
function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
|
|
4962
|
+
async function fetchCommentsApi(endpoint, options) {
|
|
4963
|
+
const authValue = await getAuthValue();
|
|
4964
|
+
return fetchClientApi(roomId, endpoint, authValue, options);
|
|
4965
|
+
}
|
|
4966
|
+
async function fetchJson(endpoint, options) {
|
|
4967
|
+
const response = await fetchCommentsApi(endpoint, options);
|
|
4968
|
+
if (!response.ok) {
|
|
4969
|
+
if (response.status >= 400 && response.status < 600) {
|
|
4970
|
+
let error3;
|
|
4971
|
+
try {
|
|
4972
|
+
const errorBody = await response.json();
|
|
4973
|
+
error3 = new CommentsApiError(
|
|
4974
|
+
errorBody.message,
|
|
4975
|
+
response.status,
|
|
4976
|
+
errorBody
|
|
4977
|
+
);
|
|
4978
|
+
} catch {
|
|
4979
|
+
error3 = new CommentsApiError(response.statusText, response.status);
|
|
5190
4980
|
}
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
4981
|
+
throw error3;
|
|
4982
|
+
}
|
|
4983
|
+
}
|
|
4984
|
+
let body;
|
|
4985
|
+
try {
|
|
4986
|
+
body = await response.json();
|
|
4987
|
+
} catch {
|
|
4988
|
+
body = {};
|
|
4989
|
+
}
|
|
4990
|
+
return body;
|
|
4991
|
+
}
|
|
4992
|
+
async function getThreads(options) {
|
|
4993
|
+
const response = await fetchCommentsApi("/threads/search", {
|
|
4994
|
+
body: JSON.stringify({
|
|
4995
|
+
...options?.query?.metadata && { metadata: options.query.metadata }
|
|
4996
|
+
}),
|
|
4997
|
+
headers: {
|
|
4998
|
+
"Content-Type": "application/json"
|
|
4999
|
+
},
|
|
5000
|
+
method: "POST"
|
|
5001
|
+
});
|
|
5002
|
+
if (response.ok) {
|
|
5003
|
+
const json = await response.json();
|
|
5004
|
+
return {
|
|
5005
|
+
threads: json.data.map((thread) => convertToThreadData(thread)),
|
|
5006
|
+
inboxNotifications: json.inboxNotifications.map(
|
|
5007
|
+
(notification) => convertToInboxNotificationData(notification)
|
|
5008
|
+
)
|
|
5009
|
+
};
|
|
5010
|
+
} else if (response.status === 404) {
|
|
5011
|
+
return { threads: [], inboxNotifications: [] };
|
|
5012
|
+
} else {
|
|
5013
|
+
throw new Error("There was an error while getting threads.");
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
async function getThread({ threadId }) {
|
|
5017
|
+
const response = await fetchCommentsApi(
|
|
5018
|
+
`/thread-with-notification/${threadId}`
|
|
5019
|
+
);
|
|
5020
|
+
if (response.ok) {
|
|
5021
|
+
const json = await response.json();
|
|
5022
|
+
return {
|
|
5023
|
+
thread: convertToThreadData(json.thread),
|
|
5024
|
+
inboxNotification: json.inboxNotification ? convertToInboxNotificationData(json.inboxNotification) : void 0
|
|
5025
|
+
};
|
|
5026
|
+
} else if (response.status === 404) {
|
|
5027
|
+
return;
|
|
5028
|
+
} else {
|
|
5029
|
+
throw new Error(`There was an error while getting thread ${threadId}.`);
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
async function createThread({
|
|
5033
|
+
metadata,
|
|
5034
|
+
body,
|
|
5035
|
+
commentId,
|
|
5036
|
+
threadId
|
|
5037
|
+
}) {
|
|
5038
|
+
const thread = await fetchJson(
|
|
5039
|
+
"/threads",
|
|
5040
|
+
{
|
|
5041
|
+
method: "POST",
|
|
5042
|
+
headers: {
|
|
5043
|
+
"Content-Type": "application/json"
|
|
5044
|
+
},
|
|
5045
|
+
body: JSON.stringify({
|
|
5046
|
+
id: threadId,
|
|
5047
|
+
comment: {
|
|
5048
|
+
id: commentId,
|
|
5049
|
+
body
|
|
5050
|
+
},
|
|
5051
|
+
metadata
|
|
5052
|
+
})
|
|
5053
|
+
}
|
|
5054
|
+
);
|
|
5055
|
+
return convertToThreadData(thread);
|
|
5056
|
+
}
|
|
5057
|
+
async function editThreadMetadata({
|
|
5058
|
+
metadata,
|
|
5059
|
+
threadId
|
|
5060
|
+
}) {
|
|
5061
|
+
return await fetchJson(
|
|
5062
|
+
`/threads/${encodeURIComponent(threadId)}/metadata`,
|
|
5063
|
+
{
|
|
5064
|
+
method: "POST",
|
|
5065
|
+
headers: {
|
|
5066
|
+
"Content-Type": "application/json"
|
|
5067
|
+
},
|
|
5068
|
+
body: JSON.stringify(metadata)
|
|
5069
|
+
}
|
|
5070
|
+
);
|
|
5071
|
+
}
|
|
5072
|
+
async function createComment({
|
|
5073
|
+
threadId,
|
|
5074
|
+
commentId,
|
|
5075
|
+
body
|
|
5076
|
+
}) {
|
|
5077
|
+
const comment = await fetchJson(
|
|
5078
|
+
`/threads/${encodeURIComponent(threadId)}/comments`,
|
|
5079
|
+
{
|
|
5080
|
+
method: "POST",
|
|
5081
|
+
headers: {
|
|
5082
|
+
"Content-Type": "application/json"
|
|
5083
|
+
},
|
|
5084
|
+
body: JSON.stringify({
|
|
5085
|
+
id: commentId,
|
|
5086
|
+
body
|
|
5087
|
+
})
|
|
5088
|
+
}
|
|
5089
|
+
);
|
|
5090
|
+
return convertToCommentData(comment);
|
|
5091
|
+
}
|
|
5092
|
+
async function editComment({
|
|
5093
|
+
threadId,
|
|
5094
|
+
commentId,
|
|
5095
|
+
body
|
|
5096
|
+
}) {
|
|
5097
|
+
const comment = await fetchJson(
|
|
5098
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5099
|
+
commentId
|
|
5100
|
+
)}`,
|
|
5101
|
+
{
|
|
5102
|
+
method: "POST",
|
|
5103
|
+
headers: {
|
|
5104
|
+
"Content-Type": "application/json"
|
|
5105
|
+
},
|
|
5106
|
+
body: JSON.stringify({
|
|
5107
|
+
body
|
|
5108
|
+
})
|
|
5109
|
+
}
|
|
5110
|
+
);
|
|
5111
|
+
return convertToCommentData(comment);
|
|
5112
|
+
}
|
|
5113
|
+
async function deleteComment({
|
|
5114
|
+
threadId,
|
|
5115
|
+
commentId
|
|
5116
|
+
}) {
|
|
5117
|
+
await fetchJson(
|
|
5118
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5119
|
+
commentId
|
|
5120
|
+
)}`,
|
|
5121
|
+
{
|
|
5122
|
+
method: "DELETE"
|
|
5123
|
+
}
|
|
5124
|
+
);
|
|
5125
|
+
}
|
|
5126
|
+
async function addReaction({
|
|
5127
|
+
threadId,
|
|
5128
|
+
commentId,
|
|
5129
|
+
emoji
|
|
5130
|
+
}) {
|
|
5131
|
+
const reaction = await fetchJson(
|
|
5132
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5133
|
+
commentId
|
|
5134
|
+
)}/reactions`,
|
|
5135
|
+
{
|
|
5136
|
+
method: "POST",
|
|
5137
|
+
headers: {
|
|
5138
|
+
"Content-Type": "application/json"
|
|
5139
|
+
},
|
|
5140
|
+
body: JSON.stringify({ emoji })
|
|
5141
|
+
}
|
|
5142
|
+
);
|
|
5143
|
+
return convertToCommentUserReaction(reaction);
|
|
5144
|
+
}
|
|
5145
|
+
async function removeReaction({
|
|
5146
|
+
threadId,
|
|
5147
|
+
commentId,
|
|
5148
|
+
emoji
|
|
5149
|
+
}) {
|
|
5150
|
+
await fetchJson(
|
|
5151
|
+
`/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
|
|
5152
|
+
commentId
|
|
5153
|
+
)}/reactions/${encodeURIComponent(emoji)}`,
|
|
5154
|
+
{
|
|
5155
|
+
method: "DELETE"
|
|
5156
|
+
}
|
|
5157
|
+
);
|
|
5158
|
+
}
|
|
5159
|
+
return {
|
|
5160
|
+
getThreads,
|
|
5161
|
+
getThread,
|
|
5162
|
+
createThread,
|
|
5163
|
+
editThreadMetadata,
|
|
5164
|
+
createComment,
|
|
5165
|
+
editComment,
|
|
5166
|
+
deleteComment,
|
|
5167
|
+
addReaction,
|
|
5168
|
+
removeReaction
|
|
5169
|
+
};
|
|
5170
|
+
}
|
|
5171
|
+
function createRoom(options, config) {
|
|
5172
|
+
const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
|
|
5173
|
+
const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
|
|
5174
|
+
const [inBackgroundSince, uninstallBgTabSpy] = installBackgroundTabSpy();
|
|
5175
|
+
const delegates = {
|
|
5176
|
+
...config.delegates,
|
|
5177
|
+
// A connection is allowed to go into "zombie state" only if all of the
|
|
5178
|
+
// following conditions apply:
|
|
5179
|
+
//
|
|
5180
|
+
// - The `backgroundKeepAliveTimeout` client option is configured
|
|
5181
|
+
// - The browser window has been in the background for at least
|
|
5182
|
+
// `backgroundKeepAliveTimeout` milliseconds
|
|
5183
|
+
// - There are no pending changes
|
|
5184
|
+
//
|
|
5185
|
+
canZombie() {
|
|
5186
|
+
return config.backgroundKeepAliveTimeout !== void 0 && inBackgroundSince.current !== null && Date.now() > inBackgroundSince.current + config.backgroundKeepAliveTimeout && getStorageStatus() !== "synchronizing";
|
|
5187
|
+
}
|
|
5188
|
+
};
|
|
5189
|
+
const managedSocket = new ManagedSocket(
|
|
5190
|
+
delegates,
|
|
5191
|
+
config.enableDebugLogging
|
|
5192
|
+
);
|
|
5193
|
+
const context = {
|
|
5194
|
+
buffer: {
|
|
5195
|
+
flushTimerID: void 0,
|
|
5196
|
+
lastFlushedAt: 0,
|
|
5197
|
+
presenceUpdates: (
|
|
5198
|
+
// Queue up the initial presence message as a Full Presence™ update
|
|
5199
|
+
{
|
|
5200
|
+
type: "full",
|
|
5201
|
+
data: initialPresence
|
|
5202
|
+
}
|
|
5203
|
+
),
|
|
5204
|
+
messages: [],
|
|
5205
|
+
storageOperations: []
|
|
5206
|
+
},
|
|
5207
|
+
staticSessionInfo: new ValueRef(null),
|
|
5208
|
+
dynamicSessionInfo: new ValueRef(null),
|
|
5209
|
+
myPresence: new PatchableRef(initialPresence),
|
|
5210
|
+
others: new OthersRef(),
|
|
5211
|
+
initialStorage,
|
|
5212
|
+
idFactory: null,
|
|
5213
|
+
// Storage
|
|
5214
|
+
clock: 0,
|
|
5215
|
+
opClock: 0,
|
|
5216
|
+
nodes: /* @__PURE__ */ new Map(),
|
|
5217
|
+
root: void 0,
|
|
5218
|
+
undoStack: [],
|
|
5207
5219
|
redoStack: [],
|
|
5208
5220
|
pausedHistory: null,
|
|
5209
5221
|
activeBatch: null,
|
|
@@ -5217,7 +5229,7 @@ function createRoom(options, config) {
|
|
|
5217
5229
|
function onStatusDidChange(newStatus) {
|
|
5218
5230
|
const authValue = managedSocket.authValue;
|
|
5219
5231
|
if (authValue !== null) {
|
|
5220
|
-
const tokenKey = authValue
|
|
5232
|
+
const tokenKey = getAuthBearerHeaderFromAuthValue(authValue);
|
|
5221
5233
|
if (tokenKey !== lastTokenKey) {
|
|
5222
5234
|
lastTokenKey = tokenKey;
|
|
5223
5235
|
if (authValue.type === "secret") {
|
|
@@ -5371,18 +5383,26 @@ function createRoom(options, config) {
|
|
|
5371
5383
|
ydoc: makeEventSource(),
|
|
5372
5384
|
comments: makeEventSource()
|
|
5373
5385
|
};
|
|
5374
|
-
async function
|
|
5386
|
+
async function fetchClientApi(roomId, endpoint, authValue, options2) {
|
|
5375
5387
|
const url = new URL(
|
|
5376
|
-
`/v2/c/rooms/${encodeURIComponent(roomId)}
|
|
5388
|
+
`/v2/c/rooms/${encodeURIComponent(roomId)}${endpoint}`,
|
|
5377
5389
|
config.baseUrl
|
|
5378
|
-
)
|
|
5390
|
+
);
|
|
5379
5391
|
const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
|
|
5380
5392
|
fetch;
|
|
5381
|
-
return fetcher(url.toString(), {
|
|
5393
|
+
return await fetcher(url.toString(), {
|
|
5394
|
+
...options2,
|
|
5395
|
+
headers: {
|
|
5396
|
+
...options2?.headers,
|
|
5397
|
+
Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
|
|
5398
|
+
}
|
|
5399
|
+
});
|
|
5400
|
+
}
|
|
5401
|
+
async function streamFetch(authValue, roomId) {
|
|
5402
|
+
return fetchClientApi(roomId, "/storage", authValue, {
|
|
5382
5403
|
method: "GET",
|
|
5383
5404
|
headers: {
|
|
5384
|
-
"Content-Type": "application/json"
|
|
5385
|
-
Authorization: `Bearer ${authTokenOrPublicApiKey}`
|
|
5405
|
+
"Content-Type": "application/json"
|
|
5386
5406
|
}
|
|
5387
5407
|
});
|
|
5388
5408
|
}
|
|
@@ -5390,18 +5410,10 @@ function createRoom(options, config) {
|
|
|
5390
5410
|
if (!managedSocket.authValue) {
|
|
5391
5411
|
throw new Error("Not authorized");
|
|
5392
5412
|
}
|
|
5393
|
-
|
|
5394
|
-
const url = new URL(
|
|
5395
|
-
`/v2/c/rooms/${encodeURIComponent(config.roomId)}${endpoint}`,
|
|
5396
|
-
config.baseUrl
|
|
5397
|
-
).toString();
|
|
5398
|
-
const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
|
|
5399
|
-
fetch;
|
|
5400
|
-
return fetcher(url, {
|
|
5413
|
+
return fetchClientApi(config.roomId, endpoint, managedSocket.authValue, {
|
|
5401
5414
|
method: "POST",
|
|
5402
5415
|
headers: {
|
|
5403
|
-
"Content-Type": "application/json"
|
|
5404
|
-
Authorization: `Bearer ${authTokenOrPublicApiKey}`
|
|
5416
|
+
"Content-Type": "application/json"
|
|
5405
5417
|
},
|
|
5406
5418
|
body: JSON.stringify(body)
|
|
5407
5419
|
});
|
|
@@ -6015,10 +6027,7 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6015
6027
|
if (!managedSocket.authValue) {
|
|
6016
6028
|
return;
|
|
6017
6029
|
}
|
|
6018
|
-
const result = await streamFetch(
|
|
6019
|
-
managedSocket.authValue.type === "public" ? managedSocket.authValue.publicApiKey : managedSocket.authValue.token.raw,
|
|
6020
|
-
config.roomId
|
|
6021
|
-
);
|
|
6030
|
+
const result = await streamFetch(managedSocket.authValue, config.roomId);
|
|
6022
6031
|
const items = await result.json();
|
|
6023
6032
|
processInitialStorage({ type: 200 /* INITIAL_STORAGE_STATE */, items });
|
|
6024
6033
|
}
|
|
@@ -6204,27 +6213,71 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6204
6213
|
ydoc: eventHub.ydoc.observable,
|
|
6205
6214
|
comments: eventHub.comments.observable
|
|
6206
6215
|
};
|
|
6207
|
-
const commentsApi = createCommentsApi(
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6216
|
+
const commentsApi = createCommentsApi(
|
|
6217
|
+
config.roomId,
|
|
6218
|
+
delegates.authenticate,
|
|
6219
|
+
fetchClientApi
|
|
6220
|
+
);
|
|
6221
|
+
async function fetchJson(endpoint, options2) {
|
|
6222
|
+
const authValue = await delegates.authenticate();
|
|
6223
|
+
const response = await fetchClientApi(
|
|
6224
|
+
config.roomId,
|
|
6225
|
+
endpoint,
|
|
6226
|
+
authValue,
|
|
6227
|
+
options2
|
|
6228
|
+
);
|
|
6229
|
+
if (!response.ok) {
|
|
6230
|
+
if (response.status >= 400 && response.status < 600) {
|
|
6231
|
+
let errorMessage = "";
|
|
6232
|
+
try {
|
|
6233
|
+
const errorBody = await response.json();
|
|
6234
|
+
errorMessage = errorBody.message;
|
|
6235
|
+
} catch (error3) {
|
|
6236
|
+
errorMessage = response.statusText;
|
|
6237
|
+
}
|
|
6238
|
+
throw new Error(
|
|
6239
|
+
`Request failed with status ${response.status}: ${errorMessage}`
|
|
6240
|
+
);
|
|
6241
|
+
}
|
|
6242
|
+
}
|
|
6243
|
+
let body;
|
|
6244
|
+
try {
|
|
6245
|
+
body = await response.json();
|
|
6246
|
+
} catch {
|
|
6247
|
+
body = {};
|
|
6248
|
+
}
|
|
6249
|
+
return body;
|
|
6250
|
+
}
|
|
6251
|
+
function getRoomNotificationSettings() {
|
|
6252
|
+
return fetchJson("/notification-settings");
|
|
6253
|
+
}
|
|
6254
|
+
function updateRoomNotificationSettings(settings) {
|
|
6255
|
+
return fetchJson("/notification-settings", {
|
|
6256
|
+
method: "POST",
|
|
6257
|
+
body: JSON.stringify(settings),
|
|
6258
|
+
headers: {
|
|
6259
|
+
"Content-Type": "application/json"
|
|
6260
|
+
}
|
|
6261
|
+
});
|
|
6262
|
+
}
|
|
6263
|
+
return Object.defineProperty(
|
|
6264
|
+
{
|
|
6265
|
+
/* NOTE: Exposing internals here only to allow testing implementation details in unit tests */
|
|
6266
|
+
[kInternal]: {
|
|
6267
|
+
get presenceBuffer() {
|
|
6268
|
+
return deepClone(context.buffer.presenceUpdates?.data ?? null);
|
|
6269
|
+
},
|
|
6270
|
+
// prettier-ignore
|
|
6271
|
+
get undoStack() {
|
|
6272
|
+
return deepClone(context.undoStack);
|
|
6273
|
+
},
|
|
6274
|
+
// prettier-ignore
|
|
6275
|
+
get nodeCount() {
|
|
6276
|
+
return context.nodes.size;
|
|
6277
|
+
},
|
|
6278
|
+
// prettier-ignore
|
|
6279
|
+
// Support for the Liveblocks browser extension
|
|
6280
|
+
getSelf_forDevTools: () => selfAsTreeNode.current,
|
|
6228
6281
|
getOthers_forDevTools: () => others_forDevTools.current,
|
|
6229
6282
|
// prettier-ignore
|
|
6230
6283
|
simulate: {
|
|
@@ -6269,11 +6322,15 @@ ${Array.from(traces).join("\n\n")}`
|
|
|
6269
6322
|
// Presence
|
|
6270
6323
|
getPresence: () => context.myPresence.current,
|
|
6271
6324
|
getOthers: () => context.others.current,
|
|
6272
|
-
|
|
6325
|
+
// Comments
|
|
6326
|
+
...commentsApi,
|
|
6327
|
+
// Notifications
|
|
6328
|
+
getRoomNotificationSettings,
|
|
6329
|
+
updateRoomNotificationSettings
|
|
6273
6330
|
},
|
|
6274
|
-
// Explictly make the
|
|
6331
|
+
// Explictly make the internal field non-enumerable, to avoid aggressive
|
|
6275
6332
|
// freezing when used with Immer
|
|
6276
|
-
|
|
6333
|
+
kInternal,
|
|
6277
6334
|
{ enumerable: false }
|
|
6278
6335
|
);
|
|
6279
6336
|
}
|
|
@@ -6373,7 +6430,7 @@ function isRoomEventName(value) {
|
|
|
6373
6430
|
}
|
|
6374
6431
|
function makeAuthDelegateForRoom(roomId, authManager) {
|
|
6375
6432
|
return async () => {
|
|
6376
|
-
return authManager.getAuthValue("room:read", roomId);
|
|
6433
|
+
return authManager.getAuthValue({ requestedScope: "room:read", roomId });
|
|
6377
6434
|
};
|
|
6378
6435
|
}
|
|
6379
6436
|
function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
|
|
@@ -6400,6 +6457,327 @@ function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
|
|
|
6400
6457
|
};
|
|
6401
6458
|
}
|
|
6402
6459
|
|
|
6460
|
+
// src/store.ts
|
|
6461
|
+
function createClientStore() {
|
|
6462
|
+
const store = createStore({
|
|
6463
|
+
threads: {},
|
|
6464
|
+
queries: {},
|
|
6465
|
+
optimisticUpdates: [],
|
|
6466
|
+
inboxNotifications: {},
|
|
6467
|
+
notificationSettings: {}
|
|
6468
|
+
});
|
|
6469
|
+
function mergeThreads(existingThreads, newThreads) {
|
|
6470
|
+
const updatedThreads = { ...existingThreads };
|
|
6471
|
+
Object.entries(newThreads).forEach(([id, thread]) => {
|
|
6472
|
+
const existingThread = updatedThreads[id];
|
|
6473
|
+
if (existingThread) {
|
|
6474
|
+
const result = compareThreads(existingThread, thread);
|
|
6475
|
+
if (result === 1)
|
|
6476
|
+
return;
|
|
6477
|
+
}
|
|
6478
|
+
updatedThreads[id] = thread;
|
|
6479
|
+
});
|
|
6480
|
+
return updatedThreads;
|
|
6481
|
+
}
|
|
6482
|
+
function mergeNotifications(existingInboxNotifications, newInboxNotifications) {
|
|
6483
|
+
const inboxNotifications = Object.values({
|
|
6484
|
+
...existingInboxNotifications,
|
|
6485
|
+
...newInboxNotifications
|
|
6486
|
+
});
|
|
6487
|
+
return Object.fromEntries(
|
|
6488
|
+
inboxNotifications.map((notification) => [notification.id, notification])
|
|
6489
|
+
);
|
|
6490
|
+
}
|
|
6491
|
+
return {
|
|
6492
|
+
...store,
|
|
6493
|
+
deleteThread(threadId) {
|
|
6494
|
+
store.set((state) => {
|
|
6495
|
+
return {
|
|
6496
|
+
...state,
|
|
6497
|
+
threads: deleteKeyImmutable(state.threads, threadId),
|
|
6498
|
+
inboxNotifications: Object.fromEntries(
|
|
6499
|
+
Object.entries(state.inboxNotifications).filter(
|
|
6500
|
+
([_id, notification]) => notification.threadId !== threadId
|
|
6501
|
+
)
|
|
6502
|
+
)
|
|
6503
|
+
};
|
|
6504
|
+
});
|
|
6505
|
+
},
|
|
6506
|
+
updateThreadAndNotification(thread, inboxNotification) {
|
|
6507
|
+
store.set((state) => {
|
|
6508
|
+
const existingThread = state.threads[thread.id];
|
|
6509
|
+
return {
|
|
6510
|
+
...state,
|
|
6511
|
+
threads: existingThread === void 0 || compareThreads(thread, existingThread) === 1 ? { ...state.threads, [thread.id]: thread } : state.threads,
|
|
6512
|
+
inboxNotifications: inboxNotification === void 0 ? state.inboxNotifications : {
|
|
6513
|
+
...state.inboxNotifications,
|
|
6514
|
+
[inboxNotification.id]: inboxNotification
|
|
6515
|
+
}
|
|
6516
|
+
};
|
|
6517
|
+
});
|
|
6518
|
+
},
|
|
6519
|
+
updateThreadsAndNotifications(threads, inboxNotifications, queryKey) {
|
|
6520
|
+
store.set((state) => ({
|
|
6521
|
+
...state,
|
|
6522
|
+
threads: mergeThreads(
|
|
6523
|
+
state.threads,
|
|
6524
|
+
Object.fromEntries(threads.map((thread) => [thread.id, thread]))
|
|
6525
|
+
),
|
|
6526
|
+
inboxNotifications: mergeNotifications(
|
|
6527
|
+
state.inboxNotifications,
|
|
6528
|
+
Object.fromEntries(
|
|
6529
|
+
inboxNotifications.map((notification) => [
|
|
6530
|
+
notification.id,
|
|
6531
|
+
notification
|
|
6532
|
+
])
|
|
6533
|
+
)
|
|
6534
|
+
),
|
|
6535
|
+
queries: queryKey !== void 0 ? {
|
|
6536
|
+
...state.queries,
|
|
6537
|
+
[queryKey]: {
|
|
6538
|
+
isLoading: false
|
|
6539
|
+
}
|
|
6540
|
+
} : state.queries
|
|
6541
|
+
}));
|
|
6542
|
+
},
|
|
6543
|
+
pushOptimisticUpdate(optimisticUpdate) {
|
|
6544
|
+
store.set((state) => ({
|
|
6545
|
+
...state,
|
|
6546
|
+
optimisticUpdates: [...state.optimisticUpdates, optimisticUpdate]
|
|
6547
|
+
}));
|
|
6548
|
+
},
|
|
6549
|
+
setQueryState(queryKey, queryState) {
|
|
6550
|
+
store.set((state) => ({
|
|
6551
|
+
...state,
|
|
6552
|
+
queries: {
|
|
6553
|
+
...state.queries,
|
|
6554
|
+
[queryKey]: queryState
|
|
6555
|
+
}
|
|
6556
|
+
}));
|
|
6557
|
+
}
|
|
6558
|
+
};
|
|
6559
|
+
}
|
|
6560
|
+
function deleteKeyImmutable(record, key) {
|
|
6561
|
+
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
|
6562
|
+
const { [key]: _toDelete, ...rest } = record;
|
|
6563
|
+
return rest;
|
|
6564
|
+
}
|
|
6565
|
+
return record;
|
|
6566
|
+
}
|
|
6567
|
+
function compareThreads(thread1, thread2) {
|
|
6568
|
+
if (thread1.updatedAt && thread2.updatedAt) {
|
|
6569
|
+
return thread1.updatedAt > thread2.updatedAt ? 1 : thread1.updatedAt < thread2.updatedAt ? -1 : 0;
|
|
6570
|
+
} else if (thread1.updatedAt || thread2.updatedAt) {
|
|
6571
|
+
return thread1.updatedAt ? 1 : -1;
|
|
6572
|
+
}
|
|
6573
|
+
if (thread1.createdAt > thread2.createdAt) {
|
|
6574
|
+
return 1;
|
|
6575
|
+
} else if (thread1.createdAt < thread2.createdAt) {
|
|
6576
|
+
return -1;
|
|
6577
|
+
}
|
|
6578
|
+
return 0;
|
|
6579
|
+
}
|
|
6580
|
+
function applyOptimisticUpdates(state) {
|
|
6581
|
+
const result = {
|
|
6582
|
+
threads: {
|
|
6583
|
+
...state.threads
|
|
6584
|
+
},
|
|
6585
|
+
inboxNotifications: {
|
|
6586
|
+
...state.inboxNotifications
|
|
6587
|
+
},
|
|
6588
|
+
notificationSettings: {
|
|
6589
|
+
...state.notificationSettings
|
|
6590
|
+
}
|
|
6591
|
+
};
|
|
6592
|
+
for (const optimisticUpdate of state.optimisticUpdates) {
|
|
6593
|
+
switch (optimisticUpdate.type) {
|
|
6594
|
+
case "create-thread": {
|
|
6595
|
+
result.threads[optimisticUpdate.thread.id] = optimisticUpdate.thread;
|
|
6596
|
+
break;
|
|
6597
|
+
}
|
|
6598
|
+
case "edit-thread-metadata": {
|
|
6599
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6600
|
+
if (thread === void 0) {
|
|
6601
|
+
break;
|
|
6602
|
+
}
|
|
6603
|
+
result.threads[thread.id] = {
|
|
6604
|
+
...thread,
|
|
6605
|
+
metadata: {
|
|
6606
|
+
...thread.metadata,
|
|
6607
|
+
...optimisticUpdate.metadata
|
|
6608
|
+
}
|
|
6609
|
+
};
|
|
6610
|
+
break;
|
|
6611
|
+
}
|
|
6612
|
+
case "create-comment": {
|
|
6613
|
+
const thread = result.threads[optimisticUpdate.comment.threadId];
|
|
6614
|
+
if (thread === void 0) {
|
|
6615
|
+
break;
|
|
6616
|
+
}
|
|
6617
|
+
result.threads[thread.id] = {
|
|
6618
|
+
...thread,
|
|
6619
|
+
comments: [...thread.comments, optimisticUpdate.comment]
|
|
6620
|
+
// TODO: Handle replace comment
|
|
6621
|
+
};
|
|
6622
|
+
if (!optimisticUpdate.inboxNotificationId) {
|
|
6623
|
+
break;
|
|
6624
|
+
}
|
|
6625
|
+
const inboxNotification = result.inboxNotifications[optimisticUpdate.inboxNotificationId];
|
|
6626
|
+
result.inboxNotifications[optimisticUpdate.inboxNotificationId] = {
|
|
6627
|
+
...inboxNotification,
|
|
6628
|
+
notifiedAt: optimisticUpdate.comment.createdAt,
|
|
6629
|
+
readAt: optimisticUpdate.comment.createdAt
|
|
6630
|
+
};
|
|
6631
|
+
break;
|
|
6632
|
+
}
|
|
6633
|
+
case "edit-comment": {
|
|
6634
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6635
|
+
if (thread === void 0) {
|
|
6636
|
+
break;
|
|
6637
|
+
}
|
|
6638
|
+
result.threads[thread.id] = {
|
|
6639
|
+
...thread,
|
|
6640
|
+
comments: thread.comments.map(
|
|
6641
|
+
(comment) => comment.id === optimisticUpdate.commentId ? {
|
|
6642
|
+
...comment,
|
|
6643
|
+
editedAt: optimisticUpdate.editedAt,
|
|
6644
|
+
body: optimisticUpdate.body
|
|
6645
|
+
} : comment
|
|
6646
|
+
)
|
|
6647
|
+
};
|
|
6648
|
+
break;
|
|
6649
|
+
}
|
|
6650
|
+
case "delete-comment": {
|
|
6651
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6652
|
+
if (thread === void 0) {
|
|
6653
|
+
break;
|
|
6654
|
+
}
|
|
6655
|
+
result.threads[thread.id] = {
|
|
6656
|
+
...thread,
|
|
6657
|
+
comments: thread.comments.map(
|
|
6658
|
+
(comment) => comment.id === optimisticUpdate.commentId ? {
|
|
6659
|
+
...comment,
|
|
6660
|
+
deletedAt: optimisticUpdate.deletedAt,
|
|
6661
|
+
body: void 0
|
|
6662
|
+
} : comment
|
|
6663
|
+
)
|
|
6664
|
+
};
|
|
6665
|
+
if (!result.threads[thread.id].comments.some(
|
|
6666
|
+
(comment) => comment.deletedAt === void 0
|
|
6667
|
+
)) {
|
|
6668
|
+
delete result.threads[thread.id];
|
|
6669
|
+
}
|
|
6670
|
+
break;
|
|
6671
|
+
}
|
|
6672
|
+
case "add-reaction": {
|
|
6673
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6674
|
+
if (thread === void 0) {
|
|
6675
|
+
break;
|
|
6676
|
+
}
|
|
6677
|
+
result.threads[thread.id] = {
|
|
6678
|
+
...thread,
|
|
6679
|
+
comments: thread.comments.map((comment) => {
|
|
6680
|
+
if (comment.id === optimisticUpdate.commentId) {
|
|
6681
|
+
if (comment.reactions.some(
|
|
6682
|
+
(reaction) => reaction.emoji === optimisticUpdate.emoji
|
|
6683
|
+
)) {
|
|
6684
|
+
return {
|
|
6685
|
+
...comment,
|
|
6686
|
+
reactions: comment.reactions.map(
|
|
6687
|
+
(reaction) => reaction.emoji === optimisticUpdate.emoji ? {
|
|
6688
|
+
...reaction,
|
|
6689
|
+
users: [
|
|
6690
|
+
...reaction.users,
|
|
6691
|
+
{ id: optimisticUpdate.userId }
|
|
6692
|
+
]
|
|
6693
|
+
} : reaction
|
|
6694
|
+
)
|
|
6695
|
+
};
|
|
6696
|
+
} else {
|
|
6697
|
+
return {
|
|
6698
|
+
...comment,
|
|
6699
|
+
reactions: [
|
|
6700
|
+
...comment.reactions,
|
|
6701
|
+
{
|
|
6702
|
+
emoji: optimisticUpdate.emoji,
|
|
6703
|
+
createdAt: optimisticUpdate.createdAt,
|
|
6704
|
+
users: [{ id: optimisticUpdate.userId }]
|
|
6705
|
+
}
|
|
6706
|
+
]
|
|
6707
|
+
};
|
|
6708
|
+
}
|
|
6709
|
+
} else {
|
|
6710
|
+
return comment;
|
|
6711
|
+
}
|
|
6712
|
+
})
|
|
6713
|
+
};
|
|
6714
|
+
break;
|
|
6715
|
+
}
|
|
6716
|
+
case "remove-reaction": {
|
|
6717
|
+
const thread = result.threads[optimisticUpdate.threadId];
|
|
6718
|
+
if (thread === void 0) {
|
|
6719
|
+
break;
|
|
6720
|
+
}
|
|
6721
|
+
result.threads[thread.id] = {
|
|
6722
|
+
...thread,
|
|
6723
|
+
comments: thread.comments.map((comment) => {
|
|
6724
|
+
if (comment.id !== optimisticUpdate.commentId) {
|
|
6725
|
+
return comment;
|
|
6726
|
+
}
|
|
6727
|
+
const reactionIndex = comment.reactions.findIndex(
|
|
6728
|
+
(reaction) => reaction.emoji === optimisticUpdate.emoji
|
|
6729
|
+
);
|
|
6730
|
+
let reactions = comment.reactions;
|
|
6731
|
+
if (reactionIndex >= 0 && comment.reactions[reactionIndex].users.some(
|
|
6732
|
+
(user) => user.id === optimisticUpdate.userId
|
|
6733
|
+
)) {
|
|
6734
|
+
if (comment.reactions[reactionIndex].users.length <= 1) {
|
|
6735
|
+
reactions = [...comment.reactions];
|
|
6736
|
+
reactions.splice(reactionIndex, 1);
|
|
6737
|
+
} else {
|
|
6738
|
+
reactions[reactionIndex] = {
|
|
6739
|
+
...reactions[reactionIndex],
|
|
6740
|
+
users: reactions[reactionIndex].users.filter(
|
|
6741
|
+
(user) => user.id !== optimisticUpdate.userId
|
|
6742
|
+
)
|
|
6743
|
+
};
|
|
6744
|
+
}
|
|
6745
|
+
}
|
|
6746
|
+
return {
|
|
6747
|
+
...comment,
|
|
6748
|
+
reactions
|
|
6749
|
+
};
|
|
6750
|
+
})
|
|
6751
|
+
};
|
|
6752
|
+
break;
|
|
6753
|
+
}
|
|
6754
|
+
case "mark-inbox-notification-as-read": {
|
|
6755
|
+
result.inboxNotifications[optimisticUpdate.inboxNotificationId] = {
|
|
6756
|
+
...state.inboxNotifications[optimisticUpdate.inboxNotificationId],
|
|
6757
|
+
readAt: optimisticUpdate.readAt
|
|
6758
|
+
};
|
|
6759
|
+
break;
|
|
6760
|
+
}
|
|
6761
|
+
case "mark-inbox-notifications-as-read": {
|
|
6762
|
+
for (const id in result.inboxNotifications) {
|
|
6763
|
+
result.inboxNotifications[id] = {
|
|
6764
|
+
...result.inboxNotifications[id],
|
|
6765
|
+
readAt: optimisticUpdate.readAt
|
|
6766
|
+
};
|
|
6767
|
+
}
|
|
6768
|
+
break;
|
|
6769
|
+
}
|
|
6770
|
+
case "update-notification-settings": {
|
|
6771
|
+
result.notificationSettings[optimisticUpdate.roomId] = {
|
|
6772
|
+
...result.notificationSettings[optimisticUpdate.roomId],
|
|
6773
|
+
...optimisticUpdate.settings
|
|
6774
|
+
};
|
|
6775
|
+
}
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
return result;
|
|
6779
|
+
}
|
|
6780
|
+
|
|
6403
6781
|
// src/client.ts
|
|
6404
6782
|
var MIN_THROTTLE = 16;
|
|
6405
6783
|
var MAX_THROTTLE = 1e3;
|
|
@@ -6409,6 +6787,8 @@ var MIN_LOST_CONNECTION_TIMEOUT = 200;
|
|
|
6409
6787
|
var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
|
|
6410
6788
|
var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
|
|
6411
6789
|
var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
|
|
6790
|
+
var RESOLVE_USERS_BATCH_DELAY = 50;
|
|
6791
|
+
var RESOLVE_ROOMS_INFO_BATCH_DELAY = 50;
|
|
6412
6792
|
function getBaseUrlFromClientOptions(clientOptions) {
|
|
6413
6793
|
if ("liveblocksServer" in clientOptions) {
|
|
6414
6794
|
throw new Error("Client option no longer supported");
|
|
@@ -6419,6 +6799,13 @@ function getBaseUrlFromClientOptions(clientOptions) {
|
|
|
6419
6799
|
return DEFAULT_BASE_URL;
|
|
6420
6800
|
}
|
|
6421
6801
|
}
|
|
6802
|
+
function getAuthBearerHeaderFromAuthValue(authValue) {
|
|
6803
|
+
if (authValue.type === "public") {
|
|
6804
|
+
return authValue.publicApiKey;
|
|
6805
|
+
} else {
|
|
6806
|
+
return authValue.token.raw;
|
|
6807
|
+
}
|
|
6808
|
+
}
|
|
6422
6809
|
function createClient(options) {
|
|
6423
6810
|
const clientOptions = options;
|
|
6424
6811
|
const throttleDelay = getThrottle(clientOptions.throttle ?? DEFAULT_THROTTLE);
|
|
@@ -6428,6 +6815,7 @@ function createClient(options) {
|
|
|
6428
6815
|
const backgroundKeepAliveTimeout = getBackgroundKeepAliveTimeout(
|
|
6429
6816
|
clientOptions.backgroundKeepAliveTimeout
|
|
6430
6817
|
);
|
|
6818
|
+
const baseUrl = getBaseUrlFromClientOptions(clientOptions);
|
|
6431
6819
|
const authManager = createAuthManager(options);
|
|
6432
6820
|
const roomsById = /* @__PURE__ */ new Map();
|
|
6433
6821
|
function teardownRoom(room) {
|
|
@@ -6463,7 +6851,6 @@ function createClient(options) {
|
|
|
6463
6851
|
options2.initialPresence === null || options2.initialPresence === void 0,
|
|
6464
6852
|
"Please provide an initial presence value for the current user when entering the room."
|
|
6465
6853
|
);
|
|
6466
|
-
const baseUrl = getBaseUrlFromClientOptions(clientOptions);
|
|
6467
6854
|
const newRoom = createRoom(
|
|
6468
6855
|
{
|
|
6469
6856
|
initialPresence: options2.initialPresence ?? {},
|
|
@@ -6519,58 +6906,450 @@ function createClient(options) {
|
|
|
6519
6906
|
const room = roomsById.get(roomId)?.room;
|
|
6520
6907
|
return room ? room : null;
|
|
6521
6908
|
}
|
|
6522
|
-
function forceLeave(roomId) {
|
|
6523
|
-
const unsubs = roomsById.get(roomId)?.unsubs ?? /* @__PURE__ */ new Set();
|
|
6524
|
-
for (const unsub of unsubs) {
|
|
6525
|
-
unsub();
|
|
6909
|
+
function forceLeave(roomId) {
|
|
6910
|
+
const unsubs = roomsById.get(roomId)?.unsubs ?? /* @__PURE__ */ new Set();
|
|
6911
|
+
for (const unsub of unsubs) {
|
|
6912
|
+
unsub();
|
|
6913
|
+
}
|
|
6914
|
+
}
|
|
6915
|
+
function logout() {
|
|
6916
|
+
authManager.reset();
|
|
6917
|
+
for (const { room } of roomsById.values()) {
|
|
6918
|
+
if (!isIdle(room.getStatus())) {
|
|
6919
|
+
room.reconnect();
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
const currentUserIdStore = createStore(null);
|
|
6924
|
+
const {
|
|
6925
|
+
getInboxNotifications,
|
|
6926
|
+
getUnreadInboxNotificationsCount,
|
|
6927
|
+
markAllInboxNotificationsAsRead,
|
|
6928
|
+
markInboxNotificationAsRead
|
|
6929
|
+
} = createInboxNotificationsApi({
|
|
6930
|
+
baseUrl,
|
|
6931
|
+
fetcher: clientOptions.polyfills?.fetch || /* istanbul ignore next */
|
|
6932
|
+
fetch,
|
|
6933
|
+
authManager,
|
|
6934
|
+
currentUserIdStore
|
|
6935
|
+
});
|
|
6936
|
+
const cacheStore = createClientStore();
|
|
6937
|
+
const resolveUsers = clientOptions.resolveUsers;
|
|
6938
|
+
const warnIfNoResolveUsers = createDevelopmentWarning(
|
|
6939
|
+
() => !resolveUsers,
|
|
6940
|
+
"Set the resolveUsers option in createClient to specify user info."
|
|
6941
|
+
);
|
|
6942
|
+
const usersStore = createBatchStore(
|
|
6943
|
+
async (batchedUserIds) => {
|
|
6944
|
+
const userIds = batchedUserIds.flat();
|
|
6945
|
+
const users = await resolveUsers?.({ userIds });
|
|
6946
|
+
warnIfNoResolveUsers();
|
|
6947
|
+
return users ?? userIds.map(() => void 0);
|
|
6948
|
+
},
|
|
6949
|
+
{ delay: RESOLVE_USERS_BATCH_DELAY }
|
|
6950
|
+
);
|
|
6951
|
+
const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
|
|
6952
|
+
const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
|
|
6953
|
+
() => !resolveRoomsInfo,
|
|
6954
|
+
"Set the resolveRoomsInfo option in createClient to specify room info."
|
|
6955
|
+
);
|
|
6956
|
+
const roomsInfoStore = createBatchStore(
|
|
6957
|
+
async (batchedRoomIds) => {
|
|
6958
|
+
const roomIds = batchedRoomIds.flat();
|
|
6959
|
+
const roomsInfo = await resolveRoomsInfo?.({ roomIds });
|
|
6960
|
+
warnIfNoResolveRoomsInfo();
|
|
6961
|
+
return roomsInfo ?? roomIds.map(() => void 0);
|
|
6962
|
+
},
|
|
6963
|
+
{ delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
|
|
6964
|
+
);
|
|
6965
|
+
return Object.defineProperty(
|
|
6966
|
+
{
|
|
6967
|
+
logout,
|
|
6968
|
+
// Old, deprecated APIs
|
|
6969
|
+
enter,
|
|
6970
|
+
getRoom,
|
|
6971
|
+
leave: forceLeave,
|
|
6972
|
+
// New, preferred API
|
|
6973
|
+
enterRoom,
|
|
6974
|
+
// Notifications API
|
|
6975
|
+
getInboxNotifications,
|
|
6976
|
+
getUnreadInboxNotificationsCount,
|
|
6977
|
+
markAllInboxNotificationsAsRead,
|
|
6978
|
+
markInboxNotificationAsRead,
|
|
6979
|
+
// Internal
|
|
6980
|
+
[kInternal]: {
|
|
6981
|
+
currentUserIdStore,
|
|
6982
|
+
resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
|
|
6983
|
+
cacheStore,
|
|
6984
|
+
usersStore,
|
|
6985
|
+
roomsInfoStore
|
|
6986
|
+
}
|
|
6987
|
+
},
|
|
6988
|
+
kInternal,
|
|
6989
|
+
{
|
|
6990
|
+
enumerable: false
|
|
6991
|
+
}
|
|
6992
|
+
);
|
|
6993
|
+
}
|
|
6994
|
+
var NotificationsApiError = class extends Error {
|
|
6995
|
+
constructor(message, status, details) {
|
|
6996
|
+
super(message);
|
|
6997
|
+
this.message = message;
|
|
6998
|
+
this.status = status;
|
|
6999
|
+
this.details = details;
|
|
7000
|
+
}
|
|
7001
|
+
};
|
|
7002
|
+
function checkBounds(option, value, min, max, recommendedMin) {
|
|
7003
|
+
if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
|
|
7004
|
+
throw new Error(
|
|
7005
|
+
max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
|
|
7006
|
+
);
|
|
7007
|
+
}
|
|
7008
|
+
return value;
|
|
7009
|
+
}
|
|
7010
|
+
function getBackgroundKeepAliveTimeout(value) {
|
|
7011
|
+
if (value === void 0)
|
|
7012
|
+
return void 0;
|
|
7013
|
+
return checkBounds(
|
|
7014
|
+
"backgroundKeepAliveTimeout",
|
|
7015
|
+
value,
|
|
7016
|
+
MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
|
|
7017
|
+
);
|
|
7018
|
+
}
|
|
7019
|
+
function getThrottle(value) {
|
|
7020
|
+
return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
|
|
7021
|
+
}
|
|
7022
|
+
function getLostConnectionTimeout(value) {
|
|
7023
|
+
return checkBounds(
|
|
7024
|
+
"lostConnectionTimeout",
|
|
7025
|
+
value,
|
|
7026
|
+
MIN_LOST_CONNECTION_TIMEOUT,
|
|
7027
|
+
MAX_LOST_CONNECTION_TIMEOUT,
|
|
7028
|
+
RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
|
|
7029
|
+
);
|
|
7030
|
+
}
|
|
7031
|
+
function createDevelopmentWarning(condition, ...args) {
|
|
7032
|
+
let hasWarned = false;
|
|
7033
|
+
if (process.env.NODE_ENV !== "production") {
|
|
7034
|
+
return () => {
|
|
7035
|
+
if (!hasWarned && (typeof condition === "function" ? condition() : condition)) {
|
|
7036
|
+
warn(...args);
|
|
7037
|
+
hasWarned = true;
|
|
7038
|
+
}
|
|
7039
|
+
};
|
|
7040
|
+
} else {
|
|
7041
|
+
return () => {
|
|
7042
|
+
};
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
7045
|
+
|
|
7046
|
+
// src/comments/comment-body.ts
|
|
7047
|
+
function isCommentBodyParagraph(element) {
|
|
7048
|
+
return "type" in element && element.type === "mention";
|
|
7049
|
+
}
|
|
7050
|
+
function isCommentBodyText(element) {
|
|
7051
|
+
return "text" in element && typeof element.text === "string";
|
|
7052
|
+
}
|
|
7053
|
+
function isCommentBodyMention(element) {
|
|
7054
|
+
return "type" in element && element.type === "mention";
|
|
7055
|
+
}
|
|
7056
|
+
function isCommentBodyLink(element) {
|
|
7057
|
+
return "type" in element && element.type === "link";
|
|
7058
|
+
}
|
|
7059
|
+
var commentBodyElementsGuards = {
|
|
7060
|
+
paragraph: isCommentBodyParagraph,
|
|
7061
|
+
text: isCommentBodyText,
|
|
7062
|
+
link: isCommentBodyLink,
|
|
7063
|
+
mention: isCommentBodyMention
|
|
7064
|
+
};
|
|
7065
|
+
var commentBodyElementsTypes = {
|
|
7066
|
+
paragraph: "block",
|
|
7067
|
+
text: "inline",
|
|
7068
|
+
link: "inline",
|
|
7069
|
+
mention: "inline"
|
|
7070
|
+
};
|
|
7071
|
+
function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
|
|
7072
|
+
if (!body || !body?.content) {
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
7075
|
+
const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
|
|
7076
|
+
const type = element ? commentBodyElementsTypes[element] : "all";
|
|
7077
|
+
const guard = element ? commentBodyElementsGuards[element] : () => true;
|
|
7078
|
+
const visitor = typeof elementOrVisitor === "function" ? elementOrVisitor : possiblyVisitor;
|
|
7079
|
+
for (const block of body.content) {
|
|
7080
|
+
if (type === "all" || type === "block") {
|
|
7081
|
+
if (guard(block)) {
|
|
7082
|
+
visitor?.(block);
|
|
7083
|
+
}
|
|
7084
|
+
}
|
|
7085
|
+
if (type === "all" || type === "inline") {
|
|
7086
|
+
for (const inline of block.children) {
|
|
7087
|
+
if (guard(inline)) {
|
|
7088
|
+
visitor?.(inline);
|
|
7089
|
+
}
|
|
7090
|
+
}
|
|
7091
|
+
}
|
|
7092
|
+
}
|
|
7093
|
+
}
|
|
7094
|
+
function getMentionedIdsFromCommentBody(body) {
|
|
7095
|
+
const mentionedIds = /* @__PURE__ */ new Set();
|
|
7096
|
+
traverseCommentBody(
|
|
7097
|
+
body,
|
|
7098
|
+
"mention",
|
|
7099
|
+
(mention) => mentionedIds.add(mention.id)
|
|
7100
|
+
);
|
|
7101
|
+
return Array.from(mentionedIds);
|
|
7102
|
+
}
|
|
7103
|
+
async function resolveUsersInCommentBody(body, resolveUsers) {
|
|
7104
|
+
const resolvedUsers = /* @__PURE__ */ new Map();
|
|
7105
|
+
if (!resolveUsers) {
|
|
7106
|
+
return resolvedUsers;
|
|
7107
|
+
}
|
|
7108
|
+
const userIds = getMentionedIdsFromCommentBody(body);
|
|
7109
|
+
const users = await resolveUsers({
|
|
7110
|
+
userIds
|
|
7111
|
+
});
|
|
7112
|
+
for (const [index, userId] of userIds.entries()) {
|
|
7113
|
+
const user = users?.[index];
|
|
7114
|
+
if (user) {
|
|
7115
|
+
resolvedUsers.set(userId, user);
|
|
7116
|
+
}
|
|
7117
|
+
}
|
|
7118
|
+
return resolvedUsers;
|
|
7119
|
+
}
|
|
7120
|
+
var htmlEscapables = {
|
|
7121
|
+
"&": "&",
|
|
7122
|
+
"<": "<",
|
|
7123
|
+
">": ">",
|
|
7124
|
+
'"': """,
|
|
7125
|
+
"'": "'"
|
|
7126
|
+
};
|
|
7127
|
+
var htmlEscapablesRegex = new RegExp(
|
|
7128
|
+
Object.keys(htmlEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
7129
|
+
"g"
|
|
7130
|
+
);
|
|
7131
|
+
function htmlSafe(value) {
|
|
7132
|
+
return new HtmlSafeString([String(value)], []);
|
|
7133
|
+
}
|
|
7134
|
+
function joinHtml(strings) {
|
|
7135
|
+
if (strings.length <= 0) {
|
|
7136
|
+
return new HtmlSafeString([""], []);
|
|
7137
|
+
}
|
|
7138
|
+
return new HtmlSafeString(
|
|
7139
|
+
["", ...Array(strings.length - 1).fill(""), ""],
|
|
7140
|
+
strings
|
|
7141
|
+
);
|
|
7142
|
+
}
|
|
7143
|
+
function escapeHtml(value) {
|
|
7144
|
+
if (value instanceof HtmlSafeString) {
|
|
7145
|
+
return value.toString();
|
|
7146
|
+
}
|
|
7147
|
+
if (Array.isArray(value)) {
|
|
7148
|
+
return joinHtml(value).toString();
|
|
7149
|
+
}
|
|
7150
|
+
return String(value).replace(
|
|
7151
|
+
htmlEscapablesRegex,
|
|
7152
|
+
(character) => htmlEscapables[character]
|
|
7153
|
+
);
|
|
7154
|
+
}
|
|
7155
|
+
var HtmlSafeString = class {
|
|
7156
|
+
constructor(strings, values) {
|
|
7157
|
+
this._strings = strings;
|
|
7158
|
+
this._values = values;
|
|
7159
|
+
}
|
|
7160
|
+
toString() {
|
|
7161
|
+
return this._strings.reduce((result, str, i) => {
|
|
7162
|
+
return result + escapeHtml(nn(this._values[i - 1])) + str;
|
|
7163
|
+
});
|
|
7164
|
+
}
|
|
7165
|
+
};
|
|
7166
|
+
function html(strings, ...values) {
|
|
7167
|
+
return new HtmlSafeString(strings, values);
|
|
7168
|
+
}
|
|
7169
|
+
var markdownEscapables = {
|
|
7170
|
+
_: "\\_",
|
|
7171
|
+
"*": "\\*",
|
|
7172
|
+
"#": "\\#",
|
|
7173
|
+
"`": "\\`",
|
|
7174
|
+
"~": "\\~",
|
|
7175
|
+
"!": "\\!",
|
|
7176
|
+
"|": "\\|",
|
|
7177
|
+
"(": "\\(",
|
|
7178
|
+
")": "\\)",
|
|
7179
|
+
"{": "\\{",
|
|
7180
|
+
"}": "\\}",
|
|
7181
|
+
"[": "\\[",
|
|
7182
|
+
"]": "\\]"
|
|
7183
|
+
};
|
|
7184
|
+
var markdownEscapablesRegex = new RegExp(
|
|
7185
|
+
Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
|
|
7186
|
+
"g"
|
|
7187
|
+
);
|
|
7188
|
+
function joinMarkdown(strings) {
|
|
7189
|
+
if (strings.length <= 0) {
|
|
7190
|
+
return new MarkdownSafeString([""], []);
|
|
7191
|
+
}
|
|
7192
|
+
return new MarkdownSafeString(
|
|
7193
|
+
["", ...Array(strings.length - 1).fill(""), ""],
|
|
7194
|
+
strings
|
|
7195
|
+
);
|
|
7196
|
+
}
|
|
7197
|
+
function escapeMarkdown(value) {
|
|
7198
|
+
if (value instanceof MarkdownSafeString) {
|
|
7199
|
+
return value.toString();
|
|
7200
|
+
}
|
|
7201
|
+
if (Array.isArray(value)) {
|
|
7202
|
+
return joinMarkdown(value).toString();
|
|
7203
|
+
}
|
|
7204
|
+
return String(value).replace(
|
|
7205
|
+
markdownEscapablesRegex,
|
|
7206
|
+
(character) => markdownEscapables[character]
|
|
7207
|
+
);
|
|
7208
|
+
}
|
|
7209
|
+
var MarkdownSafeString = class {
|
|
7210
|
+
constructor(strings, values) {
|
|
7211
|
+
this._strings = strings;
|
|
7212
|
+
this._values = values;
|
|
7213
|
+
}
|
|
7214
|
+
toString() {
|
|
7215
|
+
return this._strings.reduce((result, str, i) => {
|
|
7216
|
+
return result + escapeMarkdown(nn(this._values[i - 1])) + str;
|
|
7217
|
+
});
|
|
7218
|
+
}
|
|
7219
|
+
};
|
|
7220
|
+
function markdown(strings, ...values) {
|
|
7221
|
+
return new MarkdownSafeString(strings, values);
|
|
7222
|
+
}
|
|
7223
|
+
function toAbsoluteUrl(url) {
|
|
7224
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
7225
|
+
return url;
|
|
7226
|
+
} else if (url.startsWith("www.")) {
|
|
7227
|
+
return "https://" + url;
|
|
7228
|
+
}
|
|
7229
|
+
return;
|
|
7230
|
+
}
|
|
7231
|
+
var stringifyCommentBodyPlainElements = {
|
|
7232
|
+
paragraph: ({ children }) => children,
|
|
7233
|
+
text: ({ element }) => element.text,
|
|
7234
|
+
link: ({ element }) => element.url,
|
|
7235
|
+
mention: ({ element, user }) => {
|
|
7236
|
+
return `@${user?.name ?? element.id}`;
|
|
7237
|
+
}
|
|
7238
|
+
};
|
|
7239
|
+
var stringifyCommentBodyHtmlElements = {
|
|
7240
|
+
paragraph: ({ children }) => {
|
|
7241
|
+
return children ? html`<p>${htmlSafe(children)}</p>` : children;
|
|
7242
|
+
},
|
|
7243
|
+
text: ({ element }) => {
|
|
7244
|
+
let children = element.text;
|
|
7245
|
+
if (!children) {
|
|
7246
|
+
return children;
|
|
7247
|
+
}
|
|
7248
|
+
if (element.bold) {
|
|
7249
|
+
children = html`<strong>${children}</strong>`;
|
|
7250
|
+
}
|
|
7251
|
+
if (element.italic) {
|
|
7252
|
+
children = html`<em>${children}</em>`;
|
|
7253
|
+
}
|
|
7254
|
+
if (element.strikethrough) {
|
|
7255
|
+
children = html`<s>${children}</s>`;
|
|
7256
|
+
}
|
|
7257
|
+
if (element.code) {
|
|
7258
|
+
children = html`<code>${children}</code>`;
|
|
7259
|
+
}
|
|
7260
|
+
return children;
|
|
7261
|
+
},
|
|
7262
|
+
link: ({ element, href }) => {
|
|
7263
|
+
return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
|
|
7264
|
+
},
|
|
7265
|
+
mention: ({ element, user }) => {
|
|
7266
|
+
return html`<span data-mention>@${user?.name ?? element.id}</span>`;
|
|
7267
|
+
}
|
|
7268
|
+
};
|
|
7269
|
+
var stringifyCommentBodyMarkdownElements = {
|
|
7270
|
+
paragraph: ({ children }) => {
|
|
7271
|
+
return children;
|
|
7272
|
+
},
|
|
7273
|
+
text: ({ element }) => {
|
|
7274
|
+
let children = element.text;
|
|
7275
|
+
if (!children) {
|
|
7276
|
+
return children;
|
|
6526
7277
|
}
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
7278
|
+
if (element.bold) {
|
|
7279
|
+
children = markdown`**${children}**`;
|
|
7280
|
+
}
|
|
7281
|
+
if (element.italic) {
|
|
7282
|
+
children = markdown`_${children}_`;
|
|
7283
|
+
}
|
|
7284
|
+
if (element.strikethrough) {
|
|
7285
|
+
children = markdown`~~${children}~~`;
|
|
6534
7286
|
}
|
|
7287
|
+
if (element.code) {
|
|
7288
|
+
children = markdown`\`${children}\``;
|
|
7289
|
+
}
|
|
7290
|
+
return children;
|
|
7291
|
+
},
|
|
7292
|
+
link: ({ element, href }) => {
|
|
7293
|
+
return markdown`[${element.url}](${href})`;
|
|
7294
|
+
},
|
|
7295
|
+
mention: ({ element, user }) => {
|
|
7296
|
+
return markdown`@${user?.name ?? element.id}`;
|
|
6535
7297
|
}
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
enterRoom
|
|
7298
|
+
};
|
|
7299
|
+
async function stringifyCommentBody(body, options) {
|
|
7300
|
+
const format = options?.format ?? "plain";
|
|
7301
|
+
const separator = options?.separator ?? (format === "markdown" ? "\n\n" : "\n");
|
|
7302
|
+
const elements = {
|
|
7303
|
+
...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
|
|
7304
|
+
...options?.elements
|
|
6544
7305
|
};
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
throw new Error(
|
|
6549
|
-
max !== void 0 ? `${option} should be between ${recommendedMin ?? min} and ${max}.` : `${option} should be at least ${recommendedMin ?? min}.`
|
|
6550
|
-
);
|
|
6551
|
-
}
|
|
6552
|
-
return value;
|
|
6553
|
-
}
|
|
6554
|
-
function getBackgroundKeepAliveTimeout(value) {
|
|
6555
|
-
if (value === void 0)
|
|
6556
|
-
return void 0;
|
|
6557
|
-
return checkBounds(
|
|
6558
|
-
"backgroundKeepAliveTimeout",
|
|
6559
|
-
value,
|
|
6560
|
-
MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
|
|
6561
|
-
);
|
|
6562
|
-
}
|
|
6563
|
-
function getThrottle(value) {
|
|
6564
|
-
return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
|
|
6565
|
-
}
|
|
6566
|
-
function getLostConnectionTimeout(value) {
|
|
6567
|
-
return checkBounds(
|
|
6568
|
-
"lostConnectionTimeout",
|
|
6569
|
-
value,
|
|
6570
|
-
MIN_LOST_CONNECTION_TIMEOUT,
|
|
6571
|
-
MAX_LOST_CONNECTION_TIMEOUT,
|
|
6572
|
-
RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
|
|
7306
|
+
const resolvedUsers = await resolveUsersInCommentBody(
|
|
7307
|
+
body,
|
|
7308
|
+
options?.resolveUsers
|
|
6573
7309
|
);
|
|
7310
|
+
const blocks = body.content.flatMap((block, blockIndex) => {
|
|
7311
|
+
switch (block.type) {
|
|
7312
|
+
case "paragraph": {
|
|
7313
|
+
const inlines = block.children.flatMap((inline, inlineIndex) => {
|
|
7314
|
+
if (isCommentBodyMention(inline)) {
|
|
7315
|
+
return inline.id ? [
|
|
7316
|
+
elements.mention(
|
|
7317
|
+
{
|
|
7318
|
+
element: inline,
|
|
7319
|
+
user: resolvedUsers.get(inline.id)
|
|
7320
|
+
},
|
|
7321
|
+
inlineIndex
|
|
7322
|
+
)
|
|
7323
|
+
] : [];
|
|
7324
|
+
}
|
|
7325
|
+
if (isCommentBodyLink(inline)) {
|
|
7326
|
+
return [
|
|
7327
|
+
elements.link(
|
|
7328
|
+
{
|
|
7329
|
+
element: inline,
|
|
7330
|
+
href: toAbsoluteUrl(inline.url) ?? inline.url
|
|
7331
|
+
},
|
|
7332
|
+
inlineIndex
|
|
7333
|
+
)
|
|
7334
|
+
];
|
|
7335
|
+
}
|
|
7336
|
+
if (isCommentBodyText(inline)) {
|
|
7337
|
+
return [elements.text({ element: inline }, inlineIndex)];
|
|
7338
|
+
}
|
|
7339
|
+
return [];
|
|
7340
|
+
});
|
|
7341
|
+
return [
|
|
7342
|
+
elements.paragraph(
|
|
7343
|
+
{ element: block, children: inlines.join("") },
|
|
7344
|
+
blockIndex
|
|
7345
|
+
)
|
|
7346
|
+
];
|
|
7347
|
+
}
|
|
7348
|
+
default:
|
|
7349
|
+
return [];
|
|
7350
|
+
}
|
|
7351
|
+
});
|
|
7352
|
+
return blocks.join(separator);
|
|
6574
7353
|
}
|
|
6575
7354
|
|
|
6576
7355
|
// src/crdts/utils.ts
|
|
@@ -6904,161 +7683,6 @@ function legacy_patchImmutableNode(state, path, update) {
|
|
|
6904
7683
|
}
|
|
6905
7684
|
}
|
|
6906
7685
|
|
|
6907
|
-
// src/lib/shallow.ts
|
|
6908
|
-
function shallowArray(xs, ys) {
|
|
6909
|
-
if (xs.length !== ys.length) {
|
|
6910
|
-
return false;
|
|
6911
|
-
}
|
|
6912
|
-
for (let i = 0; i < xs.length; i++) {
|
|
6913
|
-
if (!Object.is(xs[i], ys[i])) {
|
|
6914
|
-
return false;
|
|
6915
|
-
}
|
|
6916
|
-
}
|
|
6917
|
-
return true;
|
|
6918
|
-
}
|
|
6919
|
-
function shallowObj(objA, objB) {
|
|
6920
|
-
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]") {
|
|
6921
|
-
return false;
|
|
6922
|
-
}
|
|
6923
|
-
const keysA = Object.keys(objA);
|
|
6924
|
-
if (keysA.length !== Object.keys(objB).length) {
|
|
6925
|
-
return false;
|
|
6926
|
-
}
|
|
6927
|
-
return keysA.every(
|
|
6928
|
-
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
6929
|
-
);
|
|
6930
|
-
}
|
|
6931
|
-
function shallow(a, b) {
|
|
6932
|
-
if (Object.is(a, b)) {
|
|
6933
|
-
return true;
|
|
6934
|
-
}
|
|
6935
|
-
const isArrayA = Array.isArray(a);
|
|
6936
|
-
const isArrayB = Array.isArray(b);
|
|
6937
|
-
if (isArrayA || isArrayB) {
|
|
6938
|
-
if (!isArrayA || !isArrayB) {
|
|
6939
|
-
return false;
|
|
6940
|
-
}
|
|
6941
|
-
return shallowArray(a, b);
|
|
6942
|
-
}
|
|
6943
|
-
return shallowObj(a, b);
|
|
6944
|
-
}
|
|
6945
|
-
|
|
6946
|
-
// src/lib/AsyncCache.ts
|
|
6947
|
-
var noop = () => {
|
|
6948
|
-
};
|
|
6949
|
-
function isShallowEqual(a, b) {
|
|
6950
|
-
if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
|
|
6951
|
-
return false;
|
|
6952
|
-
} else {
|
|
6953
|
-
return shallow(a.data, b.data) && shallow(a.error, b.error);
|
|
6954
|
-
}
|
|
6955
|
-
}
|
|
6956
|
-
function createCacheItem(key, asyncFunction, options) {
|
|
6957
|
-
const $asyncFunction = async () => asyncFunction(key);
|
|
6958
|
-
const context = {
|
|
6959
|
-
isInvalid: true
|
|
6960
|
-
};
|
|
6961
|
-
let state = { isLoading: false };
|
|
6962
|
-
let previousState = { isLoading: false };
|
|
6963
|
-
const eventSource2 = makeEventSource();
|
|
6964
|
-
function notify() {
|
|
6965
|
-
const isEqual = options?.isStateEqual ?? isShallowEqual;
|
|
6966
|
-
if (!isEqual(previousState, state)) {
|
|
6967
|
-
previousState = state;
|
|
6968
|
-
eventSource2.notify(state);
|
|
6969
|
-
}
|
|
6970
|
-
}
|
|
6971
|
-
async function resolve() {
|
|
6972
|
-
if (!context.promise) {
|
|
6973
|
-
return;
|
|
6974
|
-
}
|
|
6975
|
-
try {
|
|
6976
|
-
const data = await context.promise;
|
|
6977
|
-
context.isInvalid = false;
|
|
6978
|
-
state = {
|
|
6979
|
-
isLoading: false,
|
|
6980
|
-
data
|
|
6981
|
-
};
|
|
6982
|
-
} catch (error3) {
|
|
6983
|
-
state = {
|
|
6984
|
-
isLoading: false,
|
|
6985
|
-
data: state.data,
|
|
6986
|
-
error: error3
|
|
6987
|
-
};
|
|
6988
|
-
}
|
|
6989
|
-
context.promise = void 0;
|
|
6990
|
-
notify();
|
|
6991
|
-
}
|
|
6992
|
-
async function revalidate() {
|
|
6993
|
-
context.isInvalid = true;
|
|
6994
|
-
return get();
|
|
6995
|
-
}
|
|
6996
|
-
async function get() {
|
|
6997
|
-
if (context.isInvalid) {
|
|
6998
|
-
if (!context.promise) {
|
|
6999
|
-
context.isInvalid = true;
|
|
7000
|
-
context.promise = $asyncFunction();
|
|
7001
|
-
state = { isLoading: true, data: state.data };
|
|
7002
|
-
notify();
|
|
7003
|
-
}
|
|
7004
|
-
await resolve();
|
|
7005
|
-
}
|
|
7006
|
-
return getState();
|
|
7007
|
-
}
|
|
7008
|
-
function getState() {
|
|
7009
|
-
return state;
|
|
7010
|
-
}
|
|
7011
|
-
return {
|
|
7012
|
-
...eventSource2.observable,
|
|
7013
|
-
get,
|
|
7014
|
-
getState,
|
|
7015
|
-
revalidate
|
|
7016
|
-
};
|
|
7017
|
-
}
|
|
7018
|
-
function createAsyncCache(asyncFunction, options) {
|
|
7019
|
-
const cache = /* @__PURE__ */ new Map();
|
|
7020
|
-
function create(key) {
|
|
7021
|
-
let cacheItem = cache.get(key);
|
|
7022
|
-
if (cacheItem) {
|
|
7023
|
-
return cacheItem;
|
|
7024
|
-
}
|
|
7025
|
-
cacheItem = createCacheItem(key, asyncFunction, options);
|
|
7026
|
-
cache.set(key, cacheItem);
|
|
7027
|
-
return cacheItem;
|
|
7028
|
-
}
|
|
7029
|
-
function get(key) {
|
|
7030
|
-
return create(key).get();
|
|
7031
|
-
}
|
|
7032
|
-
function getState(key) {
|
|
7033
|
-
return cache.get(key)?.getState();
|
|
7034
|
-
}
|
|
7035
|
-
function revalidate(key) {
|
|
7036
|
-
return create(key).revalidate();
|
|
7037
|
-
}
|
|
7038
|
-
function subscribe(key, callback) {
|
|
7039
|
-
return create(key).subscribe(callback) ?? noop;
|
|
7040
|
-
}
|
|
7041
|
-
function subscribeOnce(key, callback) {
|
|
7042
|
-
return create(key).subscribeOnce(callback) ?? noop;
|
|
7043
|
-
}
|
|
7044
|
-
function has(key) {
|
|
7045
|
-
return cache.has(key);
|
|
7046
|
-
}
|
|
7047
|
-
function clear() {
|
|
7048
|
-
cache.clear();
|
|
7049
|
-
}
|
|
7050
|
-
return {
|
|
7051
|
-
create,
|
|
7052
|
-
get,
|
|
7053
|
-
getState,
|
|
7054
|
-
revalidate,
|
|
7055
|
-
subscribe,
|
|
7056
|
-
subscribeOnce,
|
|
7057
|
-
has,
|
|
7058
|
-
clear
|
|
7059
|
-
};
|
|
7060
|
-
}
|
|
7061
|
-
|
|
7062
7686
|
// src/lib/Poller.ts
|
|
7063
7687
|
function makePoller(callback) {
|
|
7064
7688
|
let context = {
|
|
@@ -7148,19 +7772,43 @@ function makePoller(callback) {
|
|
|
7148
7772
|
};
|
|
7149
7773
|
}
|
|
7150
7774
|
|
|
7151
|
-
// src/lib/
|
|
7152
|
-
function
|
|
7153
|
-
if (
|
|
7154
|
-
return
|
|
7775
|
+
// src/lib/shallow.ts
|
|
7776
|
+
function shallowArray(xs, ys) {
|
|
7777
|
+
if (xs.length !== ys.length) {
|
|
7778
|
+
return false;
|
|
7155
7779
|
}
|
|
7156
|
-
|
|
7157
|
-
(
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7780
|
+
for (let i = 0; i < xs.length; i++) {
|
|
7781
|
+
if (!Object.is(xs[i], ys[i])) {
|
|
7782
|
+
return false;
|
|
7783
|
+
}
|
|
7784
|
+
}
|
|
7785
|
+
return true;
|
|
7786
|
+
}
|
|
7787
|
+
function shallowObj(objA, objB) {
|
|
7788
|
+
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]") {
|
|
7789
|
+
return false;
|
|
7790
|
+
}
|
|
7791
|
+
const keysA = Object.keys(objA);
|
|
7792
|
+
if (keysA.length !== Object.keys(objB).length) {
|
|
7793
|
+
return false;
|
|
7794
|
+
}
|
|
7795
|
+
return keysA.every(
|
|
7796
|
+
(key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
|
|
7162
7797
|
);
|
|
7163
|
-
|
|
7798
|
+
}
|
|
7799
|
+
function shallow(a, b) {
|
|
7800
|
+
if (Object.is(a, b)) {
|
|
7801
|
+
return true;
|
|
7802
|
+
}
|
|
7803
|
+
const isArrayA = Array.isArray(a);
|
|
7804
|
+
const isArrayB = Array.isArray(b);
|
|
7805
|
+
if (isArrayA || isArrayB) {
|
|
7806
|
+
if (!isArrayA || !isArrayB) {
|
|
7807
|
+
return false;
|
|
7808
|
+
}
|
|
7809
|
+
return shallowArray(a, b);
|
|
7810
|
+
}
|
|
7811
|
+
return shallowObj(a, b);
|
|
7164
7812
|
}
|
|
7165
7813
|
|
|
7166
7814
|
// src/index.ts
|
|
@@ -7172,10 +7820,12 @@ export {
|
|
|
7172
7820
|
LiveList,
|
|
7173
7821
|
LiveMap,
|
|
7174
7822
|
LiveObject,
|
|
7823
|
+
NotificationsApiError,
|
|
7175
7824
|
OpCode,
|
|
7176
7825
|
ServerMsgCode,
|
|
7177
7826
|
WebsocketCloseCodes,
|
|
7178
7827
|
ackOp,
|
|
7828
|
+
applyOptimisticUpdates,
|
|
7179
7829
|
asPos,
|
|
7180
7830
|
assert,
|
|
7181
7831
|
assertNever,
|
|
@@ -7185,9 +7835,7 @@ export {
|
|
|
7185
7835
|
convertToCommentData,
|
|
7186
7836
|
convertToCommentUserReaction,
|
|
7187
7837
|
convertToThreadData,
|
|
7188
|
-
createAsyncCache,
|
|
7189
7838
|
createClient,
|
|
7190
|
-
createCommentsApi,
|
|
7191
7839
|
deprecate,
|
|
7192
7840
|
deprecateIf,
|
|
7193
7841
|
detectDupes,
|
|
@@ -7201,6 +7849,7 @@ export {
|
|
|
7201
7849
|
isLiveNode,
|
|
7202
7850
|
isPlainObject,
|
|
7203
7851
|
isRootCrdt,
|
|
7852
|
+
kInternal,
|
|
7204
7853
|
legacy_patchImmutableObject,
|
|
7205
7854
|
lsonToJson,
|
|
7206
7855
|
makeEventSource,
|