@liveblocks/core 1.9.6 → 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.js CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "1.9.6";
9
+ var PKG_VERSION = "1.10.0-beta1";
10
10
  var PKG_FORMAT = "cjs";
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(requestedScope, roomId) {
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(requestedScope, roomId) {
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(requestedScope, roomId);
1398
+ const cachedToken = getCachedToken(roomOptions);
1396
1399
  if (cachedToken !== void 0) {
1397
1400
  return { type: "secret", token: cachedToken };
1398
1401
  }
1399
- let currentPromise = requestPromises.get(roomId);
1400
- if (currentPromise === void 0) {
1401
- currentPromise = makeAuthRequest(roomId);
1402
- requestPromises.set(roomId, currentPromise);
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
- requestPromises.delete(roomId);
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.__internal.getSelf_forDevTools();
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.__internal.getOthers_forDevTools();
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.__internal.getSelf_forDevTools();
1655
- const others = room.__internal.getOthers_forDevTools();
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 = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _44 => _44.size]), () => ( DEFAULT_SIZE));
1767
+ this.delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _45 => _45.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 = _optionalChain([results, 'optionalAccess', _46 => _46[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,1025 +1942,621 @@ function errorIf(condition, message) {
1744
1942
  }
1745
1943
  }
1746
1944
 
1747
- // src/comments/comment-body.ts
1748
- function isCommentBodyParagraph(element) {
1749
- return "type" in element && element.type === "mention";
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 isCommentBodyText(element) {
1752
- return "text" in element && typeof element.text === "string";
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 isCommentBodyMention(element) {
1755
- return "type" in element && element.type === "mention";
1984
+ function convertToCommentUserReaction(data) {
1985
+ return {
1986
+ ...data,
1987
+ createdAt: new Date(data.createdAt)
1988
+ };
1756
1989
  }
1757
- function isCommentBodyLink(element) {
1758
- return "type" in element && element.type === "link";
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
- var commentBodyElementsGuards = {
1761
- paragraph: isCommentBodyParagraph,
1762
- text: isCommentBodyText,
1763
- link: isCommentBodyLink,
1764
- mention: isCommentBodyMention
1765
- };
1766
- var commentBodyElementsTypes = {
1767
- paragraph: "block",
1768
- text: "inline",
1769
- link: "inline",
1770
- mention: "inline"
1771
- };
1772
- function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
1773
- if (!body || !_optionalChain([body, 'optionalAccess', _44 => _44.content])) {
1774
- return;
1775
- }
1776
- const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
1777
- const type = element ? commentBodyElementsTypes[element] : "all";
1778
- const guard = element ? commentBodyElementsGuards[element] : () => true;
1779
- const visitor = typeof elementOrVisitor === "function" ? elementOrVisitor : possiblyVisitor;
1780
- for (const block of body.content) {
1781
- if (type === "all" || type === "block") {
1782
- if (guard(block)) {
1783
- _optionalChain([visitor, 'optionalCall', _45 => _45(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
- if (type === "all" || type === "inline") {
1787
- for (const inline of block.children) {
1788
- if (guard(inline)) {
1789
- _optionalChain([visitor, 'optionalCall', _46 => _46(inline)]);
2014
+ const url = new URL(`/v2/c${endpoint}`, baseUrl);
2015
+ const response = await fetcher(url.toString(), {
2016
+ ...options,
2017
+ headers: {
2018
+ ..._optionalChain([options, 'optionalAccess', _47 => _47.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 (e3) {
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 (e4) {
2045
+ body = {};
2046
+ }
2047
+ return body;
1793
2048
  }
1794
- }
1795
- function getMentionedIdsFromCommentBody(body) {
1796
- const mentionedIds = /* @__PURE__ */ new Set();
1797
- traverseCommentBody(
1798
- body,
1799
- "mention",
1800
- (mention) => mentionedIds.add(mention.id)
1801
- );
1802
- return Array.from(mentionedIds);
1803
- }
1804
- async function resolveUsersInCommentBody(body, resolveUsers) {
1805
- const resolvedUsers = /* @__PURE__ */ new Map();
1806
- if (!resolveUsers) {
1807
- return resolvedUsers;
2049
+ async function getInboxNotifications(options) {
2050
+ const queryParams = toURLSearchParams({ limit: _optionalChain([options, 'optionalAccess', _48 => _48.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
- const userIds = getMentionedIdsFromCommentBody(body);
1810
- const users = await resolveUsers({
1811
- userIds
1812
- });
1813
- for (const [index, userId] of userIds.entries()) {
1814
- const user = _optionalChain([users, 'optionalAccess', _47 => _47[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
- return resolvedUsers;
1820
- }
1821
- var htmlEscapables = {
1822
- "&": "&amp;",
1823
- "<": "&lt;",
1824
- ">": "&gt;",
1825
- '"': "&quot;",
1826
- "'": "&#39;"
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
- return new HtmlSafeString(
1840
- ["", ...Array(strings.length - 1).fill(""), ""],
1841
- strings
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
  );
2089
+ async function markInboxNotificationAsRead(inboxNotificationId) {
2090
+ await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
2091
+ }
2092
+ return {
2093
+ getInboxNotifications,
2094
+ getUnreadInboxNotificationsCount,
2095
+ markAllInboxNotificationsAsRead,
2096
+ markInboxNotificationAsRead
2097
+ };
1843
2098
  }
1844
- function escapeHtml(value) {
1845
- if (value instanceof HtmlSafeString) {
1846
- return value.toString();
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
+ }
1847
2105
  }
1848
- if (Array.isArray(value)) {
1849
- return joinHtml(value).toString();
1850
- }
1851
- return String(value).replace(
1852
- htmlEscapablesRegex,
1853
- (character) => htmlEscapables[character]
1854
- );
2106
+ return result;
1855
2107
  }
1856
- var HtmlSafeString = class {
1857
- constructor(strings, values) {
1858
- this._strings = strings;
1859
- this._values = values;
1860
- }
1861
- toString() {
1862
- return this._strings.reduce((result, str, i) => {
1863
- return result + escapeHtml(nn(this._values[i - 1])) + str;
1864
- });
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}`);
1865
2120
  }
1866
- };
1867
- function html(strings, ...values) {
1868
- return new HtmlSafeString(strings, values);
2121
+ return String.fromCharCode(code);
1869
2122
  }
1870
- var markdownEscapables = {
1871
- _: "\\_",
1872
- "*": "\\*",
1873
- "#": "\\#",
1874
- "`": "\\`",
1875
- "~": "\\~",
1876
- "!": "\\!",
1877
- "|": "\\|",
1878
- "(": "\\(",
1879
- ")": "\\)",
1880
- "{": "\\{",
1881
- "}": "\\}",
1882
- "[": "\\[",
1883
- "]": "\\]"
1884
- };
1885
- var markdownEscapablesRegex = new RegExp(
1886
- Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
1887
- "g"
1888
- );
1889
- function joinMarkdown(strings) {
1890
- if (strings.length <= 0) {
1891
- return new MarkdownSafeString([""], []);
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;
1892
2132
  }
1893
- return new MarkdownSafeString(
1894
- ["", ...Array(strings.length - 1).fill(""), ""],
1895
- strings
1896
- );
1897
2133
  }
1898
- function escapeMarkdown(value) {
1899
- if (value instanceof MarkdownSafeString) {
1900
- return value.toString();
1901
- }
1902
- if (Array.isArray(value)) {
1903
- return joinMarkdown(value).toString();
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
+ }
1904
2150
  }
1905
- return String(value).replace(
1906
- markdownEscapablesRegex,
1907
- (character) => markdownEscapables[character]
1908
- );
2151
+ return ONE;
1909
2152
  }
1910
- var MarkdownSafeString = class {
1911
- constructor(strings, values) {
1912
- this._strings = strings;
1913
- this._values = values;
1914
- }
1915
- toString() {
1916
- return this._strings.reduce((result, str, i) => {
1917
- return result + escapeMarkdown(nn(this._values[i - 1])) + str;
1918
- });
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);
1919
2160
  }
1920
- };
1921
- function markdown(strings, ...values) {
1922
- return new MarkdownSafeString(strings, values);
2161
+ return pos + ONE;
1923
2162
  }
1924
- function toAbsoluteUrl(url) {
1925
- if (url.startsWith("http://") || url.startsWith("https://")) {
1926
- return url;
1927
- } else if (url.startsWith("www.")) {
1928
- return "https://" + url;
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");
1929
2170
  }
1930
- return;
1931
2171
  }
1932
- var stringifyCommentBodyPlainElements = {
1933
- paragraph: ({ children }) => children,
1934
- text: ({ element }) => element.text,
1935
- link: ({ element }) => element.url,
1936
- mention: ({ element, user }) => {
1937
- return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _48 => _48.name]), () => ( element.id))}`;
1938
- }
1939
- };
1940
- var stringifyCommentBodyHtmlElements = {
1941
- paragraph: ({ children }) => {
1942
- return children ? html`<p>${htmlSafe(children)}</p>` : children;
1943
- },
1944
- text: ({ element }) => {
1945
- let children = element.text;
1946
- if (!children) {
1947
- return children;
1948
- }
1949
- if (element.bold) {
1950
- children = html`<strong>${children}</strong>`;
1951
- }
1952
- if (element.italic) {
1953
- children = html`<em>${children}</em>`;
1954
- }
1955
- if (element.strikethrough) {
1956
- children = html`<s>${children}</s>`;
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 (element.code) {
1959
- children = html`<code>${children}</code>`;
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>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _49 => _49.name]), () => ( element.id))}</span>`;
1968
2195
  }
1969
- };
1970
- var stringifyCommentBodyMarkdownElements = {
1971
- paragraph: ({ children }) => {
1972
- return children;
1973
- },
1974
- text: ({ element }) => {
1975
- let children = element.text;
1976
- if (!children) {
1977
- return children;
1978
- }
1979
- if (element.bold) {
1980
- children = markdown`**${children}**`;
1981
- }
1982
- if (element.italic) {
1983
- children = markdown`_${children}_`;
1984
- }
1985
- if (element.strikethrough) {
1986
- children = markdown`~~${children}~~`;
1987
- }
1988
- if (element.code) {
1989
- children = markdown`\`${children}\``;
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`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _50 => _50.name]), () => ( element.id))}`;
1998
2215
  }
1999
- };
2000
- async function stringifyCommentBody(body, options) {
2001
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _51 => _51.format]), () => ( "plain"));
2002
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _52 => _52.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
2003
- const elements = {
2004
- ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
2005
- ..._optionalChain([options, 'optionalAccess', _53 => _53.elements])
2006
- };
2007
- const resolvedUsers = await resolveUsersInCommentBody(
2008
- body,
2009
- _optionalChain([options, 'optionalAccess', _54 => _54.resolveUsers])
2216
+ return true;
2217
+ }
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);
2223
+ }
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
2010
2230
  );
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: _nullishCoalesce(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);
2054
2231
  }
2055
- function convertToCommentData(data) {
2056
- const editedAt = data.editedAt ? new Date(data.editedAt) : void 0;
2057
- const createdAt = new Date(data.createdAt);
2058
- const reactions = data.reactions.map((reaction) => ({
2059
- ...reaction,
2060
- createdAt: new Date(reaction.createdAt)
2061
- }));
2062
- if (data.body) {
2063
- return {
2064
- ...data,
2065
- reactions,
2066
- createdAt,
2067
- editedAt
2068
- };
2069
- } else {
2070
- const deletedAt = new Date(data.deletedAt);
2071
- return {
2072
- ...data,
2073
- reactions,
2074
- createdAt,
2075
- editedAt,
2076
- deletedAt
2077
- };
2078
- }
2232
+ function asPos(str) {
2233
+ return isPos(str) ? str : convertToPos(str);
2079
2234
  }
2080
- function convertToThreadData(data) {
2081
- const updatedAt = data.updatedAt ? new Date(data.updatedAt) : void 0;
2082
- const createdAt = new Date(data.createdAt);
2083
- const comments = data.comments.map(
2084
- (comment) => convertToCommentData(comment)
2085
- );
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) {
2086
2250
  return {
2087
- ...data,
2088
- createdAt,
2089
- updatedAt,
2090
- comments
2251
+ type: 5 /* DELETE_CRDT */,
2252
+ id: "ACK",
2253
+ // (H)ACK
2254
+ opId
2091
2255
  };
2092
2256
  }
2093
- function convertToCommentUserReaction(data) {
2094
- return {
2095
- ...data,
2096
- createdAt: new Date(data.createdAt)
2097
- };
2257
+ function isAckOp(op) {
2258
+ return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
2098
2259
  }
2099
2260
 
2100
- // src/comments/index.ts
2101
- function getAuthBearerHeaderFromAuthValue(authValue) {
2102
- if (authValue.type === "public") {
2103
- return authValue.publicApiKey;
2104
- } else {
2105
- return authValue.token.raw;
2106
- }
2261
+ // src/crdts/AbstractCrdt.ts
2262
+ function crdtAsLiveNode(value) {
2263
+ return value;
2107
2264
  }
2108
- var CommentsApiError = class extends Error {
2109
- constructor(message, status, details) {
2110
- super(message);
2111
- this.message = message;
2112
- this.status = status;
2113
- this.details = details;
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
- function createCommentsApi(roomId, getAuthValue, config) {
2117
- async function fetchJson(endpoint, options) {
2118
- const response = await fetchApi(roomId, endpoint, options);
2119
- if (!response.ok) {
2120
- if (response.status >= 400 && response.status < 600) {
2121
- let error3;
2122
- try {
2123
- const errorBody = await response.json();
2124
- error3 = new CommentsApiError(
2125
- errorBody.message,
2126
- response.status,
2127
- errorBody
2128
- );
2129
- } catch (e3) {
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
- let body;
2136
- try {
2137
- body = await response.json();
2138
- } catch (e4) {
2139
- body = {};
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
- async function fetchApi(roomId2, endpoint, options) {
2144
- const authValue = await getAuthValue();
2145
- const url = new URL(
2146
- `/v2/c/rooms/${encodeURIComponent(roomId2)}${endpoint}`,
2147
- config.baseUrl
2148
- );
2149
- return await fetch(url.toString(), {
2150
- ...options,
2151
- headers: {
2152
- ..._optionalChain([options, 'optionalAccess', _55 => _55.headers]),
2153
- Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
2154
- }
2155
- });
2303
+ /** @internal */
2304
+ get _pool() {
2305
+ return this.__pool;
2156
2306
  }
2157
- async function getThreads(options) {
2158
- const response = await fetchApi(roomId, "/threads/search", {
2159
- body: JSON.stringify({
2160
- ..._optionalChain([options, 'optionalAccess', _56 => _56.query, 'optionalAccess', _57 => _57.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.");
2307
+ get roomId() {
2308
+ return this.__pool ? this.__pool.roomId : null;
2309
+ }
2310
+ /** @internal */
2311
+ get _id() {
2312
+ return this.__id;
2313
+ }
2314
+ /** @internal */
2315
+ get parent() {
2316
+ return this._parent;
2317
+ }
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");
2174
2329
  }
2175
2330
  }
2176
- async function createThread({
2177
- metadata,
2178
- body,
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
- })
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 };
2197
2339
  }
2198
- );
2199
- return convertToThreadData(thread);
2340
+ }
2341
+ return { modified: false };
2200
2342
  }
2201
- async function editThreadMetadata({
2202
- metadata,
2203
- threadId
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)
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;
2213
2357
  }
2214
- );
2358
+ default:
2359
+ return assertNever(this.parent, "Unknown state");
2360
+ }
2215
2361
  }
2216
- async function createComment({
2217
- threadId,
2218
- commentId,
2219
- body
2220
- }) {
2221
- const comment = await fetchJson(
2222
- `/threads/${encodeURIComponent(threadId)}/comments`,
2223
- {
2224
- method: "POST",
2225
- headers: {
2226
- "Content-Type": "application/json"
2227
- },
2228
- body: JSON.stringify({
2229
- id: commentId,
2230
- body
2231
- })
2232
- }
2233
- );
2234
- return convertToCommentData(comment);
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;
2235
2370
  }
2236
- async function editComment({
2237
- threadId,
2238
- commentId,
2239
- body
2240
- }) {
2241
- const comment = await fetchJson(
2242
- `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
2243
- commentId
2244
- )}`,
2245
- {
2246
- method: "POST",
2247
- headers: {
2248
- "Content-Type": "application/json"
2249
- },
2250
- body: JSON.stringify({
2251
- body
2252
- })
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;
2253
2380
  }
2254
- );
2255
- return convertToCommentData(comment);
2256
- }
2257
- async function deleteComment({
2258
- threadId,
2259
- commentId
2260
- }) {
2261
- await fetchJson(
2262
- `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
2263
- commentId
2264
- )}`,
2265
- {
2266
- method: "DELETE"
2381
+ case "NoParent": {
2382
+ this._parent = NoParent;
2383
+ break;
2267
2384
  }
2268
- );
2269
- }
2270
- async function addReaction({
2271
- threadId,
2272
- commentId,
2273
- emoji
2274
- }) {
2275
- const reaction = await fetchJson(
2276
- `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
2277
- commentId
2278
- )}/reactions`,
2279
- {
2280
- method: "POST",
2281
- headers: {
2282
- "Content-Type": "application/json"
2283
- },
2284
- body: JSON.stringify({ emoji })
2385
+ case "Orphaned": {
2386
+ break;
2285
2387
  }
2286
- );
2287
- return convertToCommentUserReaction(reaction);
2388
+ default:
2389
+ assertNever(this.parent, "Unknown state");
2390
+ }
2391
+ this.__pool = void 0;
2288
2392
  }
2289
- async function removeReaction({
2290
- threadId,
2291
- commentId,
2292
- emoji
2293
- }) {
2294
- await fetchJson(
2295
- `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
2296
- commentId
2297
- )}/reactions/${encodeURIComponent(emoji)}`,
2298
- {
2299
- method: "DELETE"
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();
2300
2406
  }
2301
- );
2302
- }
2303
- return {
2304
- getThreads,
2305
- createThread,
2306
- editThreadMetadata,
2307
- createComment,
2308
- editComment,
2309
- deleteComment,
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;
2346
2407
  }
2347
- if (i === lastIndex) {
2348
- if (code === MIN_CODE + 1) {
2349
- return pos.substring(0, i) + ZERO_NINE;
2350
- } else {
2351
- return pos.substring(0, i) + String.fromCharCode(code - 1);
2352
- }
2353
- } else {
2354
- return pos.substring(0, i + 1);
2408
+ }
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);
2355
2418
  }
2419
+ return this._cachedTreeNode;
2356
2420
  }
2357
- return ONE;
2358
- }
2359
- function after(pos) {
2360
- for (let i = 0; i <= pos.length - 1; i++) {
2361
- const code = pos.charCodeAt(i);
2362
- if (code >= MAX_CODE) {
2363
- continue;
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();
2364
2427
  }
2365
- return pos.substring(0, i) + String.fromCharCode(code + 1);
2428
+ return this._cachedImmutable;
2366
2429
  }
2367
- return pos + ONE;
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);
2368
2442
  }
2369
- function between(lo, hi) {
2370
- if (lo < hi) {
2371
- return _between(lo, hi);
2372
- } else if (lo > hi) {
2373
- return _between(hi, lo);
2374
- } else {
2375
- throw new Error("Cannot compute value between two equal positions");
2376
- }
2377
- }
2378
- function _between(lo, hi) {
2379
- let index = 0;
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/protocol/Op.ts
2443
- var OpCode = /* @__PURE__ */ ((OpCode2) => {
2444
- OpCode2[OpCode2["INIT"] = 0] = "INIT";
2445
- OpCode2[OpCode2["SET_PARENT_KEY"] = 1] = "SET_PARENT_KEY";
2446
- OpCode2[OpCode2["CREATE_LIST"] = 2] = "CREATE_LIST";
2447
- OpCode2[OpCode2["UPDATE_OBJECT"] = 3] = "UPDATE_OBJECT";
2448
- OpCode2[OpCode2["CREATE_OBJECT"] = 4] = "CREATE_OBJECT";
2449
- OpCode2[OpCode2["DELETE_CRDT"] = 5] = "DELETE_CRDT";
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/AbstractCrdt.ts
2468
- function crdtAsLiveNode(value) {
2469
- return value;
2470
- }
2471
- function HasParent(node, key, pos = asPos(key)) {
2472
- return Object.freeze({ type: "HasParent", node, key, pos });
2473
- }
2474
- var NoParent = Object.freeze({ type: "NoParent" });
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
- _getParentKeyOrThrow() {
2485
- switch (this.parent.type) {
2486
- case "HasParent":
2487
- return this.parent.key;
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
- get _parentPos() {
2498
- switch (this.parent.type) {
2499
- case "HasParent":
2500
- return this.parent.pos;
2501
- case "NoParent":
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: _optionalChain([pool, 'optionalAccess', _49 => _49.generateOpId, 'call', _50 => _50()]),
2483
+ id: this._id,
2484
+ parentId,
2485
+ parentKey,
2486
+ data: this.data
2487
+ }
2488
+ ];
2508
2489
  }
2509
2490
  /** @internal */
2510
- get _pool() {
2511
- return this.__pool;
2512
- }
2513
- get roomId() {
2514
- return this.__pool ? this.__pool.roomId : null;
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
- get _id() {
2518
- return this.__id;
2503
+ _attachChild(_op) {
2504
+ throw new Error("Method not implemented.");
2519
2505
  }
2520
2506
  /** @internal */
2521
- get parent() {
2522
- return this._parent;
2507
+ _detachChild(_crdt) {
2508
+ throw new Error("Method not implemented.");
2523
2509
  }
2524
2510
  /** @internal */
2525
- get _parentKey() {
2526
- switch (this.parent.type) {
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
- _apply(op, _isLocal) {
2539
- switch (op.type) {
2540
- case 5 /* DELETE_CRDT */: {
2541
- if (this.parent.type === "HasParent") {
2542
- return this.parent.node._detachChild(crdtAsLiveNode(this));
2543
- }
2544
- return { modified: false };
2545
- }
2546
- }
2547
- return { modified: false };
2515
+ _toTreeNode(key) {
2516
+ return {
2517
+ type: "Json",
2518
+ id: _nullishCoalesce(this._id, () => ( nanoid())),
2519
+ key,
2520
+ payload: this._data
2521
+ };
2548
2522
  }
2549
2523
  /** @internal */
2550
- _setParentLink(newParentNode, newParentKey) {
2551
- switch (this.parent.type) {
2552
- case "HasParent":
2553
- if (this.parent.node !== newParentNode) {
2554
- throw new Error("Cannot set parent: node already has a parent");
2555
- } else {
2556
- this._parent = HasParent(newParentNode, newParentKey);
2557
- return;
2558
- }
2559
- case "Orphaned":
2560
- case "NoParent": {
2561
- this._parent = HasParent(newParentNode, newParentKey);
2562
- return;
2563
- }
2564
- default:
2565
- return assertNever(this.parent, "Unknown state");
2566
- }
2524
+ _toImmutable() {
2525
+ return this._data;
2567
2526
  }
2568
- /** @internal */
2569
- _attach(id, pool) {
2570
- if (this.__id || this.__pool) {
2571
- throw new Error("Cannot attach node: already attached");
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;
2572
2551
  }
2573
- pool.addNode(id, crdtAsLiveNode(this));
2574
- this.__id = id;
2575
- this.__pool = pool;
2576
2552
  }
2577
2553
  /** @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: _optionalChain([pool, 'optionalAccess', _58 => _58.generateOpId, 'call', _59 => _59()]),
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: _nullishCoalesce(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;
2757
- }
2758
- }
2759
- /** @internal */
2760
- static _deserialize([id], parentToChildren, pool) {
2761
- const list = new _LiveList();
2762
- list._attach(id, pool);
2763
- const children = parentToChildren.get(id);
2764
- if (children === void 0) {
2765
- return list;
2554
+ static _deserialize([id], parentToChildren, pool) {
2555
+ const list = new _LiveList();
2556
+ list._attach(id, pool);
2557
+ const children = parentToChildren.get(id);
2558
+ if (children === void 0) {
2559
+ return list;
2766
2560
  }
2767
2561
  for (const [id2, crdt] of children) {
2768
2562
  const child = deserialize([id2, crdt], parentToChildren, pool);
@@ -2787,7 +2581,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2787
2581
  const ops = [];
2788
2582
  const op = {
2789
2583
  id: this._id,
2790
- opId: _optionalChain([pool, 'optionalAccess', _60 => _60.generateOpId, 'call', _61 => _61()]),
2584
+ opId: _optionalChain([pool, 'optionalAccess', _51 => _51.generateOpId, 'call', _52 => _52()]),
2791
2585
  type: 2 /* CREATE_LIST */,
2792
2586
  parentId,
2793
2587
  parentKey
@@ -3064,7 +2858,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3064
2858
  _applyInsertUndoRedo(op) {
3065
2859
  const { id, parentKey: key } = op;
3066
2860
  const child = creationOpToLiveNode(op);
3067
- if (_optionalChain([this, 'access', _62 => _62._pool, 'optionalAccess', _63 => _63.getNode, 'call', _64 => _64(id)]) !== void 0) {
2861
+ if (_optionalChain([this, 'access', _53 => _53._pool, 'optionalAccess', _54 => _54.getNode, 'call', _55 => _55(id)]) !== void 0) {
3068
2862
  return { modified: false };
3069
2863
  }
3070
2864
  child._attach(id, nn(this._pool));
@@ -3072,8 +2866,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
3072
2866
  const existingItemIndex = this._indexOfPosition(key);
3073
2867
  let newKey = key;
3074
2868
  if (existingItemIndex !== -1) {
3075
- const before2 = _optionalChain([this, 'access', _65 => _65._items, 'access', _66 => _66[existingItemIndex], 'optionalAccess', _67 => _67._parentPos]);
3076
- const after2 = _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]);
2869
+ const before2 = _optionalChain([this, 'access', _56 => _56._items, 'access', _57 => _57[existingItemIndex], 'optionalAccess', _58 => _58._parentPos]);
2870
+ const after2 = _optionalChain([this, 'access', _59 => _59._items, 'access', _60 => _60[existingItemIndex + 1], 'optionalAccess', _61 => _61._parentPos]);
3077
2871
  newKey = makePosition(before2, after2);
3078
2872
  child._setParentLink(this, newKey);
3079
2873
  }
@@ -3088,7 +2882,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3088
2882
  _applySetUndoRedo(op) {
3089
2883
  const { id, parentKey: key } = op;
3090
2884
  const child = creationOpToLiveNode(op);
3091
- if (_optionalChain([this, 'access', _71 => _71._pool, 'optionalAccess', _72 => _72.getNode, 'call', _73 => _73(id)]) !== void 0) {
2885
+ if (_optionalChain([this, 'access', _62 => _62._pool, 'optionalAccess', _63 => _63.getNode, 'call', _64 => _64(id)]) !== void 0) {
3092
2886
  return { modified: false };
3093
2887
  }
3094
2888
  this._unacknowledgedSets.set(key, nn(op.opId));
@@ -3210,7 +3004,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3210
3004
  } else {
3211
3005
  this._items[existingItemIndex]._setParentLink(
3212
3006
  this,
3213
- makePosition(newKey, _optionalChain([this, 'access', _74 => _74._items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]))
3007
+ makePosition(newKey, _optionalChain([this, 'access', _65 => _65._items, 'access', _66 => _66[existingItemIndex + 1], 'optionalAccess', _67 => _67._parentPos]))
3214
3008
  );
3215
3009
  const previousIndex = this._items.indexOf(child);
3216
3010
  child._setParentLink(this, newKey);
@@ -3236,7 +3030,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3236
3030
  if (existingItemIndex !== -1) {
3237
3031
  this._items[existingItemIndex]._setParentLink(
3238
3032
  this,
3239
- makePosition(newKey, _optionalChain([this, 'access', _77 => _77._items, 'access', _78 => _78[existingItemIndex + 1], 'optionalAccess', _79 => _79._parentPos]))
3033
+ makePosition(newKey, _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]))
3240
3034
  );
3241
3035
  }
3242
3036
  child._setParentLink(this, newKey);
@@ -3255,7 +3049,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3255
3049
  if (existingItemIndex !== -1) {
3256
3050
  this._items[existingItemIndex]._setParentLink(
3257
3051
  this,
3258
- makePosition(newKey, _optionalChain([this, 'access', _80 => _80._items, 'access', _81 => _81[existingItemIndex + 1], 'optionalAccess', _82 => _82._parentPos]))
3052
+ makePosition(newKey, _optionalChain([this, 'access', _71 => _71._items, 'access', _72 => _72[existingItemIndex + 1], 'optionalAccess', _73 => _73._parentPos]))
3259
3053
  );
3260
3054
  }
3261
3055
  child._setParentLink(this, newKey);
@@ -3283,7 +3077,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3283
3077
  if (existingItemIndex !== -1) {
3284
3078
  this._items[existingItemIndex]._setParentLink(
3285
3079
  this,
3286
- makePosition(newKey, _optionalChain([this, 'access', _83 => _83._items, 'access', _84 => _84[existingItemIndex + 1], 'optionalAccess', _85 => _85._parentPos]))
3080
+ makePosition(newKey, _optionalChain([this, 'access', _74 => _74._items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]))
3287
3081
  );
3288
3082
  }
3289
3083
  child._setParentLink(this, newKey);
@@ -3341,7 +3135,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3341
3135
  * @param element The element to add to the end of the LiveList.
3342
3136
  */
3343
3137
  push(element) {
3344
- _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
3138
+ _optionalChain([this, 'access', _77 => _77._pool, 'optionalAccess', _78 => _78.assertStorageIsWritable, 'call', _79 => _79()]);
3345
3139
  return this.insert(element, this.length);
3346
3140
  }
3347
3141
  /**
@@ -3350,7 +3144,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3350
3144
  * @param index The index at which you want to insert the element.
3351
3145
  */
3352
3146
  insert(element, index) {
3353
- _optionalChain([this, 'access', _89 => _89._pool, 'optionalAccess', _90 => _90.assertStorageIsWritable, 'call', _91 => _91()]);
3147
+ _optionalChain([this, 'access', _80 => _80._pool, 'optionalAccess', _81 => _81.assertStorageIsWritable, 'call', _82 => _82()]);
3354
3148
  if (index < 0 || index > this._items.length) {
3355
3149
  throw new Error(
3356
3150
  `Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
@@ -3380,7 +3174,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3380
3174
  * @param targetIndex The index where the element should be after moving.
3381
3175
  */
3382
3176
  move(index, targetIndex) {
3383
- _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
3177
+ _optionalChain([this, 'access', _83 => _83._pool, 'optionalAccess', _84 => _84.assertStorageIsWritable, 'call', _85 => _85()]);
3384
3178
  if (targetIndex < 0) {
3385
3179
  throw new Error("targetIndex cannot be less than 0");
3386
3180
  }
@@ -3438,7 +3232,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3438
3232
  * @param index The index of the element to delete
3439
3233
  */
3440
3234
  delete(index) {
3441
- _optionalChain([this, 'access', _95 => _95._pool, 'optionalAccess', _96 => _96.assertStorageIsWritable, 'call', _97 => _97()]);
3235
+ _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
3442
3236
  if (index < 0 || index >= this._items.length) {
3443
3237
  throw new Error(
3444
3238
  `Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -3471,7 +3265,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3471
3265
  }
3472
3266
  }
3473
3267
  clear() {
3474
- _optionalChain([this, 'access', _98 => _98._pool, 'optionalAccess', _99 => _99.assertStorageIsWritable, 'call', _100 => _100()]);
3268
+ _optionalChain([this, 'access', _89 => _89._pool, 'optionalAccess', _90 => _90.assertStorageIsWritable, 'call', _91 => _91()]);
3475
3269
  if (this._pool) {
3476
3270
  const ops = [];
3477
3271
  const reverseOps = [];
@@ -3505,7 +3299,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3505
3299
  }
3506
3300
  }
3507
3301
  set(index, item) {
3508
- _optionalChain([this, 'access', _101 => _101._pool, 'optionalAccess', _102 => _102.assertStorageIsWritable, 'call', _103 => _103()]);
3302
+ _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
3509
3303
  if (index < 0 || index >= this._items.length) {
3510
3304
  throw new Error(
3511
3305
  `Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -3653,7 +3447,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3653
3447
  _shiftItemPosition(index, key) {
3654
3448
  const shiftedPosition = makePosition(
3655
3449
  key,
3656
- this._items.length > index + 1 ? _optionalChain([this, 'access', _104 => _104._items, 'access', _105 => _105[index + 1], 'optionalAccess', _106 => _106._parentPos]) : void 0
3450
+ this._items.length > index + 1 ? _optionalChain([this, 'access', _95 => _95._items, 'access', _96 => _96[index + 1], 'optionalAccess', _97 => _97._parentPos]) : void 0
3657
3451
  );
3658
3452
  this._items[index]._setParentLink(this, shiftedPosition);
3659
3453
  }
@@ -3782,7 +3576,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3782
3576
  const ops = [];
3783
3577
  const op = {
3784
3578
  id: this._id,
3785
- opId: _optionalChain([pool, 'optionalAccess', _107 => _107.generateOpId, 'call', _108 => _108()]),
3579
+ opId: _optionalChain([pool, 'optionalAccess', _98 => _98.generateOpId, 'call', _99 => _99()]),
3786
3580
  type: 7 /* CREATE_MAP */,
3787
3581
  parentId,
3788
3582
  parentKey
@@ -3929,7 +3723,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3929
3723
  * @param value The value of the element to add. Should be serializable to JSON.
3930
3724
  */
3931
3725
  set(key, value) {
3932
- _optionalChain([this, 'access', _109 => _109._pool, 'optionalAccess', _110 => _110.assertStorageIsWritable, 'call', _111 => _111()]);
3726
+ _optionalChain([this, 'access', _100 => _100._pool, 'optionalAccess', _101 => _101.assertStorageIsWritable, 'call', _102 => _102()]);
3933
3727
  const oldValue = this._map.get(key);
3934
3728
  if (oldValue) {
3935
3729
  oldValue._detach();
@@ -3975,7 +3769,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3975
3769
  * @returns true if an element existed and has been removed, or false if the element does not exist.
3976
3770
  */
3977
3771
  delete(key) {
3978
- _optionalChain([this, 'access', _112 => _112._pool, 'optionalAccess', _113 => _113.assertStorageIsWritable, 'call', _114 => _114()]);
3772
+ _optionalChain([this, 'access', _103 => _103._pool, 'optionalAccess', _104 => _104.assertStorageIsWritable, 'call', _105 => _105()]);
3979
3773
  const item = this._map.get(key);
3980
3774
  if (item === void 0) {
3981
3775
  return false;
@@ -4154,7 +3948,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4154
3948
  if (this._id === void 0) {
4155
3949
  throw new Error("Cannot serialize item is not attached");
4156
3950
  }
4157
- const opId = _optionalChain([pool, 'optionalAccess', _115 => _115.generateOpId, 'call', _116 => _116()]);
3951
+ const opId = _optionalChain([pool, 'optionalAccess', _106 => _106.generateOpId, 'call', _107 => _107()]);
4158
3952
  const ops = [];
4159
3953
  const op = {
4160
3954
  type: 4 /* CREATE_OBJECT */,
@@ -4432,7 +4226,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4432
4226
  * @param value The value of the property to add
4433
4227
  */
4434
4228
  set(key, value) {
4435
- _optionalChain([this, 'access', _117 => _117._pool, 'optionalAccess', _118 => _118.assertStorageIsWritable, 'call', _119 => _119()]);
4229
+ _optionalChain([this, 'access', _108 => _108._pool, 'optionalAccess', _109 => _109.assertStorageIsWritable, 'call', _110 => _110()]);
4436
4230
  this.update({ [key]: value });
4437
4231
  }
4438
4232
  /**
@@ -4447,7 +4241,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4447
4241
  * @param key The key of the property to delete
4448
4242
  */
4449
4243
  delete(key) {
4450
- _optionalChain([this, 'access', _120 => _120._pool, 'optionalAccess', _121 => _121.assertStorageIsWritable, 'call', _122 => _122()]);
4244
+ _optionalChain([this, 'access', _111 => _111._pool, 'optionalAccess', _112 => _112.assertStorageIsWritable, 'call', _113 => _113()]);
4451
4245
  const keyAsString = key;
4452
4246
  const oldValue = this._map.get(keyAsString);
4453
4247
  if (oldValue === void 0) {
@@ -4500,7 +4294,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4500
4294
  * @param patch The object used to overrides properties
4501
4295
  */
4502
4296
  update(patch) {
4503
- _optionalChain([this, 'access', _123 => _123._pool, 'optionalAccess', _124 => _124.assertStorageIsWritable, 'call', _125 => _125()]);
4297
+ _optionalChain([this, 'access', _114 => _114._pool, 'optionalAccess', _115 => _115.assertStorageIsWritable, 'call', _116 => _116()]);
4504
4298
  if (this._pool === void 0 || this._id === void 0) {
4505
4299
  for (const key in patch) {
4506
4300
  const newValue = patch[key];
@@ -5144,63 +4938,281 @@ function installBackgroundTabSpy() {
5144
4938
  const doc = typeof document !== "undefined" ? document : void 0;
5145
4939
  const inBackgroundSince = { current: null };
5146
4940
  function onVisibilityChange() {
5147
- if (_optionalChain([doc, 'optionalAccess', _126 => _126.visibilityState]) === "hidden") {
4941
+ if (_optionalChain([doc, 'optionalAccess', _117 => _117.visibilityState]) === "hidden") {
5148
4942
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
5149
4943
  } else {
5150
4944
  inBackgroundSince.current = null;
5151
4945
  }
5152
4946
  }
5153
- _optionalChain([doc, 'optionalAccess', _127 => _127.addEventListener, 'call', _128 => _128("visibilitychange", onVisibilityChange)]);
4947
+ _optionalChain([doc, 'optionalAccess', _118 => _118.addEventListener, 'call', _119 => _119("visibilitychange", onVisibilityChange)]);
5154
4948
  const unsub = () => {
5155
- _optionalChain([doc, 'optionalAccess', _129 => _129.removeEventListener, 'call', _130 => _130("visibilitychange", onVisibilityChange)]);
4949
+ _optionalChain([doc, 'optionalAccess', _120 => _120.removeEventListener, 'call', _121 => _121("visibilitychange", onVisibilityChange)]);
5156
4950
  };
5157
4951
  return [inBackgroundSince, unsub];
5158
4952
  }
5159
- function createRoom(options, config) {
5160
- const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
5161
- const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
5162
- const [inBackgroundSince, uninstallBgTabSpy] = installBackgroundTabSpy();
5163
- const delegates = {
5164
- ...config.delegates,
5165
- // A connection is allowed to go into "zombie state" only if all of the
5166
- // following conditions apply:
5167
- //
5168
- // - The `backgroundKeepAliveTimeout` client option is configured
5169
- // - The browser window has been in the background for at least
5170
- // `backgroundKeepAliveTimeout` milliseconds
5171
- // - There are no pending changes
5172
- //
5173
- canZombie() {
5174
- return config.backgroundKeepAliveTimeout !== void 0 && inBackgroundSince.current !== null && Date.now() > inBackgroundSince.current + config.backgroundKeepAliveTimeout && getStorageStatus() !== "synchronizing";
5175
- }
5176
- };
5177
- const managedSocket = new ManagedSocket(
5178
- delegates,
5179
- config.enableDebugLogging
5180
- );
5181
- const context = {
5182
- buffer: {
5183
- flushTimerID: void 0,
5184
- lastFlushedAt: 0,
5185
- presenceUpdates: (
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 (e5) {
4979
+ error3 = new CommentsApiError(response.statusText, response.status);
5190
4980
  }
5191
- ),
5192
- messages: [],
5193
- storageOperations: []
5194
- },
5195
- staticSessionInfo: new ValueRef(null),
5196
- dynamicSessionInfo: new ValueRef(null),
5197
- myPresence: new PatchableRef(initialPresence),
5198
- others: new OthersRef(),
5199
- initialStorage,
5200
- idFactory: null,
5201
- // Storage
5202
- clock: 0,
5203
- opClock: 0,
4981
+ throw error3;
4982
+ }
4983
+ }
4984
+ let body;
4985
+ try {
4986
+ body = await response.json();
4987
+ } catch (e6) {
4988
+ body = {};
4989
+ }
4990
+ return body;
4991
+ }
4992
+ async function getThreads(options) {
4993
+ const response = await fetchCommentsApi("/threads/search", {
4994
+ body: JSON.stringify({
4995
+ ..._optionalChain([options, 'optionalAccess', _122 => _122.query, 'optionalAccess', _123 => _123.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,
5204
5216
  nodes: /* @__PURE__ */ new Map(),
5205
5217
  root: void 0,
5206
5218
  undoStack: [],
@@ -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.type === "secret" ? authValue.token.raw : authValue.publicApiKey;
5232
+ const tokenKey = getAuthBearerHeaderFromAuthValue(authValue);
5221
5233
  if (tokenKey !== lastTokenKey) {
5222
5234
  lastTokenKey = tokenKey;
5223
5235
  if (authValue.type === "secret") {
@@ -5341,7 +5353,7 @@ function createRoom(options, config) {
5341
5353
  }
5342
5354
  },
5343
5355
  assertStorageIsWritable: () => {
5344
- const scopes = _optionalChain([context, 'access', _131 => _131.dynamicSessionInfo, 'access', _132 => _132.current, 'optionalAccess', _133 => _133.scopes]);
5356
+ const scopes = _optionalChain([context, 'access', _124 => _124.dynamicSessionInfo, 'access', _125 => _125.current, 'optionalAccess', _126 => _126.scopes]);
5345
5357
  if (scopes === void 0) {
5346
5358
  return;
5347
5359
  }
@@ -5371,18 +5383,26 @@ function createRoom(options, config) {
5371
5383
  ydoc: makeEventSource(),
5372
5384
  comments: makeEventSource()
5373
5385
  };
5374
- async function streamFetch(authTokenOrPublicApiKey, roomId) {
5386
+ async function fetchClientApi(roomId, endpoint, authValue, options2) {
5375
5387
  const url = new URL(
5376
- `/v2/c/rooms/${encodeURIComponent(roomId)}/storage`,
5388
+ `/v2/c/rooms/${encodeURIComponent(roomId)}${endpoint}`,
5377
5389
  config.baseUrl
5378
- ).toString();
5379
- const fetcher = _optionalChain([config, 'access', _134 => _134.polyfills, 'optionalAccess', _135 => _135.fetch]) || /* istanbul ignore next */
5390
+ );
5391
+ const fetcher = _optionalChain([config, 'access', _127 => _127.polyfills, 'optionalAccess', _128 => _128.fetch]) || /* istanbul ignore next */
5380
5392
  fetch;
5381
- return fetcher(url.toString(), {
5393
+ return await fetcher(url.toString(), {
5394
+ ...options2,
5395
+ headers: {
5396
+ ..._optionalChain([options2, 'optionalAccess', _129 => _129.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,25 +5410,17 @@ function createRoom(options, config) {
5390
5410
  if (!managedSocket.authValue) {
5391
5411
  throw new Error("Not authorized");
5392
5412
  }
5393
- const authTokenOrPublicApiKey = managedSocket.authValue.type === "public" ? managedSocket.authValue.publicApiKey : managedSocket.authValue.token.raw;
5394
- const url = new URL(
5395
- `/v2/c/rooms/${encodeURIComponent(config.roomId)}${endpoint}`,
5396
- config.baseUrl
5397
- ).toString();
5398
- const fetcher = _optionalChain([config, 'access', _136 => _136.polyfills, 'optionalAccess', _137 => _137.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
  });
5408
5420
  }
5409
5421
  function sendMessages(messages) {
5410
5422
  const serializedPayload = JSON.stringify(messages);
5411
- const nonce = _optionalChain([context, 'access', _138 => _138.dynamicSessionInfo, 'access', _139 => _139.current, 'optionalAccess', _140 => _140.nonce]);
5423
+ const nonce = _optionalChain([context, 'access', _130 => _130.dynamicSessionInfo, 'access', _131 => _131.current, 'optionalAccess', _132 => _132.nonce]);
5412
5424
  if (config.unstable_fallbackToHTTP && nonce) {
5413
5425
  const size = new TextEncoder().encode(serializedPayload).length;
5414
5426
  if (size > MAX_SOCKET_MESSAGE_SIZE) {
@@ -5670,7 +5682,7 @@ function createRoom(options, config) {
5670
5682
  }
5671
5683
  context.myPresence.patch(patch);
5672
5684
  if (context.activeBatch) {
5673
- if (_optionalChain([options2, 'optionalAccess', _141 => _141.addToHistory])) {
5685
+ if (_optionalChain([options2, 'optionalAccess', _133 => _133.addToHistory])) {
5674
5686
  context.activeBatch.reverseOps.unshift({
5675
5687
  type: "presence",
5676
5688
  data: oldValues
@@ -5680,7 +5692,7 @@ function createRoom(options, config) {
5680
5692
  } else {
5681
5693
  flushNowOrSoon();
5682
5694
  batchUpdates(() => {
5683
- if (_optionalChain([options2, 'optionalAccess', _142 => _142.addToHistory])) {
5695
+ if (_optionalChain([options2, 'optionalAccess', _134 => _134.addToHistory])) {
5684
5696
  addToUndoStack(
5685
5697
  [{ type: "presence", data: oldValues }],
5686
5698
  doNotBatchUpdates
@@ -5878,7 +5890,7 @@ function createRoom(options, config) {
5878
5890
  if (process.env.NODE_ENV !== "production") {
5879
5891
  const traces = /* @__PURE__ */ new Set();
5880
5892
  for (const opId of message.opIds) {
5881
- const trace = _optionalChain([context, 'access', _143 => _143.opStackTraces, 'optionalAccess', _144 => _144.get, 'call', _145 => _145(opId)]);
5893
+ const trace = _optionalChain([context, 'access', _135 => _135.opStackTraces, 'optionalAccess', _136 => _136.get, 'call', _137 => _137(opId)]);
5882
5894
  if (trace) {
5883
5895
  traces.add(trace);
5884
5896
  }
@@ -6007,7 +6019,7 @@ ${Array.from(traces).join("\n\n")}`
6007
6019
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
6008
6020
  createOrUpdateRootFromMessage(message, doNotBatchUpdates);
6009
6021
  applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
6010
- _optionalChain([_resolveStoragePromise, 'optionalCall', _146 => _146()]);
6022
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _138 => _138()]);
6011
6023
  notifyStorageStatus();
6012
6024
  eventHub.storageDidLoad.notify();
6013
6025
  }
@@ -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,34 +6213,78 @@ ${Array.from(traces).join("\n\n")}`
6204
6213
  ydoc: eventHub.ydoc.observable,
6205
6214
  comments: eventHub.comments.observable
6206
6215
  };
6207
- const commentsApi = createCommentsApi(config.roomId, delegates.authenticate, {
6208
- baseUrl: config.baseUrl
6209
- });
6210
- return Object.defineProperty(
6211
- {
6212
- /* NOTE: Exposing __internal here only to allow testing implementation details in unit tests */
6213
- __internal: {
6214
- get presenceBuffer() {
6215
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _147 => _147.buffer, 'access', _148 => _148.presenceUpdates, 'optionalAccess', _149 => _149.data]), () => ( null)));
6216
- },
6217
- // prettier-ignore
6218
- get undoStack() {
6219
- return deepClone(context.undoStack);
6220
- },
6221
- // prettier-ignore
6222
- get nodeCount() {
6223
- return context.nodes.size;
6224
- },
6225
- // prettier-ignore
6226
- // Support for the Liveblocks browser extension
6227
- getSelf_forDevTools: () => selfAsTreeNode.current,
6228
- getOthers_forDevTools: () => others_forDevTools.current,
6229
- // prettier-ignore
6230
- simulate: {
6231
- // These exist only for our E2E testing app
6232
- explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
6233
- rawSend: (data) => managedSocket.send(data)
6234
- }
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 (e7) {
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(_nullishCoalesce(_optionalChain([context, 'access', _139 => _139.buffer, 'access', _140 => _140.presenceUpdates, 'optionalAccess', _141 => _141.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,
6281
+ getOthers_forDevTools: () => others_forDevTools.current,
6282
+ // prettier-ignore
6283
+ simulate: {
6284
+ // These exist only for our E2E testing app
6285
+ explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
6286
+ rawSend: (data) => managedSocket.send(data)
6287
+ }
6235
6288
  },
6236
6289
  id: config.roomId,
6237
6290
  subscribe: makeClassicSubscribeFn(events),
@@ -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
- ...commentsApi
6325
+ // Comments
6326
+ ...commentsApi,
6327
+ // Notifications
6328
+ getRoomNotificationSettings,
6329
+ updateRoomNotificationSettings
6273
6330
  },
6274
- // Explictly make the __internal field non-enumerable, to avoid aggressive
6331
+ // Explictly make the internal field non-enumerable, to avoid aggressive
6275
6332
  // freezing when used with Immer
6276
- "__internal",
6333
+ kInternal,
6277
6334
  { enumerable: false }
6278
6335
  );
6279
6336
  }
@@ -6354,7 +6411,7 @@ function makeClassicSubscribeFn(events) {
6354
6411
  }
6355
6412
  if (isLiveNode(first)) {
6356
6413
  const node = first;
6357
- if (_optionalChain([options, 'optionalAccess', _150 => _150.isDeep])) {
6414
+ if (_optionalChain([options, 'optionalAccess', _142 => _142.isDeep])) {
6358
6415
  const storageCallback = second;
6359
6416
  return subscribeToLiveStructureDeeply(node, storageCallback);
6360
6417
  } else {
@@ -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(_nullishCoalesce(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: _nullishCoalesce(options2.initialPresence, () => ( {})),
@@ -6479,12 +6866,12 @@ function createClient(options) {
6479
6866
  createSocket: makeCreateSocketDelegateForRoom(
6480
6867
  roomId,
6481
6868
  baseUrl,
6482
- _optionalChain([clientOptions, 'access', _151 => _151.polyfills, 'optionalAccess', _152 => _152.WebSocket])
6869
+ _optionalChain([clientOptions, 'access', _143 => _143.polyfills, 'optionalAccess', _144 => _144.WebSocket])
6483
6870
  ),
6484
6871
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
6485
6872
  })),
6486
6873
  enableDebugLogging: clientOptions.enableDebugLogging,
6487
- unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _153 => _153.unstable_batchedUpdates]),
6874
+ unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _145 => _145.unstable_batchedUpdates]),
6488
6875
  baseUrl,
6489
6876
  unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
6490
6877
  unstable_streamData: !!clientOptions.unstable_streamData
@@ -6500,7 +6887,7 @@ function createClient(options) {
6500
6887
  const shouldConnect = _nullishCoalesce(_nullishCoalesce(options2.autoConnect, () => ( options2.shouldInitiallyConnect)), () => ( true));
6501
6888
  if (shouldConnect) {
6502
6889
  if (typeof atob === "undefined") {
6503
- if (_optionalChain([clientOptions, 'access', _154 => _154.polyfills, 'optionalAccess', _155 => _155.atob]) === void 0) {
6890
+ if (_optionalChain([clientOptions, 'access', _146 => _146.polyfills, 'optionalAccess', _147 => _147.atob]) === void 0) {
6504
6891
  throw new Error(
6505
6892
  "You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
6506
6893
  );
@@ -6516,61 +6903,453 @@ function createClient(options) {
6516
6903
  return room;
6517
6904
  }
6518
6905
  function getRoom(roomId) {
6519
- const room = _optionalChain([roomsById, 'access', _156 => _156.get, 'call', _157 => _157(roomId), 'optionalAccess', _158 => _158.room]);
6906
+ const room = _optionalChain([roomsById, 'access', _148 => _148.get, 'call', _149 => _149(roomId), 'optionalAccess', _150 => _150.room]);
6520
6907
  return room ? room : null;
6521
6908
  }
6522
6909
  function forceLeave(roomId) {
6523
- const unsubs = _nullishCoalesce(_optionalChain([roomsById, 'access', _159 => _159.get, 'call', _160 => _160(roomId), 'optionalAccess', _161 => _161.unsubs]), () => ( /* @__PURE__ */ new Set()));
6910
+ const unsubs = _nullishCoalesce(_optionalChain([roomsById, 'access', _151 => _151.get, 'call', _152 => _152(roomId), 'optionalAccess', _153 => _153.unsubs]), () => ( /* @__PURE__ */ new Set()));
6524
6911
  for (const unsub of unsubs) {
6525
6912
  unsub();
6526
6913
  }
6527
6914
  }
6528
- function logout() {
6529
- authManager.reset();
6530
- for (const { room } of roomsById.values()) {
6531
- if (!isIdle(room.getStatus())) {
6532
- room.reconnect();
6533
- }
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: _optionalChain([clientOptions, 'access', _154 => _154.polyfills, 'optionalAccess', _155 => _155.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 _optionalChain([resolveUsers, 'optionalCall', _156 => _156({ userIds })]);
6946
+ warnIfNoResolveUsers();
6947
+ return _nullishCoalesce(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 _optionalChain([resolveRoomsInfo, 'optionalCall', _157 => _157({ roomIds })]);
6960
+ warnIfNoResolveRoomsInfo();
6961
+ return _nullishCoalesce(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 ${_nullishCoalesce(recommendedMin, () => ( min))} and ${max}.` : `${option} should be at least ${_nullishCoalesce(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 || !_optionalChain([body, 'optionalAccess', _158 => _158.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
+ _optionalChain([visitor, 'optionalCall', _159 => _159(block)]);
7083
+ }
7084
+ }
7085
+ if (type === "all" || type === "inline") {
7086
+ for (const inline of block.children) {
7087
+ if (guard(inline)) {
7088
+ _optionalChain([visitor, 'optionalCall', _160 => _160(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 = _optionalChain([users, 'optionalAccess', _161 => _161[index]]);
7114
+ if (user) {
7115
+ resolvedUsers.set(userId, user);
7116
+ }
7117
+ }
7118
+ return resolvedUsers;
7119
+ }
7120
+ var htmlEscapables = {
7121
+ "&": "&amp;",
7122
+ "<": "&lt;",
7123
+ ">": "&gt;",
7124
+ '"': "&quot;",
7125
+ "'": "&#39;"
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 `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _162 => _162.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>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _163 => _163.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;
7277
+ }
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`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _164 => _164.name]), () => ( element.id))}`;
6535
7297
  }
6536
- return {
6537
- logout,
6538
- // Old, deprecated APIs
6539
- enter,
6540
- getRoom,
6541
- leave: forceLeave,
6542
- // New, preferred API
6543
- enterRoom
7298
+ };
7299
+ async function stringifyCommentBody(body, options) {
7300
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _165 => _165.format]), () => ( "plain"));
7301
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _166 => _166.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
7302
+ const elements = {
7303
+ ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
7304
+ ..._optionalChain([options, 'optionalAccess', _167 => _167.elements])
6544
7305
  };
6545
- }
6546
- function checkBounds(option, value, min, max, recommendedMin) {
6547
- if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
6548
- throw new Error(
6549
- max !== void 0 ? `${option} should be between ${_nullishCoalesce(recommendedMin, () => ( min))} and ${max}.` : `${option} should be at least ${_nullishCoalesce(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
+ _optionalChain([options, 'optionalAccess', _168 => _168.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: _nullishCoalesce(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
@@ -6801,12 +7580,12 @@ function legacy_patchImmutableNode(state, path, update) {
6801
7580
  }
6802
7581
  const newState = Object.assign({}, state);
6803
7582
  for (const key in update.updates) {
6804
- if (_optionalChain([update, 'access', _162 => _162.updates, 'access', _163 => _163[key], 'optionalAccess', _164 => _164.type]) === "update") {
7583
+ if (_optionalChain([update, 'access', _169 => _169.updates, 'access', _170 => _170[key], 'optionalAccess', _171 => _171.type]) === "update") {
6805
7584
  const val = update.node.get(key);
6806
7585
  if (val !== void 0) {
6807
7586
  newState[key] = lsonToJson(val);
6808
7587
  }
6809
- } else if (_optionalChain([update, 'access', _165 => _165.updates, 'access', _166 => _166[key], 'optionalAccess', _167 => _167.type]) === "delete") {
7588
+ } else if (_optionalChain([update, 'access', _172 => _172.updates, 'access', _173 => _173[key], 'optionalAccess', _174 => _174.type]) === "delete") {
6810
7589
  delete newState[key];
6811
7590
  }
6812
7591
  }
@@ -6867,12 +7646,12 @@ function legacy_patchImmutableNode(state, path, update) {
6867
7646
  }
6868
7647
  const newState = Object.assign({}, state);
6869
7648
  for (const key in update.updates) {
6870
- if (_optionalChain([update, 'access', _168 => _168.updates, 'access', _169 => _169[key], 'optionalAccess', _170 => _170.type]) === "update") {
7649
+ if (_optionalChain([update, 'access', _175 => _175.updates, 'access', _176 => _176[key], 'optionalAccess', _177 => _177.type]) === "update") {
6871
7650
  const value = update.node.get(key);
6872
7651
  if (value !== void 0) {
6873
7652
  newState[key] = lsonToJson(value);
6874
7653
  }
6875
- } else if (_optionalChain([update, 'access', _171 => _171.updates, 'access', _172 => _172[key], 'optionalAccess', _173 => _173.type]) === "delete") {
7654
+ } else if (_optionalChain([update, 'access', _178 => _178.updates, 'access', _179 => _179[key], 'optionalAccess', _180 => _180.type]) === "delete") {
6876
7655
  delete newState[key];
6877
7656
  }
6878
7657
  }
@@ -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 = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _174 => _174.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 _optionalChain([cache, 'access', _175 => _175.get, 'call', _176 => _176(key), 'optionalAccess', _177 => _177.getState, 'call', _178 => _178()]);
7034
- }
7035
- function revalidate(key) {
7036
- return create(key).revalidate();
7037
- }
7038
- function subscribe(key, callback) {
7039
- return _nullishCoalesce(create(key).subscribe(callback), () => ( noop));
7040
- }
7041
- function subscribeOnce(key, callback) {
7042
- return _nullishCoalesce(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/stringify.ts
7152
- function stringify(object, ...args) {
7153
- if (typeof object !== "object" || object === null || Array.isArray(object)) {
7154
- return JSON.stringify(object, ...args);
7775
+ // src/lib/shallow.ts
7776
+ function shallowArray(xs, ys) {
7777
+ if (xs.length !== ys.length) {
7778
+ return false;
7155
7779
  }
7156
- const sortedObject = Object.keys(object).sort().reduce(
7157
- (sortedObject2, key) => {
7158
- sortedObject2[key] = object[key];
7159
- return sortedObject2;
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
- return JSON.stringify(sortedObject, ...args);
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
@@ -7216,5 +7864,6 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
7216
7864
 
7217
7865
 
7218
7866
 
7219
- exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.cloneLson = cloneLson; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToThreadData = convertToThreadData; exports.createAsyncCache = createAsyncCache; exports.createClient = createClient; exports.createCommentsApi = createCommentsApi; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.isChildCrdt = isChildCrdt; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.nn = nn; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.withTimeout = withTimeout;
7867
+
7868
+ exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.NotificationsApiError = NotificationsApiError; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.applyOptimisticUpdates = applyOptimisticUpdates; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.cloneLson = cloneLson; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.isChildCrdt = isChildCrdt; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.kInternal = kInternal; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.nn = nn; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.withTimeout = withTimeout;
7220
7869
  //# sourceMappingURL=index.js.map