@liveblocks/core 1.19.0-test1 → 2.0.0-alpha1

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.19.0-test1";
9
+ var PKG_VERSION = "2.0.0-alpha1";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -362,23 +362,29 @@ var FSM = class {
362
362
  }
363
363
  onEnterAsync(nameOrPattern, promiseFn, onOK, onError) {
364
364
  return this.onEnter(nameOrPattern, () => {
365
- let cancelled = false;
366
- void promiseFn(this.currentContext.current).then(
365
+ const abortController = new AbortController();
366
+ const signal = abortController.signal;
367
+ let done = false;
368
+ void promiseFn(this.currentContext.current, signal).then(
367
369
  // On OK
368
370
  (data) => {
369
- if (!cancelled) {
371
+ if (!signal.aborted) {
372
+ done = true;
370
373
  this.transition({ type: "ASYNC_OK", data }, onOK);
371
374
  }
372
375
  },
373
376
  // On Error
374
377
  (reason) => {
375
- if (!cancelled) {
378
+ if (!signal.aborted) {
379
+ done = true;
376
380
  this.transition({ type: "ASYNC_ERROR", reason }, onError);
377
381
  }
378
382
  }
379
383
  );
380
384
  return () => {
381
- cancelled = true;
385
+ if (!done) {
386
+ abortController.abort();
387
+ }
382
388
  };
383
389
  });
384
390
  }
@@ -652,6 +658,7 @@ var ServerMsgCode = /* @__PURE__ */ ((ServerMsgCode2) => {
652
658
 
653
659
  // src/types/IWebSocket.ts
654
660
  var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
661
+ WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_NORMAL"] = 1e3] = "CLOSE_NORMAL";
655
662
  WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_ABNORMAL"] = 1006] = "CLOSE_ABNORMAL";
656
663
  WebsocketCloseCodes2[WebsocketCloseCodes2["UNEXPECTED_CONDITION"] = 1011] = "UNEXPECTED_CONDITION";
657
664
  WebsocketCloseCodes2[WebsocketCloseCodes2["TRY_AGAIN_LATER"] = 1013] = "TRY_AGAIN_LATER";
@@ -661,6 +668,8 @@ var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
661
668
  WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"] = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS";
662
669
  WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
663
670
  WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
671
+ WebsocketCloseCodes2[WebsocketCloseCodes2["ROOM_ID_UPDATED"] = 4006] = "ROOM_ID_UPDATED";
672
+ WebsocketCloseCodes2[WebsocketCloseCodes2["KICKED"] = 4100] = "KICKED";
664
673
  WebsocketCloseCodes2[WebsocketCloseCodes2["TOKEN_EXPIRED"] = 4109] = "TOKEN_EXPIRED";
665
674
  WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_WITHOUT_RETRY"] = 4999] = "CLOSE_WITHOUT_RETRY";
666
675
  return WebsocketCloseCodes2;
@@ -679,22 +688,6 @@ function shouldRetryWithoutReauth(code) {
679
688
  function isIdle(status) {
680
689
  return status === "initial" || status === "disconnected";
681
690
  }
682
- function newToLegacyStatus(status) {
683
- switch (status) {
684
- case "connecting":
685
- return "connecting";
686
- case "connected":
687
- return "open";
688
- case "reconnecting":
689
- return "unavailable";
690
- case "disconnected":
691
- return "failed";
692
- case "initial":
693
- return "closed";
694
- default:
695
- return "closed";
696
- }
697
- }
698
691
  function toNewConnectionStatus(machine) {
699
692
  const state = machine.currentState;
700
693
  switch (state) {
@@ -728,16 +721,19 @@ var StopRetrying = class extends Error {
728
721
  }
729
722
  };
730
723
  var LiveblocksError = class extends Error {
724
+ /** @internal */
731
725
  constructor(message, code) {
732
726
  super(message);
733
727
  this.code = code;
734
728
  }
735
729
  };
736
- function nextBackoffDelay(currentDelay, delays = BACKOFF_DELAYS) {
730
+ function nextBackoffDelay(currentDelay, delays) {
737
731
  return _nullishCoalesce(delays.find((delay) => delay > currentDelay), () => ( delays[delays.length - 1]));
738
732
  }
739
733
  function increaseBackoffDelay(context) {
740
- context.patch({ backoffDelay: nextBackoffDelay(context.backoffDelay) });
734
+ context.patch({
735
+ backoffDelay: nextBackoffDelay(context.backoffDelay, BACKOFF_DELAYS)
736
+ });
741
737
  }
742
738
  function increaseBackoffDelayAggressively(context) {
743
739
  context.patch({
@@ -770,9 +766,13 @@ function logPrematureErrorOrCloseEvent(e) {
770
766
  };
771
767
  }
772
768
  function logCloseEvent(event) {
769
+ const details = [`code: ${event.code}`];
770
+ if (event.reason) {
771
+ details.push(`reason: ${event.reason}`);
772
+ }
773
773
  return (ctx) => {
774
774
  warn(
775
- `Connection to Liveblocks websocket server closed (code: ${event.code}). Retrying in ${ctx.backoffDelay}ms.`
775
+ `Connection to Liveblocks websocket server closed (${details.join(", ")}). Retrying in ${ctx.backoffDelay}ms.`
776
776
  );
777
777
  };
778
778
  }
@@ -884,8 +884,7 @@ function createConnectionStateMachine(delegates, options) {
884
884
  (okEvent) => ({
885
885
  target: "@connecting.busy",
886
886
  effect: assign({
887
- authValue: okEvent.data,
888
- backoffDelay: RESET_DELAY
887
+ authValue: okEvent.data
889
888
  })
890
889
  }),
891
890
  // Auth failed
@@ -942,14 +941,16 @@ function createConnectionStateMachine(delegates, options) {
942
941
  // When the "open" event happens, we're ready to transition to the
943
942
  // OK state. This is done by resolving the Promise.
944
943
  //
945
- async (ctx) => {
944
+ async (ctx, signal) => {
946
945
  let capturedPrematureEvent = null;
946
+ let unconfirmedSocket = null;
947
947
  const connect$ = new Promise(
948
948
  (resolve, rej) => {
949
949
  if (ctx.authValue === null) {
950
950
  throw new Error("No auth authValue");
951
951
  }
952
952
  const socket = delegates.createSocket(ctx.authValue);
953
+ unconfirmedSocket = socket;
953
954
  function reject(event) {
954
955
  capturedPrematureEvent = event;
955
956
  socket.removeEventListener("message", onSocketMessage);
@@ -1005,12 +1006,18 @@ function createConnectionStateMachine(delegates, options) {
1005
1006
  //
1006
1007
  ([socket, unsub]) => {
1007
1008
  unsub();
1009
+ if (signal.aborted) {
1010
+ throw new Error("Aborted");
1011
+ }
1008
1012
  if (capturedPrematureEvent) {
1009
1013
  throw capturedPrematureEvent;
1010
1014
  }
1011
1015
  return socket;
1012
1016
  }
1013
- );
1017
+ ).catch((e) => {
1018
+ teardownSocket(unconfirmedSocket);
1019
+ throw e;
1020
+ });
1014
1021
  },
1015
1022
  // Only transition to OK state after a successfully opened WebSocket connection
1016
1023
  (okEvent) => ({
@@ -1205,9 +1212,6 @@ var ManagedSocket = class {
1205
1212
  this.events = events;
1206
1213
  this.cleanups = cleanups;
1207
1214
  }
1208
- getLegacyStatus() {
1209
- return newToLegacyStatus(this.getStatus());
1210
- }
1211
1215
  getStatus() {
1212
1216
  try {
1213
1217
  return toNewConnectionStatus(this.machine);
@@ -1325,7 +1329,7 @@ function createAuthManager(authOptions) {
1325
1329
  }
1326
1330
  return false;
1327
1331
  }
1328
- function getCachedToken(requestedScope, roomId) {
1332
+ function getCachedToken(requestOptions) {
1329
1333
  const now = Math.ceil(Date.now() / 1e3);
1330
1334
  for (let i = tokens.length - 1; i >= 0; i--) {
1331
1335
  const token = tokens[i];
@@ -1338,8 +1342,15 @@ function createAuthManager(authOptions) {
1338
1342
  if (token.parsed.k === "id" /* ID_TOKEN */) {
1339
1343
  return token;
1340
1344
  } else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
1345
+ if (!requestOptions.roomId && Object.entries(token.parsed.perms).length === 0) {
1346
+ return token;
1347
+ }
1341
1348
  for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
1342
- if (resource.includes("*") && roomId.startsWith(resource.replace("*", "")) || roomId === resource && hasCorrespondingScopes(requestedScope, scopes)) {
1349
+ if (!requestOptions.roomId) {
1350
+ if (resource.includes("*") && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
1351
+ return token;
1352
+ }
1353
+ } else if (resource.includes("*") && requestOptions.roomId.startsWith(resource.replace("*", "")) || requestOptions.roomId === resource && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
1343
1354
  return token;
1344
1355
  }
1345
1356
  }
@@ -1347,7 +1358,7 @@ function createAuthManager(authOptions) {
1347
1358
  }
1348
1359
  return void 0;
1349
1360
  }
1350
- async function makeAuthRequest(roomId) {
1361
+ async function makeAuthRequest(options) {
1351
1362
  const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _36 => _36.polyfills, 'optionalAccess', _37 => _37.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
1352
1363
  if (authentication.type === "private") {
1353
1364
  if (fetcher === void 0) {
@@ -1356,7 +1367,7 @@ function createAuthManager(authOptions) {
1356
1367
  );
1357
1368
  }
1358
1369
  const response = await fetchAuthEndpoint(fetcher, authentication.url, {
1359
- room: roomId
1370
+ room: options.roomId
1360
1371
  });
1361
1372
  const parsed = parseAuthToken(response.token);
1362
1373
  if (seenTokens.has(parsed.raw)) {
@@ -1367,10 +1378,11 @@ function createAuthManager(authOptions) {
1367
1378
  return parsed;
1368
1379
  }
1369
1380
  if (authentication.type === "custom") {
1370
- const response = await authentication.callback(roomId);
1381
+ const response = await authentication.callback(options.roomId);
1371
1382
  if (response && typeof response === "object") {
1372
1383
  if (typeof response.token === "string") {
1373
- return parseAuthToken(response.token);
1384
+ const parsed = parseAuthToken(response.token);
1385
+ return parsed;
1374
1386
  } else if (typeof response.error === "string") {
1375
1387
  const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
1376
1388
  if (response.error === "forbidden") {
@@ -1388,18 +1400,27 @@ function createAuthManager(authOptions) {
1388
1400
  "Unexpected authentication type. Must be private or custom."
1389
1401
  );
1390
1402
  }
1391
- async function getAuthValue(requestedScope, roomId) {
1403
+ async function getAuthValue(requestOptions) {
1392
1404
  if (authentication.type === "public") {
1393
1405
  return { type: "public", publicApiKey: authentication.publicApiKey };
1394
1406
  }
1395
- const cachedToken = getCachedToken(requestedScope, roomId);
1407
+ const cachedToken = getCachedToken(requestOptions);
1396
1408
  if (cachedToken !== void 0) {
1397
1409
  return { type: "secret", token: cachedToken };
1398
1410
  }
1399
- let currentPromise = requestPromises.get(roomId);
1400
- if (currentPromise === void 0) {
1401
- currentPromise = makeAuthRequest(roomId);
1402
- requestPromises.set(roomId, currentPromise);
1411
+ let currentPromise;
1412
+ if (requestOptions.roomId) {
1413
+ currentPromise = requestPromises.get(requestOptions.roomId);
1414
+ if (currentPromise === void 0) {
1415
+ currentPromise = makeAuthRequest(requestOptions);
1416
+ requestPromises.set(requestOptions.roomId, currentPromise);
1417
+ }
1418
+ } else {
1419
+ currentPromise = requestPromises.get("liveblocks-user-token");
1420
+ if (currentPromise === void 0) {
1421
+ currentPromise = makeAuthRequest(requestOptions);
1422
+ requestPromises.set("liveblocks-user-token", currentPromise);
1423
+ }
1403
1424
  }
1404
1425
  try {
1405
1426
  const token = await currentPromise;
@@ -1412,7 +1433,11 @@ function createAuthManager(authOptions) {
1412
1433
  }
1413
1434
  return { type: "secret", token };
1414
1435
  } finally {
1415
- requestPromises.delete(roomId);
1436
+ if (requestOptions.roomId) {
1437
+ requestPromises.delete(requestOptions.roomId);
1438
+ } else {
1439
+ requestPromises.delete("liveblocks-user-token");
1440
+ }
1416
1441
  }
1417
1442
  }
1418
1443
  return {
@@ -1501,6 +1526,9 @@ async function fetchAuthEndpoint(fetch2, endpoint, body) {
1501
1526
  // src/constants.ts
1502
1527
  var DEFAULT_BASE_URL = "https://api.liveblocks.io";
1503
1528
 
1529
+ // src/internal.ts
1530
+ var kInternal = Symbol();
1531
+
1504
1532
  // src/devtools/bridge.ts
1505
1533
  var _bridgeActive = false;
1506
1534
  function activateBridge(allowed) {
@@ -1630,7 +1658,7 @@ function partialSyncStorage(room) {
1630
1658
  }
1631
1659
  }
1632
1660
  function partialSyncMe(room) {
1633
- const me = room.__internal.getSelf_forDevTools();
1661
+ const me = room[kInternal].getSelf_forDevTools();
1634
1662
  if (me) {
1635
1663
  sendToPanel({
1636
1664
  msg: "room::sync::partial",
@@ -1640,7 +1668,7 @@ function partialSyncMe(room) {
1640
1668
  }
1641
1669
  }
1642
1670
  function partialSyncOthers(room) {
1643
- const others = room.__internal.getOthers_forDevTools();
1671
+ const others = room[kInternal].getOthers_forDevTools();
1644
1672
  if (others) {
1645
1673
  sendToPanel({
1646
1674
  msg: "room::sync::partial",
@@ -1651,8 +1679,8 @@ function partialSyncOthers(room) {
1651
1679
  }
1652
1680
  function fullSync(room) {
1653
1681
  const root = room.getStorageSnapshot();
1654
- const me = room.__internal.getSelf_forDevTools();
1655
- const others = room.__internal.getOthers_forDevTools();
1682
+ const me = room[kInternal].getSelf_forDevTools();
1683
+ const others = room[kInternal].getOthers_forDevTools();
1656
1684
  room.fetchYDoc("");
1657
1685
  sendToPanel({
1658
1686
  msg: "room::sync::full",
@@ -1711,6 +1739,183 @@ function unlinkDevTools(roomId) {
1711
1739
  });
1712
1740
  }
1713
1741
 
1742
+ // src/lib/stringify.ts
1743
+ function stringify(object, ...args) {
1744
+ if (typeof object !== "object" || object === null || Array.isArray(object)) {
1745
+ return JSON.stringify(object, ...args);
1746
+ }
1747
+ const sortedObject = Object.keys(object).sort().reduce(
1748
+ (sortedObject2, key) => {
1749
+ sortedObject2[key] = object[key];
1750
+ return sortedObject2;
1751
+ },
1752
+ {}
1753
+ );
1754
+ return JSON.stringify(sortedObject, ...args);
1755
+ }
1756
+
1757
+ // src/lib/batch.ts
1758
+ var DEFAULT_SIZE = 50;
1759
+ var DEFAULT_DELAY = 100;
1760
+ var noop = () => {
1761
+ };
1762
+ var BatchCall = class {
1763
+ constructor(args) {
1764
+ this.resolve = noop;
1765
+ this.reject = noop;
1766
+ this.promise = new Promise(noop);
1767
+ this.args = args;
1768
+ }
1769
+ };
1770
+ var Batch = class {
1771
+ constructor(callback, options) {
1772
+ this.queue = [];
1773
+ this.error = false;
1774
+ this.callback = callback;
1775
+ this.size = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _44 => _44.size]), () => ( DEFAULT_SIZE));
1776
+ this.delay = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _45 => _45.delay]), () => ( DEFAULT_DELAY));
1777
+ }
1778
+ clearDelayTimeout() {
1779
+ if (this.delayTimeoutId !== void 0) {
1780
+ clearTimeout(this.delayTimeoutId);
1781
+ this.delayTimeoutId = void 0;
1782
+ }
1783
+ }
1784
+ schedule() {
1785
+ if (this.queue.length === this.size) {
1786
+ void this.flush();
1787
+ } else if (this.queue.length === 1) {
1788
+ this.clearDelayTimeout();
1789
+ this.delayTimeoutId = setTimeout(() => void this.flush(), this.delay);
1790
+ }
1791
+ }
1792
+ async flush() {
1793
+ if (this.queue.length === 0) {
1794
+ return;
1795
+ }
1796
+ const calls = this.queue.splice(0);
1797
+ const args = calls.map((call) => call.args);
1798
+ try {
1799
+ const results = await this.callback(args);
1800
+ this.error = false;
1801
+ calls.forEach((call, index) => {
1802
+ const result = _optionalChain([results, 'optionalAccess', _46 => _46[index]]);
1803
+ if (!Array.isArray(results)) {
1804
+ call.reject(new Error("Callback must return an array."));
1805
+ } else if (calls.length !== results.length) {
1806
+ call.reject(
1807
+ new Error(
1808
+ `Callback must return an array of the same length as the number of provided items. Expected ${calls.length}, but got ${results.length}.`
1809
+ )
1810
+ );
1811
+ } else if (result instanceof Error) {
1812
+ call.reject(result);
1813
+ } else {
1814
+ call.resolve(result);
1815
+ }
1816
+ });
1817
+ } catch (error3) {
1818
+ this.error = true;
1819
+ calls.forEach((call) => {
1820
+ call.reject(error3);
1821
+ });
1822
+ }
1823
+ }
1824
+ get(...args) {
1825
+ const existingCall = this.queue.find(
1826
+ (call2) => stringify(call2.args) === stringify(args)
1827
+ );
1828
+ if (existingCall) {
1829
+ return existingCall.promise;
1830
+ }
1831
+ const call = new BatchCall(args);
1832
+ call.promise = new Promise((resolve, reject) => {
1833
+ call.resolve = resolve;
1834
+ call.reject = reject;
1835
+ });
1836
+ this.queue.push(call);
1837
+ this.schedule();
1838
+ return call.promise;
1839
+ }
1840
+ clear() {
1841
+ this.queue = [];
1842
+ this.error = false;
1843
+ this.clearDelayTimeout();
1844
+ }
1845
+ };
1846
+ function createBatchStore(callback, options) {
1847
+ const batch = new Batch(callback, options);
1848
+ const cache = /* @__PURE__ */ new Map();
1849
+ const eventSource2 = makeEventSource();
1850
+ function getCacheKey(args) {
1851
+ return stringify(args);
1852
+ }
1853
+ function setStateAndNotify(cacheKey, state) {
1854
+ if (state) {
1855
+ cache.set(cacheKey, state);
1856
+ } else {
1857
+ cache.delete(cacheKey);
1858
+ }
1859
+ eventSource2.notify(state);
1860
+ }
1861
+ async function get(...args) {
1862
+ const cacheKey = getCacheKey(args);
1863
+ if (cache.has(cacheKey)) {
1864
+ return;
1865
+ }
1866
+ try {
1867
+ setStateAndNotify(cacheKey, { isLoading: true });
1868
+ const result = await batch.get(...args);
1869
+ setStateAndNotify(cacheKey, { isLoading: false, data: result });
1870
+ } catch (error3) {
1871
+ setStateAndNotify(cacheKey, {
1872
+ isLoading: false,
1873
+ error: error3
1874
+ });
1875
+ }
1876
+ }
1877
+ function getState(...args) {
1878
+ const cacheKey = getCacheKey(args);
1879
+ return cache.get(cacheKey);
1880
+ }
1881
+ return {
1882
+ ...eventSource2,
1883
+ get,
1884
+ getState
1885
+ };
1886
+ }
1887
+
1888
+ // src/lib/create-store.ts
1889
+ function createStore(initialState) {
1890
+ let state = initialState;
1891
+ const subscribers = /* @__PURE__ */ new Set();
1892
+ function get() {
1893
+ return state;
1894
+ }
1895
+ function set(callback) {
1896
+ const newState = callback(state);
1897
+ if (state === newState) {
1898
+ return;
1899
+ }
1900
+ state = newState;
1901
+ for (const subscriber of subscribers) {
1902
+ subscriber(state);
1903
+ }
1904
+ }
1905
+ function subscribe(callback) {
1906
+ subscribers.add(callback);
1907
+ callback(state);
1908
+ return () => {
1909
+ subscribers.delete(callback);
1910
+ };
1911
+ }
1912
+ return {
1913
+ get,
1914
+ set,
1915
+ subscribe
1916
+ };
1917
+ }
1918
+
1714
1919
  // src/lib/deprecation.ts
1715
1920
  var _emittedDeprecationWarnings = /* @__PURE__ */ new Set();
1716
1921
  function deprecate(message, key = message) {
@@ -1744,390 +1949,144 @@ function errorIf(condition, message) {
1744
1949
  }
1745
1950
  }
1746
1951
 
1747
- // src/comments/comment-body.ts
1748
- function isCommentBodyParagraph(element) {
1749
- return "type" in element && element.type === "mention";
1750
- }
1751
- function isCommentBodyText(element) {
1752
- return "text" in element && typeof element.text === "string";
1753
- }
1754
- function isCommentBodyMention(element) {
1755
- return "type" in element && element.type === "mention";
1756
- }
1757
- function isCommentBodyLink(element) {
1758
- return "type" in element && element.type === "link";
1759
- }
1760
- var commentBodyElementsGuards = {
1761
- paragraph: isCommentBodyParagraph,
1762
- text: isCommentBodyText,
1763
- link: isCommentBodyLink,
1764
- mention: isCommentBodyMention
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
- }
1785
- }
1786
- if (type === "all" || type === "inline") {
1787
- for (const inline of block.children) {
1788
- if (guard(inline)) {
1789
- _optionalChain([visitor, 'optionalCall', _46 => _46(inline)]);
1790
- }
1791
- }
1792
- }
1952
+ // src/convert-plain-data.ts
1953
+ function convertToCommentData(data) {
1954
+ const editedAt = data.editedAt ? new Date(data.editedAt) : void 0;
1955
+ const createdAt = new Date(data.createdAt);
1956
+ const reactions = data.reactions.map((reaction) => ({
1957
+ ...reaction,
1958
+ createdAt: new Date(reaction.createdAt)
1959
+ }));
1960
+ if (data.body) {
1961
+ return {
1962
+ ...data,
1963
+ reactions,
1964
+ createdAt,
1965
+ editedAt
1966
+ };
1967
+ } else {
1968
+ const deletedAt = new Date(data.deletedAt);
1969
+ return {
1970
+ ...data,
1971
+ reactions,
1972
+ createdAt,
1973
+ editedAt,
1974
+ deletedAt
1975
+ };
1793
1976
  }
1794
1977
  }
1795
- function getMentionedIdsFromCommentBody(body) {
1796
- const mentionedIds = /* @__PURE__ */ new Set();
1797
- traverseCommentBody(
1798
- body,
1799
- "mention",
1800
- (mention) => mentionedIds.add(mention.id)
1978
+ function convertToThreadData(data) {
1979
+ const updatedAt = data.updatedAt ? new Date(data.updatedAt) : void 0;
1980
+ const createdAt = new Date(data.createdAt);
1981
+ const comments = data.comments.map(
1982
+ (comment) => convertToCommentData(comment)
1801
1983
  );
1802
- return Array.from(mentionedIds);
1984
+ return {
1985
+ ...data,
1986
+ createdAt,
1987
+ updatedAt,
1988
+ comments
1989
+ };
1803
1990
  }
1804
- async function resolveUsersInCommentBody(body, resolveUsers) {
1805
- const resolvedUsers = /* @__PURE__ */ new Map();
1806
- if (!resolveUsers) {
1807
- return resolvedUsers;
1808
- }
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
- }
1991
+ function convertToCommentUserReaction(data) {
1992
+ return {
1993
+ ...data,
1994
+ createdAt: new Date(data.createdAt)
1995
+ };
1996
+ }
1997
+ function convertToInboxNotificationData(data) {
1998
+ const notifiedAt = new Date(data.notifiedAt);
1999
+ const readAt = data.readAt ? new Date(data.readAt) : null;
2000
+ if ("activities" in data) {
2001
+ const activities = data.activities.map((activity) => ({
2002
+ ...activity,
2003
+ createdAt: new Date(activity.createdAt)
2004
+ }));
2005
+ return {
2006
+ ...data,
2007
+ notifiedAt,
2008
+ readAt,
2009
+ activities
2010
+ };
1818
2011
  }
1819
- return resolvedUsers;
2012
+ return {
2013
+ ...data,
2014
+ notifiedAt,
2015
+ readAt
2016
+ };
1820
2017
  }
1821
- var htmlEscapables = {
1822
- "&": "&",
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)], []);
2018
+ function convertToThreadDeleteInfo(data) {
2019
+ const deletedAt = new Date(data.deletedAt);
2020
+ return {
2021
+ ...data,
2022
+ deletedAt
2023
+ };
1834
2024
  }
1835
- function joinHtml(strings) {
1836
- if (strings.length <= 0) {
1837
- return new HtmlSafeString([""], []);
1838
- }
1839
- return new HtmlSafeString(
1840
- ["", ...Array(strings.length - 1).fill(""), ""],
1841
- strings
1842
- );
2025
+ function convertToInboxNotificationDeleteInfo(data) {
2026
+ const deletedAt = new Date(data.deletedAt);
2027
+ return {
2028
+ ...data,
2029
+ deletedAt
2030
+ };
1843
2031
  }
1844
- function escapeHtml(value) {
1845
- if (value instanceof HtmlSafeString) {
1846
- return value.toString();
1847
- }
1848
- if (Array.isArray(value)) {
1849
- return joinHtml(value).toString();
2032
+
2033
+ // src/lib/url.ts
2034
+ function toURLSearchParams(params) {
2035
+ const result = new URLSearchParams();
2036
+ for (const [key, value] of Object.entries(params)) {
2037
+ if (value !== void 0 && value !== null) {
2038
+ result.set(key, value.toString());
2039
+ }
1850
2040
  }
1851
- return String(value).replace(
1852
- htmlEscapablesRegex,
1853
- (character) => htmlEscapables[character]
1854
- );
2041
+ return result;
1855
2042
  }
1856
- var HtmlSafeString = class {
1857
- constructor(strings, values) {
1858
- this._strings = strings;
1859
- this._values = values;
2043
+ function urljoin(baseUrl, path, params) {
2044
+ const url = new URL(path, baseUrl);
2045
+ if (params !== void 0) {
2046
+ url.search = (params instanceof URLSearchParams ? params : toURLSearchParams(params)).toString();
1860
2047
  }
1861
- toString() {
1862
- return this._strings.reduce((result, str, i) => {
1863
- return result + escapeHtml(nn(this._values[i - 1])) + str;
2048
+ return url.toString();
2049
+ }
2050
+
2051
+ // src/notifications.ts
2052
+ var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY = 50;
2053
+ function createNotificationsApi({
2054
+ baseUrl,
2055
+ authManager,
2056
+ currentUserIdStore,
2057
+ fetcher
2058
+ }) {
2059
+ async function fetchJson(endpoint, options, params) {
2060
+ const authValue = await authManager.getAuthValue({
2061
+ requestedScope: "comments:read"
1864
2062
  });
1865
- }
1866
- };
1867
- function html(strings, ...values) {
1868
- return new HtmlSafeString(strings, values);
1869
- }
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([""], []);
1892
- }
1893
- return new MarkdownSafeString(
1894
- ["", ...Array(strings.length - 1).fill(""), ""],
1895
- strings
1896
- );
1897
- }
1898
- function escapeMarkdown(value) {
1899
- if (value instanceof MarkdownSafeString) {
1900
- return value.toString();
1901
- }
1902
- if (Array.isArray(value)) {
1903
- return joinMarkdown(value).toString();
1904
- }
1905
- return String(value).replace(
1906
- markdownEscapablesRegex,
1907
- (character) => markdownEscapables[character]
1908
- );
1909
- }
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
- });
1919
- }
1920
- };
1921
- function markdown(strings, ...values) {
1922
- return new MarkdownSafeString(strings, values);
1923
- }
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;
1929
- }
1930
- return;
1931
- }
1932
- var stringifyCommentBodyPlainElements = {
1933
- paragraph: ({ children }) => children,
1934
- text: ({ element }) => element.text,
1935
- link: ({ element }) => element.url,
1936
- mention: ({ element, user }) => {
1937
- return `@${_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>`;
1957
- }
1958
- if (element.code) {
1959
- children = html`<code>${children}</code>`;
1960
- }
1961
- return children;
1962
- },
1963
- link: ({ element, href }) => {
1964
- return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
1965
- },
1966
- mention: ({ element, user }) => {
1967
- return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _49 => _49.name]), () => ( element.id))}</span>`;
1968
- }
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}**`;
2063
+ if (authValue.type === "secret" && authValue.token.parsed.k === "acc" /* ACCESS_TOKEN */) {
2064
+ const userId = authValue.token.parsed.uid;
2065
+ currentUserIdStore.set(() => userId);
1981
2066
  }
1982
- if (element.italic) {
1983
- children = markdown`_${children}_`;
1984
- }
1985
- if (element.strikethrough) {
1986
- children = markdown`~~${children}~~`;
1987
- }
1988
- if (element.code) {
1989
- children = markdown`\`${children}\``;
1990
- }
1991
- return children;
1992
- },
1993
- link: ({ element, href }) => {
1994
- return markdown`[${element.url}](${href})`;
1995
- },
1996
- mention: ({ element, user }) => {
1997
- return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _50 => _50.name]), () => ( element.id))}`;
1998
- }
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])
2010
- );
2011
- const blocks = body.content.flatMap((block, blockIndex) => {
2012
- switch (block.type) {
2013
- case "paragraph": {
2014
- const inlines = block.children.flatMap((inline, inlineIndex) => {
2015
- if (isCommentBodyMention(inline)) {
2016
- return inline.id ? [
2017
- elements.mention(
2018
- {
2019
- element: inline,
2020
- user: resolvedUsers.get(inline.id)
2021
- },
2022
- inlineIndex
2023
- )
2024
- ] : [];
2025
- }
2026
- if (isCommentBodyLink(inline)) {
2027
- return [
2028
- elements.link(
2029
- {
2030
- element: inline,
2031
- href: _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
- ];
2067
+ const url = urljoin(baseUrl, `/v2/c${endpoint}`, params);
2068
+ const response = await fetcher(url.toString(), {
2069
+ ...options,
2070
+ headers: {
2071
+ ..._optionalChain([options, 'optionalAccess', _47 => _47.headers]),
2072
+ Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
2048
2073
  }
2049
- default:
2050
- return [];
2051
- }
2052
- });
2053
- return blocks.join(separator);
2054
- }
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
- }
2079
- }
2080
- function convertToThreadData(data) {
2081
- const updatedAt = data.updatedAt ? new Date(data.updatedAt) : void 0;
2082
- const createdAt = new Date(data.createdAt);
2083
- const comments = data.comments.map(
2084
- (comment) => convertToCommentData(comment)
2085
- );
2086
- return {
2087
- ...data,
2088
- createdAt,
2089
- updatedAt,
2090
- comments
2091
- };
2092
- }
2093
- function convertToCommentUserReaction(data) {
2094
- return {
2095
- ...data,
2096
- createdAt: new Date(data.createdAt)
2097
- };
2098
- }
2099
-
2100
- // src/comments/index.ts
2101
- function getAuthBearerHeaderFromAuthValue(authValue) {
2102
- if (authValue.type === "public") {
2103
- return authValue.publicApiKey;
2104
- } else {
2105
- return authValue.token.raw;
2106
- }
2107
- }
2108
- var CommentsApiError = class extends Error {
2109
- constructor(message, status, details) {
2110
- super(message);
2111
- this.message = message;
2112
- this.status = status;
2113
- this.details = details;
2114
- }
2115
- };
2116
- function createCommentsApi(roomId, getAuthValue, config) {
2117
- async function fetchJson(endpoint, options) {
2118
- const response = await fetchApi(roomId, endpoint, options);
2074
+ });
2119
2075
  if (!response.ok) {
2120
2076
  if (response.status >= 400 && response.status < 600) {
2121
2077
  let error3;
2122
2078
  try {
2123
2079
  const errorBody = await response.json();
2124
- error3 = new CommentsApiError(
2080
+ error3 = new NotificationsApiError(
2125
2081
  errorBody.message,
2126
2082
  response.status,
2127
2083
  errorBody
2128
2084
  );
2129
2085
  } catch (e3) {
2130
- error3 = new CommentsApiError(response.statusText, response.status);
2086
+ error3 = new NotificationsApiError(
2087
+ response.statusText,
2088
+ response.status
2089
+ );
2131
2090
  }
2132
2091
  throw error3;
2133
2092
  }
@@ -2140,175 +2099,65 @@ function createCommentsApi(roomId, getAuthValue, config) {
2140
2099
  }
2141
2100
  return body;
2142
2101
  }
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
- }
2102
+ async function getInboxNotifications(options) {
2103
+ const json = await fetchJson("/inbox-notifications", void 0, {
2104
+ limit: _optionalChain([options, 'optionalAccess', _48 => _48.limit]),
2105
+ since: _optionalChain([options, 'optionalAccess', _49 => _49.since, 'optionalAccess', _50 => _50.toISOString, 'call', _51 => _51()])
2155
2106
  });
2156
- }
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.");
2174
- }
2175
- }
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
- })
2197
- }
2198
- );
2199
- return convertToThreadData(thread);
2200
- }
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)
2213
- }
2214
- );
2215
- }
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
- })
2107
+ return {
2108
+ threads: json.threads.map((thread) => convertToThreadData(thread)),
2109
+ inboxNotifications: json.inboxNotifications.map(
2110
+ (notification) => convertToInboxNotificationData(notification)
2111
+ ),
2112
+ deletedThreads: json.deletedThreads.map(
2113
+ (info) => convertToThreadDeleteInfo(info)
2114
+ ),
2115
+ deletedInboxNotifications: json.deletedInboxNotifications.map(
2116
+ (info) => convertToInboxNotificationDeleteInfo(info)
2117
+ ),
2118
+ meta: {
2119
+ requestedAt: new Date(json.meta.requestedAt)
2232
2120
  }
2233
- );
2234
- return convertToCommentData(comment);
2121
+ };
2235
2122
  }
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
- })
2253
- }
2254
- );
2255
- return convertToCommentData(comment);
2123
+ async function getUnreadInboxNotificationsCount() {
2124
+ const { count } = await fetchJson("/inbox-notifications/count");
2125
+ return count;
2256
2126
  }
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"
2267
- }
2268
- );
2127
+ async function markAllInboxNotificationsAsRead() {
2128
+ await fetchJson("/inbox-notifications/read", {
2129
+ method: "POST",
2130
+ headers: {
2131
+ "Content-Type": "application/json"
2132
+ },
2133
+ body: JSON.stringify({ inboxNotificationIds: "all" })
2134
+ });
2269
2135
  }
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 })
2285
- }
2286
- );
2287
- return convertToCommentUserReaction(reaction);
2136
+ async function markInboxNotificationsAsRead(inboxNotificationIds) {
2137
+ await fetchJson("/inbox-notifications/read", {
2138
+ method: "POST",
2139
+ headers: {
2140
+ "Content-Type": "application/json"
2141
+ },
2142
+ body: JSON.stringify({ inboxNotificationIds })
2143
+ });
2288
2144
  }
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"
2300
- }
2301
- );
2145
+ const batchedMarkInboxNotificationsAsRead = new Batch(
2146
+ async (batchedInboxNotificationIds) => {
2147
+ const inboxNotificationIds = batchedInboxNotificationIds.flat();
2148
+ await markInboxNotificationsAsRead(inboxNotificationIds);
2149
+ return inboxNotificationIds;
2150
+ },
2151
+ { delay: MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY }
2152
+ );
2153
+ async function markInboxNotificationAsRead(inboxNotificationId) {
2154
+ await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
2302
2155
  }
2303
2156
  return {
2304
- getThreads,
2305
- createThread,
2306
- editThreadMetadata,
2307
- createComment,
2308
- editComment,
2309
- deleteComment,
2310
- addReaction,
2311
- removeReaction
2157
+ getInboxNotifications,
2158
+ getUnreadInboxNotificationsCount,
2159
+ markAllInboxNotificationsAsRead,
2160
+ markInboxNotificationAsRead
2312
2161
  };
2313
2162
  }
2314
2163
 
@@ -2452,6 +2301,14 @@ var OpCode = /* @__PURE__ */ ((OpCode2) => {
2452
2301
  OpCode2[OpCode2["CREATE_REGISTER"] = 8] = "CREATE_REGISTER";
2453
2302
  return OpCode2;
2454
2303
  })(OpCode || {});
2304
+ function ackOp(opId) {
2305
+ return {
2306
+ type: 5 /* DELETE_CRDT */,
2307
+ id: "ACK",
2308
+ // (H)ACK
2309
+ opId
2310
+ };
2311
+ }
2455
2312
  function isAckOp(op) {
2456
2313
  return op.type === 5 /* DELETE_CRDT */ && op.id === "ACK";
2457
2314
  }
@@ -2677,7 +2534,7 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
2677
2534
  return [
2678
2535
  {
2679
2536
  type: 8 /* CREATE_REGISTER */,
2680
- opId: _optionalChain([pool, 'optionalAccess', _58 => _58.generateOpId, 'call', _59 => _59()]),
2537
+ opId: _optionalChain([pool, 'optionalAccess', _52 => _52.generateOpId, 'call', _53 => _53()]),
2681
2538
  id: this._id,
2682
2539
  parentId,
2683
2540
  parentKey,
@@ -2779,7 +2636,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2779
2636
  const ops = [];
2780
2637
  const op = {
2781
2638
  id: this._id,
2782
- opId: _optionalChain([pool, 'optionalAccess', _60 => _60.generateOpId, 'call', _61 => _61()]),
2639
+ opId: _optionalChain([pool, 'optionalAccess', _54 => _54.generateOpId, 'call', _55 => _55()]),
2783
2640
  type: 2 /* CREATE_LIST */,
2784
2641
  parentId,
2785
2642
  parentKey
@@ -3056,7 +2913,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3056
2913
  _applyInsertUndoRedo(op) {
3057
2914
  const { id, parentKey: key } = op;
3058
2915
  const child = creationOpToLiveNode(op);
3059
- if (_optionalChain([this, 'access', _62 => _62._pool, 'optionalAccess', _63 => _63.getNode, 'call', _64 => _64(id)]) !== void 0) {
2916
+ if (_optionalChain([this, 'access', _56 => _56._pool, 'optionalAccess', _57 => _57.getNode, 'call', _58 => _58(id)]) !== void 0) {
3060
2917
  return { modified: false };
3061
2918
  }
3062
2919
  child._attach(id, nn(this._pool));
@@ -3064,8 +2921,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
3064
2921
  const existingItemIndex = this._indexOfPosition(key);
3065
2922
  let newKey = key;
3066
2923
  if (existingItemIndex !== -1) {
3067
- const before2 = _optionalChain([this, 'access', _65 => _65._items, 'access', _66 => _66[existingItemIndex], 'optionalAccess', _67 => _67._parentPos]);
3068
- const after2 = _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]);
2924
+ const before2 = _optionalChain([this, 'access', _59 => _59._items, 'access', _60 => _60[existingItemIndex], 'optionalAccess', _61 => _61._parentPos]);
2925
+ const after2 = _optionalChain([this, 'access', _62 => _62._items, 'access', _63 => _63[existingItemIndex + 1], 'optionalAccess', _64 => _64._parentPos]);
3069
2926
  newKey = makePosition(before2, after2);
3070
2927
  child._setParentLink(this, newKey);
3071
2928
  }
@@ -3080,7 +2937,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3080
2937
  _applySetUndoRedo(op) {
3081
2938
  const { id, parentKey: key } = op;
3082
2939
  const child = creationOpToLiveNode(op);
3083
- if (_optionalChain([this, 'access', _71 => _71._pool, 'optionalAccess', _72 => _72.getNode, 'call', _73 => _73(id)]) !== void 0) {
2940
+ if (_optionalChain([this, 'access', _65 => _65._pool, 'optionalAccess', _66 => _66.getNode, 'call', _67 => _67(id)]) !== void 0) {
3084
2941
  return { modified: false };
3085
2942
  }
3086
2943
  this._unacknowledgedSets.set(key, nn(op.opId));
@@ -3202,7 +3059,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3202
3059
  } else {
3203
3060
  this._items[existingItemIndex]._setParentLink(
3204
3061
  this,
3205
- makePosition(newKey, _optionalChain([this, 'access', _74 => _74._items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]))
3062
+ makePosition(newKey, _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]))
3206
3063
  );
3207
3064
  const previousIndex = this._items.indexOf(child);
3208
3065
  child._setParentLink(this, newKey);
@@ -3228,7 +3085,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3228
3085
  if (existingItemIndex !== -1) {
3229
3086
  this._items[existingItemIndex]._setParentLink(
3230
3087
  this,
3231
- makePosition(newKey, _optionalChain([this, 'access', _77 => _77._items, 'access', _78 => _78[existingItemIndex + 1], 'optionalAccess', _79 => _79._parentPos]))
3088
+ makePosition(newKey, _optionalChain([this, 'access', _71 => _71._items, 'access', _72 => _72[existingItemIndex + 1], 'optionalAccess', _73 => _73._parentPos]))
3232
3089
  );
3233
3090
  }
3234
3091
  child._setParentLink(this, newKey);
@@ -3247,7 +3104,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3247
3104
  if (existingItemIndex !== -1) {
3248
3105
  this._items[existingItemIndex]._setParentLink(
3249
3106
  this,
3250
- makePosition(newKey, _optionalChain([this, 'access', _80 => _80._items, 'access', _81 => _81[existingItemIndex + 1], 'optionalAccess', _82 => _82._parentPos]))
3107
+ makePosition(newKey, _optionalChain([this, 'access', _74 => _74._items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]))
3251
3108
  );
3252
3109
  }
3253
3110
  child._setParentLink(this, newKey);
@@ -3275,7 +3132,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3275
3132
  if (existingItemIndex !== -1) {
3276
3133
  this._items[existingItemIndex]._setParentLink(
3277
3134
  this,
3278
- makePosition(newKey, _optionalChain([this, 'access', _83 => _83._items, 'access', _84 => _84[existingItemIndex + 1], 'optionalAccess', _85 => _85._parentPos]))
3135
+ makePosition(newKey, _optionalChain([this, 'access', _77 => _77._items, 'access', _78 => _78[existingItemIndex + 1], 'optionalAccess', _79 => _79._parentPos]))
3279
3136
  );
3280
3137
  }
3281
3138
  child._setParentLink(this, newKey);
@@ -3333,7 +3190,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3333
3190
  * @param element The element to add to the end of the LiveList.
3334
3191
  */
3335
3192
  push(element) {
3336
- _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
3193
+ _optionalChain([this, 'access', _80 => _80._pool, 'optionalAccess', _81 => _81.assertStorageIsWritable, 'call', _82 => _82()]);
3337
3194
  return this.insert(element, this.length);
3338
3195
  }
3339
3196
  /**
@@ -3342,7 +3199,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3342
3199
  * @param index The index at which you want to insert the element.
3343
3200
  */
3344
3201
  insert(element, index) {
3345
- _optionalChain([this, 'access', _89 => _89._pool, 'optionalAccess', _90 => _90.assertStorageIsWritable, 'call', _91 => _91()]);
3202
+ _optionalChain([this, 'access', _83 => _83._pool, 'optionalAccess', _84 => _84.assertStorageIsWritable, 'call', _85 => _85()]);
3346
3203
  if (index < 0 || index > this._items.length) {
3347
3204
  throw new Error(
3348
3205
  `Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
@@ -3372,7 +3229,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3372
3229
  * @param targetIndex The index where the element should be after moving.
3373
3230
  */
3374
3231
  move(index, targetIndex) {
3375
- _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
3232
+ _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
3376
3233
  if (targetIndex < 0) {
3377
3234
  throw new Error("targetIndex cannot be less than 0");
3378
3235
  }
@@ -3430,7 +3287,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3430
3287
  * @param index The index of the element to delete
3431
3288
  */
3432
3289
  delete(index) {
3433
- _optionalChain([this, 'access', _95 => _95._pool, 'optionalAccess', _96 => _96.assertStorageIsWritable, 'call', _97 => _97()]);
3290
+ _optionalChain([this, 'access', _89 => _89._pool, 'optionalAccess', _90 => _90.assertStorageIsWritable, 'call', _91 => _91()]);
3434
3291
  if (index < 0 || index >= this._items.length) {
3435
3292
  throw new Error(
3436
3293
  `Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -3463,7 +3320,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3463
3320
  }
3464
3321
  }
3465
3322
  clear() {
3466
- _optionalChain([this, 'access', _98 => _98._pool, 'optionalAccess', _99 => _99.assertStorageIsWritable, 'call', _100 => _100()]);
3323
+ _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
3467
3324
  if (this._pool) {
3468
3325
  const ops = [];
3469
3326
  const reverseOps = [];
@@ -3497,7 +3354,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3497
3354
  }
3498
3355
  }
3499
3356
  set(index, item) {
3500
- _optionalChain([this, 'access', _101 => _101._pool, 'optionalAccess', _102 => _102.assertStorageIsWritable, 'call', _103 => _103()]);
3357
+ _optionalChain([this, 'access', _95 => _95._pool, 'optionalAccess', _96 => _96.assertStorageIsWritable, 'call', _97 => _97()]);
3501
3358
  if (index < 0 || index >= this._items.length) {
3502
3359
  throw new Error(
3503
3360
  `Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -3645,7 +3502,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3645
3502
  _shiftItemPosition(index, key) {
3646
3503
  const shiftedPosition = makePosition(
3647
3504
  key,
3648
- this._items.length > index + 1 ? _optionalChain([this, 'access', _104 => _104._items, 'access', _105 => _105[index + 1], 'optionalAccess', _106 => _106._parentPos]) : void 0
3505
+ this._items.length > index + 1 ? _optionalChain([this, 'access', _98 => _98._items, 'access', _99 => _99[index + 1], 'optionalAccess', _100 => _100._parentPos]) : void 0
3649
3506
  );
3650
3507
  this._items[index]._setParentLink(this, shiftedPosition);
3651
3508
  }
@@ -3774,7 +3631,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3774
3631
  const ops = [];
3775
3632
  const op = {
3776
3633
  id: this._id,
3777
- opId: _optionalChain([pool, 'optionalAccess', _107 => _107.generateOpId, 'call', _108 => _108()]),
3634
+ opId: _optionalChain([pool, 'optionalAccess', _101 => _101.generateOpId, 'call', _102 => _102()]),
3778
3635
  type: 7 /* CREATE_MAP */,
3779
3636
  parentId,
3780
3637
  parentKey
@@ -3921,7 +3778,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3921
3778
  * @param value The value of the element to add. Should be serializable to JSON.
3922
3779
  */
3923
3780
  set(key, value) {
3924
- _optionalChain([this, 'access', _109 => _109._pool, 'optionalAccess', _110 => _110.assertStorageIsWritable, 'call', _111 => _111()]);
3781
+ _optionalChain([this, 'access', _103 => _103._pool, 'optionalAccess', _104 => _104.assertStorageIsWritable, 'call', _105 => _105()]);
3925
3782
  const oldValue = this._map.get(key);
3926
3783
  if (oldValue) {
3927
3784
  oldValue._detach();
@@ -3967,7 +3824,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3967
3824
  * @returns true if an element existed and has been removed, or false if the element does not exist.
3968
3825
  */
3969
3826
  delete(key) {
3970
- _optionalChain([this, 'access', _112 => _112._pool, 'optionalAccess', _113 => _113.assertStorageIsWritable, 'call', _114 => _114()]);
3827
+ _optionalChain([this, 'access', _106 => _106._pool, 'optionalAccess', _107 => _107.assertStorageIsWritable, 'call', _108 => _108()]);
3971
3828
  const item = this._map.get(key);
3972
3829
  if (item === void 0) {
3973
3830
  return false;
@@ -4100,15 +3957,14 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4100
3957
  constructor(obj = {}) {
4101
3958
  super();
4102
3959
  this._propToLastUpdate = /* @__PURE__ */ new Map();
4103
- for (const key in obj) {
4104
- const value = obj[key];
4105
- if (value === void 0) {
4106
- continue;
4107
- } else if (isLiveNode(value)) {
3960
+ const o = compactObject(obj);
3961
+ for (const key of Object.keys(o)) {
3962
+ const value = o[key];
3963
+ if (isLiveNode(value)) {
4108
3964
  value._setParentLink(this, key);
4109
3965
  }
4110
3966
  }
4111
- this._map = new Map(Object.entries(obj));
3967
+ this._map = new Map(Object.entries(o));
4112
3968
  }
4113
3969
  /** @internal */
4114
3970
  static _buildRootAndParentToChildren(items) {
@@ -4146,7 +4002,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4146
4002
  if (this._id === void 0) {
4147
4003
  throw new Error("Cannot serialize item is not attached");
4148
4004
  }
4149
- const opId = _optionalChain([pool, 'optionalAccess', _115 => _115.generateOpId, 'call', _116 => _116()]);
4005
+ const opId = _optionalChain([pool, 'optionalAccess', _109 => _109.generateOpId, 'call', _110 => _110()]);
4150
4006
  const ops = [];
4151
4007
  const op = {
4152
4008
  type: 4 /* CREATE_OBJECT */,
@@ -4424,7 +4280,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4424
4280
  * @param value The value of the property to add
4425
4281
  */
4426
4282
  set(key, value) {
4427
- _optionalChain([this, 'access', _117 => _117._pool, 'optionalAccess', _118 => _118.assertStorageIsWritable, 'call', _119 => _119()]);
4283
+ _optionalChain([this, 'access', _111 => _111._pool, 'optionalAccess', _112 => _112.assertStorageIsWritable, 'call', _113 => _113()]);
4428
4284
  this.update({ [key]: value });
4429
4285
  }
4430
4286
  /**
@@ -4439,7 +4295,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4439
4295
  * @param key The key of the property to delete
4440
4296
  */
4441
4297
  delete(key) {
4442
- _optionalChain([this, 'access', _120 => _120._pool, 'optionalAccess', _121 => _121.assertStorageIsWritable, 'call', _122 => _122()]);
4298
+ _optionalChain([this, 'access', _114 => _114._pool, 'optionalAccess', _115 => _115.assertStorageIsWritable, 'call', _116 => _116()]);
4443
4299
  const keyAsString = key;
4444
4300
  const oldValue = this._map.get(keyAsString);
4445
4301
  if (oldValue === void 0) {
@@ -4492,7 +4348,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4492
4348
  * @param patch The object used to overrides properties
4493
4349
  */
4494
4350
  update(patch) {
4495
- _optionalChain([this, 'access', _123 => _123._pool, 'optionalAccess', _124 => _124.assertStorageIsWritable, 'call', _125 => _125()]);
4351
+ _optionalChain([this, 'access', _117 => _117._pool, 'optionalAccess', _118 => _118.assertStorageIsWritable, 'call', _119 => _119()]);
4496
4352
  if (this._pool === void 0 || this._id === void 0) {
4497
4353
  for (const key in patch) {
4498
4354
  const newValue = patch[key];
@@ -4886,6 +4742,115 @@ function isJsonObject(data) {
4886
4742
  return !isJsonScalar(data) && !isJsonArray(data);
4887
4743
  }
4888
4744
 
4745
+ // src/lib/objectToQuery.ts
4746
+ var identifierRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
4747
+ function objectToQuery(obj) {
4748
+ let filterList = [];
4749
+ const entries2 = Object.entries(obj);
4750
+ const keyValuePairs = [];
4751
+ const keyValuePairsWithOperator = [];
4752
+ const indexedKeys = [];
4753
+ entries2.forEach(([key, value]) => {
4754
+ if (!identifierRegex.test(key)) {
4755
+ throw new Error("Key must only contain letters, numbers, _");
4756
+ }
4757
+ if (isSimpleValue(value)) {
4758
+ keyValuePairs.push([key, value]);
4759
+ } else if (isValueWithOperator(value)) {
4760
+ keyValuePairsWithOperator.push([key, value]);
4761
+ } else if (typeof value === "object" && !("startsWith" in value)) {
4762
+ indexedKeys.push([key, value]);
4763
+ }
4764
+ });
4765
+ filterList = [
4766
+ ...getFiltersFromKeyValuePairs(keyValuePairs),
4767
+ ...getFiltersFromKeyValuePairsWithOperator(keyValuePairsWithOperator)
4768
+ ];
4769
+ indexedKeys.forEach(([key, value]) => {
4770
+ const nestedEntries = Object.entries(value);
4771
+ const nKeyValuePairs = [];
4772
+ const nKeyValuePairsWithOperator = [];
4773
+ nestedEntries.forEach(([nestedKey, nestedValue]) => {
4774
+ if (isStringEmpty(nestedKey)) {
4775
+ throw new Error("Key cannot be empty");
4776
+ }
4777
+ if (isSimpleValue(nestedValue)) {
4778
+ nKeyValuePairs.push([formatFilterKey(key, nestedKey), nestedValue]);
4779
+ } else if (isValueWithOperator(nestedValue)) {
4780
+ nKeyValuePairsWithOperator.push([
4781
+ formatFilterKey(key, nestedKey),
4782
+ nestedValue
4783
+ ]);
4784
+ }
4785
+ });
4786
+ filterList = [
4787
+ ...filterList,
4788
+ ...getFiltersFromKeyValuePairs(nKeyValuePairs),
4789
+ ...getFiltersFromKeyValuePairsWithOperator(nKeyValuePairsWithOperator)
4790
+ ];
4791
+ });
4792
+ return filterList.map(
4793
+ ({ key, operator, value }) => formatFilter(key, operator, formatFilterValue(value))
4794
+ ).join(" AND ");
4795
+ }
4796
+ var getFiltersFromKeyValuePairs = (keyValuePairs) => {
4797
+ const filters = [];
4798
+ keyValuePairs.forEach(([key, value]) => {
4799
+ filters.push({
4800
+ key,
4801
+ operator: ":",
4802
+ value
4803
+ });
4804
+ });
4805
+ return filters;
4806
+ };
4807
+ var getFiltersFromKeyValuePairsWithOperator = (keyValuePairsWithOperator) => {
4808
+ const filters = [];
4809
+ keyValuePairsWithOperator.forEach(([key, value]) => {
4810
+ if ("startsWith" in value && typeof value.startsWith === "string") {
4811
+ filters.push({
4812
+ key,
4813
+ operator: "^",
4814
+ value: value.startsWith
4815
+ });
4816
+ }
4817
+ });
4818
+ return filters;
4819
+ };
4820
+ var isSimpleValue = (value) => {
4821
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4822
+ return true;
4823
+ }
4824
+ return false;
4825
+ };
4826
+ var isValueWithOperator = (value) => {
4827
+ if (typeof value === "object" && value !== null && "startsWith" in value) {
4828
+ return true;
4829
+ }
4830
+ return false;
4831
+ };
4832
+ var formatFilter = (key, operator, value) => {
4833
+ return `${key}${operator}${value}`;
4834
+ };
4835
+ var formatFilterKey = (key, nestedKey) => {
4836
+ if (nestedKey) {
4837
+ return `${key}[${JSON.stringify(nestedKey)}]`;
4838
+ }
4839
+ return key;
4840
+ };
4841
+ var formatFilterValue = (value) => {
4842
+ if (typeof value === "string") {
4843
+ if (isStringEmpty(value)) {
4844
+ throw new Error("Value cannot be empty");
4845
+ }
4846
+ return JSON.stringify(value);
4847
+ }
4848
+ return value.toString();
4849
+ };
4850
+ var isStringEmpty = (value) => {
4851
+ return !value || value.toString().trim() === "";
4852
+ };
4853
+
4889
4854
  // src/protocol/ClientMsg.ts
4890
4855
  var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
4891
4856
  ClientMsgCode2[ClientMsgCode2["UPDATE_PRESENCE"] = 100] = "UPDATE_PRESENCE";
@@ -5129,69 +5094,315 @@ function userToTreeNode(key, user) {
5129
5094
  type: "User",
5130
5095
  id: `${user.connectionId}`,
5131
5096
  key,
5132
- payload: user
5097
+ payload: {
5098
+ connectionId: user.connectionId,
5099
+ id: user.id,
5100
+ info: user.info,
5101
+ presence: user.presence,
5102
+ isReadOnly: !user.canWrite
5103
+ }
5133
5104
  };
5134
5105
  }
5135
5106
  function installBackgroundTabSpy() {
5136
5107
  const doc = typeof document !== "undefined" ? document : void 0;
5137
5108
  const inBackgroundSince = { current: null };
5138
5109
  function onVisibilityChange() {
5139
- if (_optionalChain([doc, 'optionalAccess', _126 => _126.visibilityState]) === "hidden") {
5110
+ if (_optionalChain([doc, 'optionalAccess', _120 => _120.visibilityState]) === "hidden") {
5140
5111
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
5141
5112
  } else {
5142
5113
  inBackgroundSince.current = null;
5143
5114
  }
5144
5115
  }
5145
- _optionalChain([doc, 'optionalAccess', _127 => _127.addEventListener, 'call', _128 => _128("visibilitychange", onVisibilityChange)]);
5116
+ _optionalChain([doc, 'optionalAccess', _121 => _121.addEventListener, 'call', _122 => _122("visibilitychange", onVisibilityChange)]);
5146
5117
  const unsub = () => {
5147
- _optionalChain([doc, 'optionalAccess', _129 => _129.removeEventListener, 'call', _130 => _130("visibilitychange", onVisibilityChange)]);
5118
+ _optionalChain([doc, 'optionalAccess', _123 => _123.removeEventListener, 'call', _124 => _124("visibilitychange", onVisibilityChange)]);
5148
5119
  };
5149
5120
  return [inBackgroundSince, unsub];
5150
5121
  }
5151
- function createRoom(options, config) {
5152
- const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
5153
- const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
5154
- const [inBackgroundSince, uninstallBgTabSpy] = installBackgroundTabSpy();
5155
- const delegates = {
5156
- ...config.delegates,
5157
- // A connection is allowed to go into "zombie state" only if all of the
5158
- // following conditions apply:
5159
- //
5160
- // - The `backgroundKeepAliveTimeout` client option is configured
5161
- // - The browser window has been in the background for at least
5162
- // `backgroundKeepAliveTimeout` milliseconds
5163
- // - There are no pending changes
5164
- //
5165
- canZombie() {
5166
- return config.backgroundKeepAliveTimeout !== void 0 && inBackgroundSince.current !== null && Date.now() > inBackgroundSince.current + config.backgroundKeepAliveTimeout && getStorageStatus() !== "synchronizing";
5167
- }
5168
- };
5169
- const managedSocket = new ManagedSocket(
5170
- delegates,
5171
- config.enableDebugLogging
5172
- );
5173
- const context = {
5174
- buffer: {
5175
- flushTimerID: void 0,
5176
- lastFlushedAt: 0,
5177
- presenceUpdates: (
5178
- // Queue up the initial presence message as a Full Presence™ update
5179
- {
5180
- type: "full",
5181
- data: initialPresence
5122
+ var CommentsApiError = class extends Error {
5123
+ constructor(message, status, details) {
5124
+ super(message);
5125
+ this.message = message;
5126
+ this.status = status;
5127
+ this.details = details;
5128
+ }
5129
+ };
5130
+ function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
5131
+ async function fetchCommentsApi(endpoint, params, options) {
5132
+ const authValue = await getAuthValue();
5133
+ return fetchClientApi(roomId, endpoint, authValue, options, params);
5134
+ }
5135
+ async function fetchJson(endpoint, options, params) {
5136
+ const response = await fetchCommentsApi(endpoint, params, options);
5137
+ if (!response.ok) {
5138
+ if (response.status >= 400 && response.status < 600) {
5139
+ let error3;
5140
+ try {
5141
+ const errorBody = await response.json();
5142
+ error3 = new CommentsApiError(
5143
+ errorBody.message,
5144
+ response.status,
5145
+ errorBody
5146
+ );
5147
+ } catch (e5) {
5148
+ error3 = new CommentsApiError(response.statusText, response.status);
5182
5149
  }
5183
- ),
5184
- messages: [],
5185
- storageOperations: []
5186
- },
5187
- staticSessionInfo: new ValueRef(null),
5188
- dynamicSessionInfo: new ValueRef(null),
5189
- myPresence: new PatchableRef(initialPresence),
5190
- others: new OthersRef(),
5191
- initialStorage,
5192
- idFactory: null,
5193
- // Storage
5194
- clock: 0,
5150
+ throw error3;
5151
+ }
5152
+ }
5153
+ let body;
5154
+ try {
5155
+ body = await response.json();
5156
+ } catch (e6) {
5157
+ body = {};
5158
+ }
5159
+ return body;
5160
+ }
5161
+ async function getThreads(options) {
5162
+ let query;
5163
+ if (_optionalChain([options, 'optionalAccess', _125 => _125.query])) {
5164
+ query = objectToQuery(options.query);
5165
+ }
5166
+ const response = await fetchCommentsApi(
5167
+ "/threads",
5168
+ {
5169
+ since: _optionalChain([options, 'optionalAccess', _126 => _126.since, 'optionalAccess', _127 => _127.toISOString, 'call', _128 => _128()]),
5170
+ query
5171
+ },
5172
+ {
5173
+ headers: {
5174
+ "Content-Type": "application/json"
5175
+ }
5176
+ }
5177
+ );
5178
+ if (response.ok) {
5179
+ const json = await response.json();
5180
+ return {
5181
+ threads: json.data.map((thread) => convertToThreadData(thread)),
5182
+ inboxNotifications: json.inboxNotifications.map(
5183
+ (notification) => convertToInboxNotificationData(notification)
5184
+ ),
5185
+ deletedThreads: json.deletedThreads.map(
5186
+ (info) => convertToThreadDeleteInfo(info)
5187
+ ),
5188
+ deletedInboxNotifications: json.deletedInboxNotifications.map(
5189
+ (info) => convertToInboxNotificationDeleteInfo(info)
5190
+ ),
5191
+ meta: {
5192
+ requestedAt: new Date(json.meta.requestedAt)
5193
+ }
5194
+ };
5195
+ } else if (response.status === 404) {
5196
+ return {
5197
+ threads: [],
5198
+ inboxNotifications: [],
5199
+ deletedThreads: [],
5200
+ deletedInboxNotifications: [],
5201
+ meta: {
5202
+ requestedAt: /* @__PURE__ */ new Date()
5203
+ }
5204
+ };
5205
+ } else {
5206
+ throw new Error("There was an error while getting threads.");
5207
+ }
5208
+ }
5209
+ async function getThread({ threadId }) {
5210
+ const response = await fetchCommentsApi(
5211
+ `/thread-with-notification/${threadId}`
5212
+ );
5213
+ if (response.ok) {
5214
+ const json = await response.json();
5215
+ return {
5216
+ thread: convertToThreadData(json.thread),
5217
+ inboxNotification: json.inboxNotification ? convertToInboxNotificationData(json.inboxNotification) : void 0
5218
+ };
5219
+ } else if (response.status === 404) {
5220
+ return;
5221
+ } else {
5222
+ throw new Error(`There was an error while getting thread ${threadId}.`);
5223
+ }
5224
+ }
5225
+ async function createThread({
5226
+ metadata,
5227
+ body,
5228
+ commentId,
5229
+ threadId
5230
+ }) {
5231
+ const thread = await fetchJson("/threads", {
5232
+ method: "POST",
5233
+ headers: {
5234
+ "Content-Type": "application/json"
5235
+ },
5236
+ body: JSON.stringify({
5237
+ id: threadId,
5238
+ comment: {
5239
+ id: commentId,
5240
+ body
5241
+ },
5242
+ metadata
5243
+ })
5244
+ });
5245
+ return convertToThreadData(thread);
5246
+ }
5247
+ async function editThreadMetadata({
5248
+ metadata,
5249
+ threadId
5250
+ }) {
5251
+ return await fetchJson(
5252
+ `/threads/${encodeURIComponent(threadId)}/metadata`,
5253
+ {
5254
+ method: "POST",
5255
+ headers: {
5256
+ "Content-Type": "application/json"
5257
+ },
5258
+ body: JSON.stringify(metadata)
5259
+ }
5260
+ );
5261
+ }
5262
+ async function createComment({
5263
+ threadId,
5264
+ commentId,
5265
+ body
5266
+ }) {
5267
+ const comment = await fetchJson(
5268
+ `/threads/${encodeURIComponent(threadId)}/comments`,
5269
+ {
5270
+ method: "POST",
5271
+ headers: {
5272
+ "Content-Type": "application/json"
5273
+ },
5274
+ body: JSON.stringify({
5275
+ id: commentId,
5276
+ body
5277
+ })
5278
+ }
5279
+ );
5280
+ return convertToCommentData(comment);
5281
+ }
5282
+ async function editComment({
5283
+ threadId,
5284
+ commentId,
5285
+ body
5286
+ }) {
5287
+ const comment = await fetchJson(
5288
+ `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
5289
+ commentId
5290
+ )}`,
5291
+ {
5292
+ method: "POST",
5293
+ headers: {
5294
+ "Content-Type": "application/json"
5295
+ },
5296
+ body: JSON.stringify({
5297
+ body
5298
+ })
5299
+ }
5300
+ );
5301
+ return convertToCommentData(comment);
5302
+ }
5303
+ async function deleteComment2({
5304
+ threadId,
5305
+ commentId
5306
+ }) {
5307
+ await fetchJson(
5308
+ `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
5309
+ commentId
5310
+ )}`,
5311
+ {
5312
+ method: "DELETE"
5313
+ }
5314
+ );
5315
+ }
5316
+ async function addReaction2({
5317
+ threadId,
5318
+ commentId,
5319
+ emoji
5320
+ }) {
5321
+ const reaction = await fetchJson(
5322
+ `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
5323
+ commentId
5324
+ )}/reactions`,
5325
+ {
5326
+ method: "POST",
5327
+ headers: {
5328
+ "Content-Type": "application/json"
5329
+ },
5330
+ body: JSON.stringify({ emoji })
5331
+ }
5332
+ );
5333
+ return convertToCommentUserReaction(reaction);
5334
+ }
5335
+ async function removeReaction2({
5336
+ threadId,
5337
+ commentId,
5338
+ emoji
5339
+ }) {
5340
+ await fetchJson(
5341
+ `/threads/${encodeURIComponent(threadId)}/comments/${encodeURIComponent(
5342
+ commentId
5343
+ )}/reactions/${encodeURIComponent(emoji)}`,
5344
+ {
5345
+ method: "DELETE"
5346
+ }
5347
+ );
5348
+ }
5349
+ return {
5350
+ getThreads,
5351
+ getThread,
5352
+ createThread,
5353
+ editThreadMetadata,
5354
+ createComment,
5355
+ editComment,
5356
+ deleteComment: deleteComment2,
5357
+ addReaction: addReaction2,
5358
+ removeReaction: removeReaction2
5359
+ };
5360
+ }
5361
+ var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY2 = 50;
5362
+ function createRoom(options, config) {
5363
+ const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
5364
+ const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
5365
+ const [inBackgroundSince, uninstallBgTabSpy] = installBackgroundTabSpy();
5366
+ const delegates = {
5367
+ ...config.delegates,
5368
+ // A connection is allowed to go into "zombie state" only if all of the
5369
+ // following conditions apply:
5370
+ //
5371
+ // - The `backgroundKeepAliveTimeout` client option is configured
5372
+ // - The browser window has been in the background for at least
5373
+ // `backgroundKeepAliveTimeout` milliseconds
5374
+ // - There are no pending changes
5375
+ //
5376
+ canZombie() {
5377
+ return config.backgroundKeepAliveTimeout !== void 0 && inBackgroundSince.current !== null && Date.now() > inBackgroundSince.current + config.backgroundKeepAliveTimeout && getStorageStatus() !== "synchronizing";
5378
+ }
5379
+ };
5380
+ const managedSocket = new ManagedSocket(
5381
+ delegates,
5382
+ config.enableDebugLogging
5383
+ );
5384
+ const context = {
5385
+ buffer: {
5386
+ flushTimerID: void 0,
5387
+ lastFlushedAt: 0,
5388
+ presenceUpdates: (
5389
+ // Queue up the initial presence message as a Full Presence™ update
5390
+ {
5391
+ type: "full",
5392
+ data: initialPresence
5393
+ }
5394
+ ),
5395
+ messages: [],
5396
+ storageOperations: []
5397
+ },
5398
+ staticSessionInfo: new ValueRef(null),
5399
+ dynamicSessionInfo: new ValueRef(null),
5400
+ myPresence: new PatchableRef(initialPresence),
5401
+ others: new OthersRef(),
5402
+ initialStorage,
5403
+ idFactory: null,
5404
+ // Storage
5405
+ clock: 0,
5195
5406
  opClock: 0,
5196
5407
  nodes: /* @__PURE__ */ new Map(),
5197
5408
  root: void 0,
@@ -5209,7 +5420,7 @@ function createRoom(options, config) {
5209
5420
  function onStatusDidChange(newStatus) {
5210
5421
  const authValue = managedSocket.authValue;
5211
5422
  if (authValue !== null) {
5212
- const tokenKey = authValue.type === "secret" ? authValue.token.raw : authValue.publicApiKey;
5423
+ const tokenKey = getAuthBearerHeaderFromAuthValue(authValue);
5213
5424
  if (tokenKey !== lastTokenKey) {
5214
5425
  lastTokenKey = tokenKey;
5215
5426
  if (authValue.type === "secret") {
@@ -5312,7 +5523,9 @@ function createRoom(options, config) {
5312
5523
  }
5313
5524
  }
5314
5525
  if (activeBatch) {
5315
- activeBatch.ops.push(...ops);
5526
+ for (const op of ops) {
5527
+ activeBatch.ops.push(op);
5528
+ }
5316
5529
  for (const [key, value] of storageUpdates) {
5317
5530
  activeBatch.updates.storageUpdates.set(
5318
5531
  key,
@@ -5333,7 +5546,7 @@ function createRoom(options, config) {
5333
5546
  }
5334
5547
  },
5335
5548
  assertStorageIsWritable: () => {
5336
- const scopes = _optionalChain([context, 'access', _131 => _131.dynamicSessionInfo, 'access', _132 => _132.current, 'optionalAccess', _133 => _133.scopes]);
5549
+ const scopes = _optionalChain([context, 'access', _129 => _129.dynamicSessionInfo, 'access', _130 => _130.current, 'optionalAccess', _131 => _131.scopes]);
5337
5550
  if (scopes === void 0) {
5338
5551
  return;
5339
5552
  }
@@ -5346,8 +5559,6 @@ function createRoom(options, config) {
5346
5559
  }
5347
5560
  };
5348
5561
  const eventHub = {
5349
- connection: makeEventSource(),
5350
- // Old/deprecated API
5351
5562
  status: makeEventSource(),
5352
5563
  // New/recommended API
5353
5564
  lostConnection: makeEventSource(),
@@ -5363,29 +5574,45 @@ function createRoom(options, config) {
5363
5574
  ydoc: makeEventSource(),
5364
5575
  comments: makeEventSource()
5365
5576
  };
5577
+ async function fetchClientApi(roomId, endpoint, authValue, options2, params) {
5578
+ const url = urljoin(
5579
+ config.baseUrl,
5580
+ `/v2/c/rooms/${encodeURIComponent(roomId)}${endpoint}`,
5581
+ params
5582
+ );
5583
+ const fetcher = _optionalChain([config, 'access', _132 => _132.polyfills, 'optionalAccess', _133 => _133.fetch]) || /* istanbul ignore next */
5584
+ fetch;
5585
+ return await fetcher(url, {
5586
+ ...options2,
5587
+ headers: {
5588
+ ..._optionalChain([options2, 'optionalAccess', _134 => _134.headers]),
5589
+ Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
5590
+ }
5591
+ });
5592
+ }
5593
+ async function streamFetch(authValue, roomId) {
5594
+ return fetchClientApi(roomId, "/storage", authValue, {
5595
+ method: "GET",
5596
+ headers: {
5597
+ "Content-Type": "application/json"
5598
+ }
5599
+ });
5600
+ }
5366
5601
  async function httpPostToRoom(endpoint, body) {
5367
5602
  if (!managedSocket.authValue) {
5368
5603
  throw new Error("Not authorized");
5369
5604
  }
5370
- const authTokenOrPublicApiKey = managedSocket.authValue.type === "public" ? managedSocket.authValue.publicApiKey : managedSocket.authValue.token.raw;
5371
- const url = new URL(
5372
- `/v2/c/rooms/${encodeURIComponent(config.roomId)}${endpoint}`,
5373
- config.baseUrl
5374
- ).toString();
5375
- const fetcher = _optionalChain([config, 'access', _134 => _134.polyfills, 'optionalAccess', _135 => _135.fetch]) || /* istanbul ignore next */
5376
- fetch;
5377
- return fetcher(url, {
5605
+ return fetchClientApi(config.roomId, endpoint, managedSocket.authValue, {
5378
5606
  method: "POST",
5379
5607
  headers: {
5380
- "Content-Type": "application/json",
5381
- Authorization: `Bearer ${authTokenOrPublicApiKey}`
5608
+ "Content-Type": "application/json"
5382
5609
  },
5383
5610
  body: JSON.stringify(body)
5384
5611
  });
5385
5612
  }
5386
5613
  function sendMessages(messages) {
5387
5614
  const serializedPayload = JSON.stringify(messages);
5388
- const nonce = _optionalChain([context, 'access', _136 => _136.dynamicSessionInfo, 'access', _137 => _137.current, 'optionalAccess', _138 => _138.nonce]);
5615
+ const nonce = _optionalChain([context, 'access', _135 => _135.dynamicSessionInfo, 'access', _136 => _136.current, 'optionalAccess', _137 => _137.nonce]);
5389
5616
  if (config.unstable_fallbackToHTTP && nonce) {
5390
5617
  const size = new TextEncoder().encode(serializedPayload).length;
5391
5618
  if (size > MAX_SOCKET_MESSAGE_SIZE) {
@@ -5419,9 +5646,7 @@ function createRoom(options, config) {
5419
5646
  info: staticSession.userInfo,
5420
5647
  presence: myPresence,
5421
5648
  canWrite,
5422
- canComment: canComment(dynamicSession.scopes),
5423
- isReadOnly: !canWrite
5424
- // Deprecated, kept for backward-compatibility
5649
+ canComment: canComment(dynamicSession.scopes)
5425
5650
  };
5426
5651
  }
5427
5652
  }
@@ -5647,7 +5872,7 @@ function createRoom(options, config) {
5647
5872
  }
5648
5873
  context.myPresence.patch(patch);
5649
5874
  if (context.activeBatch) {
5650
- if (_optionalChain([options2, 'optionalAccess', _139 => _139.addToHistory])) {
5875
+ if (_optionalChain([options2, 'optionalAccess', _138 => _138.addToHistory])) {
5651
5876
  context.activeBatch.reverseOps.unshift({
5652
5877
  type: "presence",
5653
5878
  data: oldValues
@@ -5657,7 +5882,7 @@ function createRoom(options, config) {
5657
5882
  } else {
5658
5883
  flushNowOrSoon();
5659
5884
  batchUpdates(() => {
5660
- if (_optionalChain([options2, 'optionalAccess', _140 => _140.addToHistory])) {
5885
+ if (_optionalChain([options2, 'optionalAccess', _139 => _139.addToHistory])) {
5661
5886
  addToUndoStack(
5662
5887
  [{ type: "presence", data: oldValues }],
5663
5888
  doNotBatchUpdates
@@ -5834,12 +6059,7 @@ function createRoom(options, config) {
5834
6059
  break;
5835
6060
  }
5836
6061
  case 200 /* INITIAL_STORAGE_STATE */: {
5837
- const unacknowledgedOps = new Map(context.unacknowledgedOps);
5838
- createOrUpdateRootFromMessage(message, doNotBatchUpdates);
5839
- applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
5840
- _optionalChain([_resolveStoragePromise, 'optionalCall', _141 => _141()]);
5841
- notifyStorageStatus();
5842
- eventHub.storageDidLoad.notify();
6062
+ processInitialStorage(message);
5843
6063
  break;
5844
6064
  }
5845
6065
  case 201 /* UPDATE_STORAGE */: {
@@ -5860,7 +6080,7 @@ function createRoom(options, config) {
5860
6080
  if (process.env.NODE_ENV !== "production") {
5861
6081
  const traces = /* @__PURE__ */ new Set();
5862
6082
  for (const opId of message.opIds) {
5863
- const trace = _optionalChain([context, 'access', _142 => _142.opStackTraces, 'optionalAccess', _143 => _143.get, 'call', _144 => _144(opId)]);
6083
+ const trace = _optionalChain([context, 'access', _140 => _140.opStackTraces, 'optionalAccess', _141 => _141.get, 'call', _142 => _142(opId)]);
5864
6084
  if (trace) {
5865
6085
  traces.add(trace);
5866
6086
  }
@@ -5980,14 +6200,35 @@ ${Array.from(traces).join("\n\n")}`
5980
6200
  flushNowOrSoon();
5981
6201
  }
5982
6202
  function dispatchOps(ops) {
5983
- context.buffer.storageOperations.push(...ops);
6203
+ const { storageOperations } = context.buffer;
6204
+ for (const op of ops) {
6205
+ storageOperations.push(op);
6206
+ }
5984
6207
  flushNowOrSoon();
5985
6208
  }
5986
6209
  let _getStorage$ = null;
5987
6210
  let _resolveStoragePromise = null;
6211
+ function processInitialStorage(message) {
6212
+ const unacknowledgedOps = new Map(context.unacknowledgedOps);
6213
+ createOrUpdateRootFromMessage(message, doNotBatchUpdates);
6214
+ applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
6215
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _143 => _143()]);
6216
+ notifyStorageStatus();
6217
+ eventHub.storageDidLoad.notify();
6218
+ }
6219
+ async function streamStorage() {
6220
+ if (!managedSocket.authValue) {
6221
+ return;
6222
+ }
6223
+ const result = await streamFetch(managedSocket.authValue, config.roomId);
6224
+ const items = await result.json();
6225
+ processInitialStorage({ type: 200 /* INITIAL_STORAGE_STATE */, items });
6226
+ }
5988
6227
  function refreshStorage(options2) {
5989
6228
  const messages = context.buffer.messages;
5990
- if (!messages.some((msg) => msg.type === 200 /* FETCH_STORAGE */)) {
6229
+ if (config.unstable_streamData) {
6230
+ void streamStorage();
6231
+ } else if (!messages.some((msg) => msg.type === 200 /* FETCH_STORAGE */)) {
5991
6232
  messages.push({ type: 200 /* FETCH_STORAGE */ });
5992
6233
  }
5993
6234
  if (options2.flush) {
@@ -6165,33 +6406,114 @@ ${Array.from(traces).join("\n\n")}`
6165
6406
  ydoc: eventHub.ydoc.observable,
6166
6407
  comments: eventHub.comments.observable
6167
6408
  };
6168
- const commentsApi = createCommentsApi(config.roomId, delegates.authenticate, {
6169
- baseUrl: config.baseUrl
6170
- });
6171
- return Object.defineProperty(
6172
- {
6173
- /* NOTE: Exposing __internal here only to allow testing implementation details in unit tests */
6174
- __internal: {
6175
- get presenceBuffer() {
6176
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _145 => _145.buffer, 'access', _146 => _146.presenceUpdates, 'optionalAccess', _147 => _147.data]), () => ( null)));
6177
- },
6178
- // prettier-ignore
6179
- get undoStack() {
6180
- return deepClone(context.undoStack);
6181
- },
6182
- // prettier-ignore
6183
- get nodeCount() {
6184
- return context.nodes.size;
6185
- },
6186
- // prettier-ignore
6187
- // Support for the Liveblocks browser extension
6188
- getSelf_forDevTools: () => selfAsTreeNode.current,
6189
- getOthers_forDevTools: () => others_forDevTools.current,
6190
- // prettier-ignore
6191
- simulate: {
6192
- // These exist only for our E2E testing app
6193
- explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
6194
- rawSend: (data) => managedSocket.send(data)
6409
+ const commentsApi = createCommentsApi(
6410
+ config.roomId,
6411
+ delegates.authenticate,
6412
+ fetchClientApi
6413
+ );
6414
+ async function fetchNotificationsJson(endpoint, options2) {
6415
+ const authValue = await delegates.authenticate();
6416
+ const response = await fetchClientApi(
6417
+ config.roomId,
6418
+ endpoint,
6419
+ authValue,
6420
+ options2
6421
+ );
6422
+ if (!response.ok) {
6423
+ if (response.status >= 400 && response.status < 600) {
6424
+ let error3;
6425
+ try {
6426
+ const errorBody = await response.json();
6427
+ error3 = new NotificationsApiError(
6428
+ errorBody.message,
6429
+ response.status,
6430
+ errorBody
6431
+ );
6432
+ } catch (e7) {
6433
+ error3 = new NotificationsApiError(
6434
+ response.statusText,
6435
+ response.status
6436
+ );
6437
+ }
6438
+ throw error3;
6439
+ }
6440
+ }
6441
+ let body;
6442
+ try {
6443
+ body = await response.json();
6444
+ } catch (e8) {
6445
+ body = {};
6446
+ }
6447
+ return body;
6448
+ }
6449
+ function getRoomNotificationSettings() {
6450
+ return fetchNotificationsJson(
6451
+ "/notification-settings"
6452
+ );
6453
+ }
6454
+ function updateRoomNotificationSettings(settings) {
6455
+ return fetchNotificationsJson(
6456
+ "/notification-settings",
6457
+ {
6458
+ method: "POST",
6459
+ body: JSON.stringify(settings),
6460
+ headers: {
6461
+ "Content-Type": "application/json"
6462
+ }
6463
+ }
6464
+ );
6465
+ }
6466
+ async function markInboxNotificationsAsRead(inboxNotificationIds) {
6467
+ await fetchNotificationsJson("/inbox-notifications/read", {
6468
+ method: "POST",
6469
+ headers: {
6470
+ "Content-Type": "application/json"
6471
+ },
6472
+ body: JSON.stringify({ inboxNotificationIds })
6473
+ });
6474
+ }
6475
+ const batchedMarkInboxNotificationsAsRead = new Batch(
6476
+ async (batchedInboxNotificationIds) => {
6477
+ const inboxNotificationIds = batchedInboxNotificationIds.flat();
6478
+ await markInboxNotificationsAsRead(inboxNotificationIds);
6479
+ return inboxNotificationIds;
6480
+ },
6481
+ { delay: MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY2 }
6482
+ );
6483
+ async function markInboxNotificationAsRead(inboxNotificationId) {
6484
+ await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
6485
+ }
6486
+ return Object.defineProperty(
6487
+ {
6488
+ [kInternal]: {
6489
+ get presenceBuffer() {
6490
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _144 => _144.buffer, 'access', _145 => _145.presenceUpdates, 'optionalAccess', _146 => _146.data]), () => ( null)));
6491
+ },
6492
+ // prettier-ignore
6493
+ get undoStack() {
6494
+ return deepClone(context.undoStack);
6495
+ },
6496
+ // prettier-ignore
6497
+ get nodeCount() {
6498
+ return context.nodes.size;
6499
+ },
6500
+ // prettier-ignore
6501
+ // Support for the Liveblocks browser extension
6502
+ getSelf_forDevTools: () => selfAsTreeNode.current,
6503
+ getOthers_forDevTools: () => others_forDevTools.current,
6504
+ // prettier-ignore
6505
+ simulate: {
6506
+ // These exist only for our E2E testing app
6507
+ explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
6508
+ rawSend: (data) => managedSocket.send(data)
6509
+ },
6510
+ comments: {
6511
+ ...commentsApi
6512
+ },
6513
+ notifications: {
6514
+ getRoomNotificationSettings,
6515
+ updateRoomNotificationSettings,
6516
+ markInboxNotificationAsRead
6195
6517
  }
6196
6518
  },
6197
6519
  id: config.roomId,
@@ -6225,16 +6547,14 @@ ${Array.from(traces).join("\n\n")}`
6225
6547
  events,
6226
6548
  // Core
6227
6549
  getStatus: () => managedSocket.getStatus(),
6228
- getConnectionState: () => managedSocket.getLegacyStatus(),
6229
6550
  getSelf: () => self.current,
6230
6551
  // Presence
6231
6552
  getPresence: () => context.myPresence.current,
6232
- getOthers: () => context.others.current,
6233
- ...commentsApi
6553
+ getOthers: () => context.others.current
6234
6554
  },
6235
- // Explictly make the __internal field non-enumerable, to avoid aggressive
6555
+ // Explictly make the internal field non-enumerable, to avoid aggressive
6236
6556
  // freezing when used with Immer
6237
- "__internal",
6557
+ kInternal,
6238
6558
  { enumerable: false }
6239
6559
  );
6240
6560
  }
@@ -6280,12 +6600,6 @@ function makeClassicSubscribeFn(events) {
6280
6600
  }
6281
6601
  case "error":
6282
6602
  return events.error.subscribe(callback);
6283
- case "connection": {
6284
- const cb = callback;
6285
- return events.status.subscribe(
6286
- (status) => cb(newToLegacyStatus(status))
6287
- );
6288
- }
6289
6603
  case "status":
6290
6604
  return events.status.subscribe(callback);
6291
6605
  case "lost-connection":
@@ -6315,7 +6629,7 @@ function makeClassicSubscribeFn(events) {
6315
6629
  }
6316
6630
  if (isLiveNode(first)) {
6317
6631
  const node = first;
6318
- if (_optionalChain([options, 'optionalAccess', _148 => _148.isDeep])) {
6632
+ if (_optionalChain([options, 'optionalAccess', _147 => _147.isDeep])) {
6319
6633
  const storageCallback = second;
6320
6634
  return subscribeToLiveStructureDeeply(node, storageCallback);
6321
6635
  } else {
@@ -6334,7 +6648,7 @@ function isRoomEventName(value) {
6334
6648
  }
6335
6649
  function makeAuthDelegateForRoom(roomId, authManager) {
6336
6650
  return async () => {
6337
- return authManager.getAuthValue("room:read", roomId);
6651
+ return authManager.getAuthValue({ requestedScope: "room:read", roomId });
6338
6652
  };
6339
6653
  }
6340
6654
  function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
@@ -6361,6 +6675,470 @@ function makeCreateSocketDelegateForRoom(roomId, baseUrl, WebSocketPolyfill) {
6361
6675
  };
6362
6676
  }
6363
6677
 
6678
+ // src/store.ts
6679
+ function createClientStore() {
6680
+ const store = createStore({
6681
+ threads: {},
6682
+ queries: {},
6683
+ optimisticUpdates: [],
6684
+ inboxNotifications: {},
6685
+ notificationSettings: {}
6686
+ });
6687
+ return {
6688
+ ...store,
6689
+ deleteThread(threadId) {
6690
+ store.set((state) => {
6691
+ return {
6692
+ ...state,
6693
+ threads: deleteKeyImmutable(state.threads, threadId),
6694
+ inboxNotifications: Object.fromEntries(
6695
+ Object.entries(state.inboxNotifications).filter(
6696
+ ([_id, notification]) => notification.kind === "thread" && notification.threadId === threadId
6697
+ )
6698
+ )
6699
+ };
6700
+ });
6701
+ },
6702
+ updateThreadAndNotification(thread, inboxNotification) {
6703
+ store.set((state) => {
6704
+ const existingThread = state.threads[thread.id];
6705
+ return {
6706
+ ...state,
6707
+ threads: existingThread === void 0 || compareThreads(thread, existingThread) === 1 ? { ...state.threads, [thread.id]: thread } : state.threads,
6708
+ inboxNotifications: inboxNotification === void 0 ? state.inboxNotifications : {
6709
+ ...state.inboxNotifications,
6710
+ [inboxNotification.id]: inboxNotification
6711
+ }
6712
+ };
6713
+ });
6714
+ },
6715
+ updateThreadsAndNotifications(threads, inboxNotifications, deletedThreads, deletedInboxNotifications, queryKey) {
6716
+ store.set((state) => ({
6717
+ ...state,
6718
+ threads: applyThreadUpdates(state.threads, {
6719
+ newThreads: threads,
6720
+ deletedThreads
6721
+ }),
6722
+ inboxNotifications: applyNotificationsUpdates(
6723
+ state.inboxNotifications,
6724
+ {
6725
+ newInboxNotifications: inboxNotifications,
6726
+ deletedNotifications: deletedInboxNotifications
6727
+ }
6728
+ ),
6729
+ queries: queryKey !== void 0 ? {
6730
+ ...state.queries,
6731
+ [queryKey]: {
6732
+ isLoading: false
6733
+ }
6734
+ } : state.queries
6735
+ }));
6736
+ },
6737
+ updateRoomInboxNotificationSettings(roomId, settings, queryKey) {
6738
+ store.set((state) => ({
6739
+ ...state,
6740
+ notificationSettings: {
6741
+ ...state.notificationSettings,
6742
+ [roomId]: settings
6743
+ },
6744
+ queries: {
6745
+ ...state.queries,
6746
+ [queryKey]: {
6747
+ isLoading: false
6748
+ }
6749
+ }
6750
+ }));
6751
+ },
6752
+ pushOptimisticUpdate(optimisticUpdate) {
6753
+ store.set((state) => ({
6754
+ ...state,
6755
+ optimisticUpdates: [...state.optimisticUpdates, optimisticUpdate]
6756
+ }));
6757
+ },
6758
+ setQueryState(queryKey, queryState) {
6759
+ store.set((state) => ({
6760
+ ...state,
6761
+ queries: {
6762
+ ...state.queries,
6763
+ [queryKey]: queryState
6764
+ }
6765
+ }));
6766
+ }
6767
+ };
6768
+ }
6769
+ function deleteKeyImmutable(record, key) {
6770
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
6771
+ const { [key]: _toDelete, ...rest } = record;
6772
+ return rest;
6773
+ }
6774
+ return record;
6775
+ }
6776
+ function compareThreads(thread1, thread2) {
6777
+ if (thread1.updatedAt && thread2.updatedAt) {
6778
+ return thread1.updatedAt > thread2.updatedAt ? 1 : thread1.updatedAt < thread2.updatedAt ? -1 : 0;
6779
+ } else if (thread1.updatedAt || thread2.updatedAt) {
6780
+ return thread1.updatedAt ? 1 : -1;
6781
+ }
6782
+ if (thread1.createdAt > thread2.createdAt) {
6783
+ return 1;
6784
+ } else if (thread1.createdAt < thread2.createdAt) {
6785
+ return -1;
6786
+ }
6787
+ return 0;
6788
+ }
6789
+ function applyOptimisticUpdates(state) {
6790
+ const result = {
6791
+ threads: {
6792
+ ...state.threads
6793
+ },
6794
+ inboxNotifications: {
6795
+ ...state.inboxNotifications
6796
+ },
6797
+ notificationSettings: {
6798
+ ...state.notificationSettings
6799
+ }
6800
+ };
6801
+ for (const optimisticUpdate of state.optimisticUpdates) {
6802
+ switch (optimisticUpdate.type) {
6803
+ case "create-thread": {
6804
+ result.threads[optimisticUpdate.thread.id] = optimisticUpdate.thread;
6805
+ break;
6806
+ }
6807
+ case "edit-thread-metadata": {
6808
+ const thread = result.threads[optimisticUpdate.threadId];
6809
+ if (thread === void 0) {
6810
+ break;
6811
+ }
6812
+ if (thread.deletedAt !== void 0) {
6813
+ break;
6814
+ }
6815
+ if (thread.updatedAt !== void 0 && thread.updatedAt > optimisticUpdate.updatedAt) {
6816
+ break;
6817
+ }
6818
+ result.threads[thread.id] = {
6819
+ ...thread,
6820
+ updatedAt: optimisticUpdate.updatedAt,
6821
+ metadata: {
6822
+ ...thread.metadata,
6823
+ ...optimisticUpdate.metadata
6824
+ }
6825
+ };
6826
+ break;
6827
+ }
6828
+ case "create-comment": {
6829
+ const thread = result.threads[optimisticUpdate.comment.threadId];
6830
+ if (thread === void 0) {
6831
+ break;
6832
+ }
6833
+ result.threads[thread.id] = upsertComment(
6834
+ thread,
6835
+ optimisticUpdate.comment
6836
+ );
6837
+ const inboxNotification = Object.values(result.inboxNotifications).find(
6838
+ (notification) => notification.kind === "thread" && notification.threadId === thread.id
6839
+ );
6840
+ if (inboxNotification === void 0) {
6841
+ break;
6842
+ }
6843
+ result.inboxNotifications[inboxNotification.id] = {
6844
+ ...inboxNotification,
6845
+ notifiedAt: optimisticUpdate.comment.createdAt,
6846
+ readAt: optimisticUpdate.comment.createdAt
6847
+ };
6848
+ break;
6849
+ }
6850
+ case "edit-comment": {
6851
+ const thread = result.threads[optimisticUpdate.comment.threadId];
6852
+ if (thread === void 0) {
6853
+ break;
6854
+ }
6855
+ result.threads[thread.id] = upsertComment(
6856
+ thread,
6857
+ optimisticUpdate.comment
6858
+ );
6859
+ break;
6860
+ }
6861
+ case "delete-comment": {
6862
+ const thread = result.threads[optimisticUpdate.threadId];
6863
+ if (thread === void 0) {
6864
+ break;
6865
+ }
6866
+ result.threads[thread.id] = deleteComment(
6867
+ thread,
6868
+ optimisticUpdate.commentId,
6869
+ optimisticUpdate.deletedAt
6870
+ );
6871
+ break;
6872
+ }
6873
+ case "add-reaction": {
6874
+ const thread = result.threads[optimisticUpdate.threadId];
6875
+ if (thread === void 0) {
6876
+ break;
6877
+ }
6878
+ result.threads[thread.id] = addReaction(
6879
+ thread,
6880
+ optimisticUpdate.commentId,
6881
+ optimisticUpdate.reaction
6882
+ );
6883
+ break;
6884
+ }
6885
+ case "remove-reaction": {
6886
+ const thread = result.threads[optimisticUpdate.threadId];
6887
+ if (thread === void 0) {
6888
+ break;
6889
+ }
6890
+ result.threads[thread.id] = removeReaction(
6891
+ thread,
6892
+ optimisticUpdate.commentId,
6893
+ optimisticUpdate.emoji,
6894
+ optimisticUpdate.userId,
6895
+ optimisticUpdate.removedAt
6896
+ );
6897
+ break;
6898
+ }
6899
+ case "mark-inbox-notification-as-read": {
6900
+ result.inboxNotifications[optimisticUpdate.inboxNotificationId] = {
6901
+ ...state.inboxNotifications[optimisticUpdate.inboxNotificationId],
6902
+ readAt: optimisticUpdate.readAt
6903
+ };
6904
+ break;
6905
+ }
6906
+ case "mark-inbox-notifications-as-read": {
6907
+ for (const id in result.inboxNotifications) {
6908
+ result.inboxNotifications[id] = {
6909
+ ...result.inboxNotifications[id],
6910
+ readAt: optimisticUpdate.readAt
6911
+ };
6912
+ }
6913
+ break;
6914
+ }
6915
+ case "update-notification-settings": {
6916
+ result.notificationSettings[optimisticUpdate.roomId] = {
6917
+ ...result.notificationSettings[optimisticUpdate.roomId],
6918
+ ...optimisticUpdate.settings
6919
+ };
6920
+ }
6921
+ }
6922
+ }
6923
+ return result;
6924
+ }
6925
+ function applyThreadUpdates(existingThreads, updates) {
6926
+ const updatedThreads = { ...existingThreads };
6927
+ updates.newThreads.forEach((thread) => {
6928
+ const existingThread = updatedThreads[thread.id];
6929
+ if (existingThread) {
6930
+ const result = compareThreads(existingThread, thread);
6931
+ if (result === 1)
6932
+ return;
6933
+ }
6934
+ updatedThreads[thread.id] = thread;
6935
+ });
6936
+ updates.deletedThreads.forEach(({ id, deletedAt }) => {
6937
+ const existingThread = updatedThreads[id];
6938
+ if (existingThread === void 0)
6939
+ return;
6940
+ existingThread.deletedAt = deletedAt;
6941
+ existingThread.updatedAt = deletedAt;
6942
+ existingThread.comments = [];
6943
+ });
6944
+ return updatedThreads;
6945
+ }
6946
+ function applyNotificationsUpdates(existingInboxNotifications, updates) {
6947
+ const updatedInboxNotifications = { ...existingInboxNotifications };
6948
+ updates.newInboxNotifications.forEach((notification) => {
6949
+ const existingNotification = updatedInboxNotifications[notification.id];
6950
+ if (existingNotification) {
6951
+ const result = compareInboxNotifications(
6952
+ existingNotification,
6953
+ notification
6954
+ );
6955
+ if (result === 1)
6956
+ return;
6957
+ }
6958
+ updatedInboxNotifications[notification.id] = notification;
6959
+ });
6960
+ updates.deletedNotifications.forEach(
6961
+ ({ id }) => delete updatedInboxNotifications[id]
6962
+ );
6963
+ return updatedInboxNotifications;
6964
+ }
6965
+ function compareInboxNotifications(inboxNotificationA, inboxNotificationB) {
6966
+ if (inboxNotificationA.notifiedAt > inboxNotificationB.notifiedAt) {
6967
+ return 1;
6968
+ } else if (inboxNotificationA.notifiedAt < inboxNotificationB.notifiedAt) {
6969
+ return -1;
6970
+ }
6971
+ if (inboxNotificationA.readAt && inboxNotificationB.readAt) {
6972
+ return inboxNotificationA.readAt > inboxNotificationB.readAt ? 1 : inboxNotificationA.readAt < inboxNotificationB.readAt ? -1 : 0;
6973
+ } else if (inboxNotificationA.readAt || inboxNotificationB.readAt) {
6974
+ return inboxNotificationA.readAt ? 1 : -1;
6975
+ }
6976
+ return 0;
6977
+ }
6978
+ function upsertComment(thread, comment) {
6979
+ if (thread.deletedAt !== void 0) {
6980
+ return thread;
6981
+ }
6982
+ if (comment.threadId !== thread.id) {
6983
+ warn(
6984
+ `Comment ${comment.id} does not belong to thread ${thread.id}`
6985
+ );
6986
+ return thread;
6987
+ }
6988
+ const existingComment = thread.comments.find(
6989
+ (existingComment2) => existingComment2.id === comment.id
6990
+ );
6991
+ if (existingComment === void 0) {
6992
+ const updatedAt = new Date(
6993
+ Math.max(_optionalChain([thread, 'access', _148 => _148.updatedAt, 'optionalAccess', _149 => _149.getTime, 'call', _150 => _150()]) || 0, comment.createdAt.getTime())
6994
+ );
6995
+ const updatedThread = {
6996
+ ...thread,
6997
+ updatedAt,
6998
+ comments: [...thread.comments, comment]
6999
+ };
7000
+ return updatedThread;
7001
+ }
7002
+ if (existingComment.deletedAt !== void 0) {
7003
+ return thread;
7004
+ }
7005
+ if (existingComment.editedAt === void 0 || comment.editedAt === void 0 || existingComment.editedAt <= comment.editedAt) {
7006
+ const updatedComments = thread.comments.map(
7007
+ (existingComment2) => existingComment2.id === comment.id ? comment : existingComment2
7008
+ );
7009
+ const updatedThread = {
7010
+ ...thread,
7011
+ updatedAt: new Date(
7012
+ Math.max(
7013
+ _optionalChain([thread, 'access', _151 => _151.updatedAt, 'optionalAccess', _152 => _152.getTime, 'call', _153 => _153()]) || 0,
7014
+ _optionalChain([comment, 'access', _154 => _154.editedAt, 'optionalAccess', _155 => _155.getTime, 'call', _156 => _156()]) || comment.createdAt.getTime()
7015
+ )
7016
+ ),
7017
+ comments: updatedComments
7018
+ };
7019
+ return updatedThread;
7020
+ }
7021
+ return thread;
7022
+ }
7023
+ function deleteComment(thread, commentId, deletedAt) {
7024
+ if (thread.deletedAt !== void 0) {
7025
+ return thread;
7026
+ }
7027
+ const existingComment = thread.comments.find(
7028
+ (comment) => comment.id === commentId
7029
+ );
7030
+ if (existingComment === void 0) {
7031
+ return thread;
7032
+ }
7033
+ if (existingComment.deletedAt !== void 0) {
7034
+ return thread;
7035
+ }
7036
+ const updatedComments = thread.comments.map(
7037
+ (comment) => comment.id === commentId ? {
7038
+ ...comment,
7039
+ deletedAt,
7040
+ body: void 0
7041
+ } : comment
7042
+ );
7043
+ if (!updatedComments.some((comment) => comment.deletedAt === void 0)) {
7044
+ return {
7045
+ ...thread,
7046
+ deletedAt,
7047
+ updatedAt: deletedAt,
7048
+ comments: []
7049
+ };
7050
+ }
7051
+ return {
7052
+ ...thread,
7053
+ updatedAt: deletedAt,
7054
+ comments: updatedComments
7055
+ };
7056
+ }
7057
+ function addReaction(thread, commentId, reaction) {
7058
+ if (thread.deletedAt !== void 0) {
7059
+ return thread;
7060
+ }
7061
+ const existingComment = thread.comments.find(
7062
+ (comment) => comment.id === commentId
7063
+ );
7064
+ if (existingComment === void 0) {
7065
+ return thread;
7066
+ }
7067
+ if (existingComment.deletedAt !== void 0) {
7068
+ return thread;
7069
+ }
7070
+ const updatedComments = thread.comments.map(
7071
+ (comment) => comment.id === commentId ? {
7072
+ ...comment,
7073
+ reactions: upsertReaction(comment.reactions, reaction)
7074
+ } : comment
7075
+ );
7076
+ return {
7077
+ ...thread,
7078
+ updatedAt: new Date(
7079
+ Math.max(reaction.createdAt.getTime(), _optionalChain([thread, 'access', _157 => _157.updatedAt, 'optionalAccess', _158 => _158.getTime, 'call', _159 => _159()]) || 0)
7080
+ ),
7081
+ comments: updatedComments
7082
+ };
7083
+ }
7084
+ function removeReaction(thread, commentId, emoji, userId, removedAt) {
7085
+ if (thread.deletedAt !== void 0) {
7086
+ return thread;
7087
+ }
7088
+ const existingComment = thread.comments.find(
7089
+ (comment) => comment.id === commentId
7090
+ );
7091
+ if (existingComment === void 0) {
7092
+ return thread;
7093
+ }
7094
+ if (existingComment.deletedAt !== void 0) {
7095
+ return thread;
7096
+ }
7097
+ const updatedComments = thread.comments.map(
7098
+ (comment) => comment.id === commentId ? {
7099
+ ...comment,
7100
+ reactions: comment.reactions.map(
7101
+ (reaction) => reaction.emoji === emoji ? {
7102
+ ...reaction,
7103
+ users: reaction.users.filter((user) => user.id !== userId)
7104
+ } : reaction
7105
+ ).filter((reaction) => reaction.users.length > 0)
7106
+ // Remove reactions with no users left
7107
+ } : comment
7108
+ );
7109
+ return {
7110
+ ...thread,
7111
+ updatedAt: new Date(
7112
+ Math.max(removedAt.getTime(), _optionalChain([thread, 'access', _160 => _160.updatedAt, 'optionalAccess', _161 => _161.getTime, 'call', _162 => _162()]) || 0)
7113
+ ),
7114
+ comments: updatedComments
7115
+ };
7116
+ }
7117
+ function upsertReaction(reactions, reaction) {
7118
+ const existingReaction = reactions.find(
7119
+ (existingReaction2) => existingReaction2.emoji === reaction.emoji
7120
+ );
7121
+ if (existingReaction === void 0) {
7122
+ return [
7123
+ ...reactions,
7124
+ {
7125
+ emoji: reaction.emoji,
7126
+ createdAt: reaction.createdAt,
7127
+ users: [{ id: reaction.userId }]
7128
+ }
7129
+ ];
7130
+ }
7131
+ if (existingReaction.users.some((user) => user.id === reaction.userId) === false) {
7132
+ return reactions.map(
7133
+ (existingReaction2) => existingReaction2.emoji === reaction.emoji ? {
7134
+ ...existingReaction2,
7135
+ users: [...existingReaction2.users, { id: reaction.userId }]
7136
+ } : existingReaction2
7137
+ );
7138
+ }
7139
+ return reactions;
7140
+ }
7141
+
6364
7142
  // src/client.ts
6365
7143
  var MIN_THROTTLE = 16;
6366
7144
  var MAX_THROTTLE = 1e3;
@@ -6370,16 +7148,22 @@ var MIN_LOST_CONNECTION_TIMEOUT = 200;
6370
7148
  var RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT = 1e3;
6371
7149
  var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
6372
7150
  var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
6373
- function getBaseUrlFromClientOptions(clientOptions) {
6374
- if ("liveblocksServer" in clientOptions) {
6375
- throw new Error("Client option no longer supported");
6376
- }
6377
- if (typeof clientOptions.baseUrl === "string" && clientOptions.baseUrl.startsWith("http")) {
6378
- return clientOptions.baseUrl;
7151
+ var RESOLVE_USERS_BATCH_DELAY = 50;
7152
+ var RESOLVE_ROOMS_INFO_BATCH_DELAY = 50;
7153
+ function getBaseUrl(baseUrl) {
7154
+ if (typeof baseUrl === "string" && baseUrl.startsWith("http")) {
7155
+ return baseUrl;
6379
7156
  } else {
6380
7157
  return DEFAULT_BASE_URL;
6381
7158
  }
6382
7159
  }
7160
+ function getAuthBearerHeaderFromAuthValue(authValue) {
7161
+ if (authValue.type === "public") {
7162
+ return authValue.publicApiKey;
7163
+ } else {
7164
+ return authValue.token.raw;
7165
+ }
7166
+ }
6383
7167
  function createClient(options) {
6384
7168
  const clientOptions = options;
6385
7169
  const throttleDelay = getThrottle(_nullishCoalesce(clientOptions.throttle, () => ( DEFAULT_THROTTLE)));
@@ -6389,6 +7173,7 @@ function createClient(options) {
6389
7173
  const backgroundKeepAliveTimeout = getBackgroundKeepAliveTimeout(
6390
7174
  clientOptions.backgroundKeepAliveTimeout
6391
7175
  );
7176
+ const baseUrl = getBaseUrl(clientOptions.baseUrl);
6392
7177
  const authManager = createAuthManager(options);
6393
7178
  const roomsById = /* @__PURE__ */ new Map();
6394
7179
  function teardownRoom(room) {
@@ -6424,7 +7209,6 @@ function createClient(options) {
6424
7209
  options2.initialPresence === null || options2.initialPresence === void 0,
6425
7210
  "Please provide an initial presence value for the current user when entering the room."
6426
7211
  );
6427
- const baseUrl = getBaseUrlFromClientOptions(clientOptions);
6428
7212
  const newRoom = createRoom(
6429
7213
  {
6430
7214
  initialPresence: _nullishCoalesce(options2.initialPresence, () => ( {})),
@@ -6440,14 +7224,15 @@ function createClient(options) {
6440
7224
  createSocket: makeCreateSocketDelegateForRoom(
6441
7225
  roomId,
6442
7226
  baseUrl,
6443
- _optionalChain([clientOptions, 'access', _149 => _149.polyfills, 'optionalAccess', _150 => _150.WebSocket])
7227
+ _optionalChain([clientOptions, 'access', _163 => _163.polyfills, 'optionalAccess', _164 => _164.WebSocket])
6444
7228
  ),
6445
7229
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
6446
7230
  })),
6447
7231
  enableDebugLogging: clientOptions.enableDebugLogging,
6448
- unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _151 => _151.unstable_batchedUpdates]),
7232
+ unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _165 => _165.unstable_batchedUpdates]),
6449
7233
  baseUrl,
6450
- unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP
7234
+ unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
7235
+ unstable_streamData: !!clientOptions.unstable_streamData
6451
7236
  }
6452
7237
  );
6453
7238
  const newRoomInfo = {
@@ -6457,10 +7242,10 @@ function createClient(options) {
6457
7242
  roomsById.set(roomId, newRoomInfo);
6458
7243
  setupDevTools(() => Array.from(roomsById.keys()));
6459
7244
  linkDevTools(roomId, newRoom);
6460
- const shouldConnect = _nullishCoalesce(_nullishCoalesce(options2.autoConnect, () => ( options2.shouldInitiallyConnect)), () => ( true));
7245
+ const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
6461
7246
  if (shouldConnect) {
6462
7247
  if (typeof atob === "undefined") {
6463
- if (_optionalChain([clientOptions, 'access', _152 => _152.polyfills, 'optionalAccess', _153 => _153.atob]) === void 0) {
7248
+ if (_optionalChain([clientOptions, 'access', _166 => _166.polyfills, 'optionalAccess', _167 => _167.atob]) === void 0) {
6464
7249
  throw new Error(
6465
7250
  "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"
6466
7251
  );
@@ -6469,68 +7254,464 @@ function createClient(options) {
6469
7254
  }
6470
7255
  newRoom.connect();
6471
7256
  }
6472
- return leaseRoom(newRoomInfo);
6473
- }
6474
- function enter(roomId, options2) {
6475
- const { room, leave: _ } = enterRoom(roomId, options2);
6476
- return room;
6477
- }
6478
- function getRoom(roomId) {
6479
- const room = _optionalChain([roomsById, 'access', _154 => _154.get, 'call', _155 => _155(roomId), 'optionalAccess', _156 => _156.room]);
6480
- return room ? room : null;
6481
- }
6482
- function forceLeave(roomId) {
6483
- const unsubs = _nullishCoalesce(_optionalChain([roomsById, 'access', _157 => _157.get, 'call', _158 => _158(roomId), 'optionalAccess', _159 => _159.unsubs]), () => ( /* @__PURE__ */ new Set()));
6484
- for (const unsub of unsubs) {
6485
- unsub();
7257
+ return leaseRoom(newRoomInfo);
7258
+ }
7259
+ function enter(roomId, options2) {
7260
+ const { room, leave: _ } = enterRoom(roomId, options2);
7261
+ return room;
7262
+ }
7263
+ function getRoom(roomId) {
7264
+ const room = _optionalChain([roomsById, 'access', _168 => _168.get, 'call', _169 => _169(roomId), 'optionalAccess', _170 => _170.room]);
7265
+ return room ? room : null;
7266
+ }
7267
+ function forceLeave(roomId) {
7268
+ const unsubs = _nullishCoalesce(_optionalChain([roomsById, 'access', _171 => _171.get, 'call', _172 => _172(roomId), 'optionalAccess', _173 => _173.unsubs]), () => ( /* @__PURE__ */ new Set()));
7269
+ for (const unsub of unsubs) {
7270
+ unsub();
7271
+ }
7272
+ }
7273
+ function logout() {
7274
+ authManager.reset();
7275
+ for (const { room } of roomsById.values()) {
7276
+ if (!isIdle(room.getStatus())) {
7277
+ room.reconnect();
7278
+ }
7279
+ }
7280
+ }
7281
+ const currentUserIdStore = createStore(null);
7282
+ const {
7283
+ getInboxNotifications,
7284
+ getUnreadInboxNotificationsCount,
7285
+ markAllInboxNotificationsAsRead,
7286
+ markInboxNotificationAsRead
7287
+ } = createNotificationsApi({
7288
+ baseUrl,
7289
+ fetcher: _optionalChain([clientOptions, 'access', _174 => _174.polyfills, 'optionalAccess', _175 => _175.fetch]) || /* istanbul ignore next */
7290
+ fetch,
7291
+ authManager,
7292
+ currentUserIdStore
7293
+ });
7294
+ const cacheStore = createClientStore();
7295
+ const resolveUsers = clientOptions.resolveUsers;
7296
+ const warnIfNoResolveUsers = createDevelopmentWarning(
7297
+ () => !resolveUsers,
7298
+ "Set the resolveUsers option in createClient to specify user info."
7299
+ );
7300
+ const usersStore = createBatchStore(
7301
+ async (batchedUserIds) => {
7302
+ const userIds = batchedUserIds.flat();
7303
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _176 => _176({ userIds })]);
7304
+ warnIfNoResolveUsers();
7305
+ return _nullishCoalesce(users, () => ( userIds.map(() => void 0)));
7306
+ },
7307
+ { delay: RESOLVE_USERS_BATCH_DELAY }
7308
+ );
7309
+ const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
7310
+ const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
7311
+ () => !resolveRoomsInfo,
7312
+ "Set the resolveRoomsInfo option in createClient to specify room info."
7313
+ );
7314
+ const roomsInfoStore = createBatchStore(
7315
+ async (batchedRoomIds) => {
7316
+ const roomIds = batchedRoomIds.flat();
7317
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _177 => _177({ roomIds })]);
7318
+ warnIfNoResolveRoomsInfo();
7319
+ return _nullishCoalesce(roomsInfo, () => ( roomIds.map(() => void 0)));
7320
+ },
7321
+ { delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
7322
+ );
7323
+ return Object.defineProperty(
7324
+ {
7325
+ logout,
7326
+ // Old, deprecated APIs
7327
+ enter,
7328
+ getRoom,
7329
+ leave: forceLeave,
7330
+ // New, preferred API
7331
+ enterRoom,
7332
+ // Internal
7333
+ [kInternal]: {
7334
+ notifications: {
7335
+ getInboxNotifications,
7336
+ getUnreadInboxNotificationsCount,
7337
+ markAllInboxNotificationsAsRead,
7338
+ markInboxNotificationAsRead
7339
+ },
7340
+ currentUserIdStore,
7341
+ resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
7342
+ cacheStore,
7343
+ usersStore,
7344
+ roomsInfoStore,
7345
+ getRoomIds() {
7346
+ return Array.from(roomsById.keys());
7347
+ }
7348
+ }
7349
+ },
7350
+ kInternal,
7351
+ {
7352
+ enumerable: false
7353
+ }
7354
+ );
7355
+ }
7356
+ var NotificationsApiError = class extends Error {
7357
+ constructor(message, status, details) {
7358
+ super(message);
7359
+ this.message = message;
7360
+ this.status = status;
7361
+ this.details = details;
7362
+ }
7363
+ };
7364
+ function checkBounds(option, value, min, max, recommendedMin) {
7365
+ if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
7366
+ throw new Error(
7367
+ max !== void 0 ? `${option} should be between ${_nullishCoalesce(recommendedMin, () => ( min))} and ${max}.` : `${option} should be at least ${_nullishCoalesce(recommendedMin, () => ( min))}.`
7368
+ );
7369
+ }
7370
+ return value;
7371
+ }
7372
+ function getBackgroundKeepAliveTimeout(value) {
7373
+ if (value === void 0)
7374
+ return void 0;
7375
+ return checkBounds(
7376
+ "backgroundKeepAliveTimeout",
7377
+ value,
7378
+ MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
7379
+ );
7380
+ }
7381
+ function getThrottle(value) {
7382
+ return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
7383
+ }
7384
+ function getLostConnectionTimeout(value) {
7385
+ return checkBounds(
7386
+ "lostConnectionTimeout",
7387
+ value,
7388
+ MIN_LOST_CONNECTION_TIMEOUT,
7389
+ MAX_LOST_CONNECTION_TIMEOUT,
7390
+ RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
7391
+ );
7392
+ }
7393
+ function createDevelopmentWarning(condition, ...args) {
7394
+ let hasWarned = false;
7395
+ if (process.env.NODE_ENV !== "production") {
7396
+ return () => {
7397
+ if (!hasWarned && (typeof condition === "function" ? condition() : condition)) {
7398
+ warn(...args);
7399
+ hasWarned = true;
7400
+ }
7401
+ };
7402
+ } else {
7403
+ return () => {
7404
+ };
7405
+ }
7406
+ }
7407
+
7408
+ // src/comments/comment-body.ts
7409
+ function isCommentBodyParagraph(element) {
7410
+ return "type" in element && element.type === "mention";
7411
+ }
7412
+ function isCommentBodyText(element) {
7413
+ return "text" in element && typeof element.text === "string";
7414
+ }
7415
+ function isCommentBodyMention(element) {
7416
+ return "type" in element && element.type === "mention";
7417
+ }
7418
+ function isCommentBodyLink(element) {
7419
+ return "type" in element && element.type === "link";
7420
+ }
7421
+ var commentBodyElementsGuards = {
7422
+ paragraph: isCommentBodyParagraph,
7423
+ text: isCommentBodyText,
7424
+ link: isCommentBodyLink,
7425
+ mention: isCommentBodyMention
7426
+ };
7427
+ var commentBodyElementsTypes = {
7428
+ paragraph: "block",
7429
+ text: "inline",
7430
+ link: "inline",
7431
+ mention: "inline"
7432
+ };
7433
+ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
7434
+ if (!body || !_optionalChain([body, 'optionalAccess', _178 => _178.content])) {
7435
+ return;
7436
+ }
7437
+ const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
7438
+ const type = element ? commentBodyElementsTypes[element] : "all";
7439
+ const guard = element ? commentBodyElementsGuards[element] : () => true;
7440
+ const visitor = typeof elementOrVisitor === "function" ? elementOrVisitor : possiblyVisitor;
7441
+ for (const block of body.content) {
7442
+ if (type === "all" || type === "block") {
7443
+ if (guard(block)) {
7444
+ _optionalChain([visitor, 'optionalCall', _179 => _179(block)]);
7445
+ }
7446
+ }
7447
+ if (type === "all" || type === "inline") {
7448
+ for (const inline of block.children) {
7449
+ if (guard(inline)) {
7450
+ _optionalChain([visitor, 'optionalCall', _180 => _180(inline)]);
7451
+ }
7452
+ }
7453
+ }
7454
+ }
7455
+ }
7456
+ function getMentionedIdsFromCommentBody(body) {
7457
+ const mentionedIds = /* @__PURE__ */ new Set();
7458
+ traverseCommentBody(
7459
+ body,
7460
+ "mention",
7461
+ (mention) => mentionedIds.add(mention.id)
7462
+ );
7463
+ return Array.from(mentionedIds);
7464
+ }
7465
+ async function resolveUsersInCommentBody(body, resolveUsers) {
7466
+ const resolvedUsers = /* @__PURE__ */ new Map();
7467
+ if (!resolveUsers) {
7468
+ return resolvedUsers;
7469
+ }
7470
+ const userIds = getMentionedIdsFromCommentBody(body);
7471
+ const users = await resolveUsers({
7472
+ userIds
7473
+ });
7474
+ for (const [index, userId] of userIds.entries()) {
7475
+ const user = _optionalChain([users, 'optionalAccess', _181 => _181[index]]);
7476
+ if (user) {
7477
+ resolvedUsers.set(userId, user);
7478
+ }
7479
+ }
7480
+ return resolvedUsers;
7481
+ }
7482
+ var htmlEscapables = {
7483
+ "&": "&amp;",
7484
+ "<": "&lt;",
7485
+ ">": "&gt;",
7486
+ '"': "&quot;",
7487
+ "'": "&#39;"
7488
+ };
7489
+ var htmlEscapablesRegex = new RegExp(
7490
+ Object.keys(htmlEscapables).map((entity) => `\\${entity}`).join("|"),
7491
+ "g"
7492
+ );
7493
+ function htmlSafe(value) {
7494
+ return new HtmlSafeString([String(value)], []);
7495
+ }
7496
+ function joinHtml(strings) {
7497
+ if (strings.length <= 0) {
7498
+ return new HtmlSafeString([""], []);
7499
+ }
7500
+ return new HtmlSafeString(
7501
+ ["", ...Array(strings.length - 1).fill(""), ""],
7502
+ strings
7503
+ );
7504
+ }
7505
+ function escapeHtml(value) {
7506
+ if (value instanceof HtmlSafeString) {
7507
+ return value.toString();
7508
+ }
7509
+ if (Array.isArray(value)) {
7510
+ return joinHtml(value).toString();
7511
+ }
7512
+ return String(value).replace(
7513
+ htmlEscapablesRegex,
7514
+ (character) => htmlEscapables[character]
7515
+ );
7516
+ }
7517
+ var HtmlSafeString = class {
7518
+ constructor(strings, values) {
7519
+ this._strings = strings;
7520
+ this._values = values;
7521
+ }
7522
+ toString() {
7523
+ return this._strings.reduce((result, str, i) => {
7524
+ return result + escapeHtml(nn(this._values[i - 1])) + str;
7525
+ });
7526
+ }
7527
+ };
7528
+ function html(strings, ...values) {
7529
+ return new HtmlSafeString(strings, values);
7530
+ }
7531
+ var markdownEscapables = {
7532
+ _: "\\_",
7533
+ "*": "\\*",
7534
+ "#": "\\#",
7535
+ "`": "\\`",
7536
+ "~": "\\~",
7537
+ "!": "\\!",
7538
+ "|": "\\|",
7539
+ "(": "\\(",
7540
+ ")": "\\)",
7541
+ "{": "\\{",
7542
+ "}": "\\}",
7543
+ "[": "\\[",
7544
+ "]": "\\]"
7545
+ };
7546
+ var markdownEscapablesRegex = new RegExp(
7547
+ Object.keys(markdownEscapables).map((entity) => `\\${entity}`).join("|"),
7548
+ "g"
7549
+ );
7550
+ function joinMarkdown(strings) {
7551
+ if (strings.length <= 0) {
7552
+ return new MarkdownSafeString([""], []);
7553
+ }
7554
+ return new MarkdownSafeString(
7555
+ ["", ...Array(strings.length - 1).fill(""), ""],
7556
+ strings
7557
+ );
7558
+ }
7559
+ function escapeMarkdown(value) {
7560
+ if (value instanceof MarkdownSafeString) {
7561
+ return value.toString();
7562
+ }
7563
+ if (Array.isArray(value)) {
7564
+ return joinMarkdown(value).toString();
7565
+ }
7566
+ return String(value).replace(
7567
+ markdownEscapablesRegex,
7568
+ (character) => markdownEscapables[character]
7569
+ );
7570
+ }
7571
+ var MarkdownSafeString = class {
7572
+ constructor(strings, values) {
7573
+ this._strings = strings;
7574
+ this._values = values;
7575
+ }
7576
+ toString() {
7577
+ return this._strings.reduce((result, str, i) => {
7578
+ return result + escapeMarkdown(nn(this._values[i - 1])) + str;
7579
+ });
7580
+ }
7581
+ };
7582
+ function markdown(strings, ...values) {
7583
+ return new MarkdownSafeString(strings, values);
7584
+ }
7585
+ function toAbsoluteUrl(url) {
7586
+ if (url.startsWith("http://") || url.startsWith("https://")) {
7587
+ return url;
7588
+ } else if (url.startsWith("www.")) {
7589
+ return "https://" + url;
7590
+ }
7591
+ return;
7592
+ }
7593
+ var stringifyCommentBodyPlainElements = {
7594
+ paragraph: ({ children }) => children,
7595
+ text: ({ element }) => element.text,
7596
+ link: ({ element }) => element.url,
7597
+ mention: ({ element, user }) => {
7598
+ return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _182 => _182.name]), () => ( element.id))}`;
7599
+ }
7600
+ };
7601
+ var stringifyCommentBodyHtmlElements = {
7602
+ paragraph: ({ children }) => {
7603
+ return children ? html`<p>${htmlSafe(children)}</p>` : children;
7604
+ },
7605
+ text: ({ element }) => {
7606
+ let children = element.text;
7607
+ if (!children) {
7608
+ return children;
7609
+ }
7610
+ if (element.bold) {
7611
+ children = html`<strong>${children}</strong>`;
7612
+ }
7613
+ if (element.italic) {
7614
+ children = html`<em>${children}</em>`;
7615
+ }
7616
+ if (element.strikethrough) {
7617
+ children = html`<s>${children}</s>`;
7618
+ }
7619
+ if (element.code) {
7620
+ children = html`<code>${children}</code>`;
7621
+ }
7622
+ return children;
7623
+ },
7624
+ link: ({ element, href }) => {
7625
+ return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
7626
+ },
7627
+ mention: ({ element, user }) => {
7628
+ return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _183 => _183.name]), () => ( element.id))}</span>`;
7629
+ }
7630
+ };
7631
+ var stringifyCommentBodyMarkdownElements = {
7632
+ paragraph: ({ children }) => {
7633
+ return children;
7634
+ },
7635
+ text: ({ element }) => {
7636
+ let children = element.text;
7637
+ if (!children) {
7638
+ return children;
7639
+ }
7640
+ if (element.bold) {
7641
+ children = markdown`**${children}**`;
7642
+ }
7643
+ if (element.italic) {
7644
+ children = markdown`_${children}_`;
6486
7645
  }
6487
- }
6488
- function logout() {
6489
- authManager.reset();
6490
- for (const { room } of roomsById.values()) {
6491
- if (!isIdle(room.getStatus())) {
6492
- room.reconnect();
6493
- }
7646
+ if (element.strikethrough) {
7647
+ children = markdown`~~${children}~~`;
7648
+ }
7649
+ if (element.code) {
7650
+ children = markdown`\`${children}\``;
6494
7651
  }
7652
+ return children;
7653
+ },
7654
+ link: ({ element, href }) => {
7655
+ return markdown`[${element.url}](${href})`;
7656
+ },
7657
+ mention: ({ element, user }) => {
7658
+ return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _184 => _184.name]), () => ( element.id))}`;
6495
7659
  }
6496
- return {
6497
- logout,
6498
- // Old, deprecated APIs
6499
- enter,
6500
- getRoom,
6501
- leave: forceLeave,
6502
- // New, preferred API
6503
- enterRoom
7660
+ };
7661
+ async function stringifyCommentBody(body, options) {
7662
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _185 => _185.format]), () => ( "plain"));
7663
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _186 => _186.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
7664
+ const elements = {
7665
+ ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
7666
+ ..._optionalChain([options, 'optionalAccess', _187 => _187.elements])
6504
7667
  };
6505
- }
6506
- function checkBounds(option, value, min, max, recommendedMin) {
6507
- if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
6508
- throw new Error(
6509
- max !== void 0 ? `${option} should be between ${_nullishCoalesce(recommendedMin, () => ( min))} and ${max}.` : `${option} should be at least ${_nullishCoalesce(recommendedMin, () => ( min))}.`
6510
- );
6511
- }
6512
- return value;
6513
- }
6514
- function getBackgroundKeepAliveTimeout(value) {
6515
- if (value === void 0)
6516
- return void 0;
6517
- return checkBounds(
6518
- "backgroundKeepAliveTimeout",
6519
- value,
6520
- MIN_BACKGROUND_KEEP_ALIVE_TIMEOUT
6521
- );
6522
- }
6523
- function getThrottle(value) {
6524
- return checkBounds("throttle", value, MIN_THROTTLE, MAX_THROTTLE);
6525
- }
6526
- function getLostConnectionTimeout(value) {
6527
- return checkBounds(
6528
- "lostConnectionTimeout",
6529
- value,
6530
- MIN_LOST_CONNECTION_TIMEOUT,
6531
- MAX_LOST_CONNECTION_TIMEOUT,
6532
- RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
7668
+ const resolvedUsers = await resolveUsersInCommentBody(
7669
+ body,
7670
+ _optionalChain([options, 'optionalAccess', _188 => _188.resolveUsers])
6533
7671
  );
7672
+ const blocks = body.content.flatMap((block, blockIndex) => {
7673
+ switch (block.type) {
7674
+ case "paragraph": {
7675
+ const inlines = block.children.flatMap((inline, inlineIndex) => {
7676
+ if (isCommentBodyMention(inline)) {
7677
+ return inline.id ? [
7678
+ elements.mention(
7679
+ {
7680
+ element: inline,
7681
+ user: resolvedUsers.get(inline.id)
7682
+ },
7683
+ inlineIndex
7684
+ )
7685
+ ] : [];
7686
+ }
7687
+ if (isCommentBodyLink(inline)) {
7688
+ return [
7689
+ elements.link(
7690
+ {
7691
+ element: inline,
7692
+ href: _nullishCoalesce(toAbsoluteUrl(inline.url), () => ( inline.url))
7693
+ },
7694
+ inlineIndex
7695
+ )
7696
+ ];
7697
+ }
7698
+ if (isCommentBodyText(inline)) {
7699
+ return [elements.text({ element: inline }, inlineIndex)];
7700
+ }
7701
+ return [];
7702
+ });
7703
+ return [
7704
+ elements.paragraph(
7705
+ { element: block, children: inlines.join("") },
7706
+ blockIndex
7707
+ )
7708
+ ];
7709
+ }
7710
+ default:
7711
+ return [];
7712
+ }
7713
+ });
7714
+ return blocks.join(separator);
6534
7715
  }
6535
7716
 
6536
7717
  // src/crdts/utils.ts
@@ -6761,12 +7942,12 @@ function legacy_patchImmutableNode(state, path, update) {
6761
7942
  }
6762
7943
  const newState = Object.assign({}, state);
6763
7944
  for (const key in update.updates) {
6764
- if (_optionalChain([update, 'access', _160 => _160.updates, 'access', _161 => _161[key], 'optionalAccess', _162 => _162.type]) === "update") {
7945
+ if (_optionalChain([update, 'access', _189 => _189.updates, 'access', _190 => _190[key], 'optionalAccess', _191 => _191.type]) === "update") {
6765
7946
  const val = update.node.get(key);
6766
7947
  if (val !== void 0) {
6767
7948
  newState[key] = lsonToJson(val);
6768
7949
  }
6769
- } else if (_optionalChain([update, 'access', _163 => _163.updates, 'access', _164 => _164[key], 'optionalAccess', _165 => _165.type]) === "delete") {
7950
+ } else if (_optionalChain([update, 'access', _192 => _192.updates, 'access', _193 => _193[key], 'optionalAccess', _194 => _194.type]) === "delete") {
6770
7951
  delete newState[key];
6771
7952
  }
6772
7953
  }
@@ -6827,12 +8008,12 @@ function legacy_patchImmutableNode(state, path, update) {
6827
8008
  }
6828
8009
  const newState = Object.assign({}, state);
6829
8010
  for (const key in update.updates) {
6830
- if (_optionalChain([update, 'access', _166 => _166.updates, 'access', _167 => _167[key], 'optionalAccess', _168 => _168.type]) === "update") {
8011
+ if (_optionalChain([update, 'access', _195 => _195.updates, 'access', _196 => _196[key], 'optionalAccess', _197 => _197.type]) === "update") {
6831
8012
  const value = update.node.get(key);
6832
8013
  if (value !== void 0) {
6833
8014
  newState[key] = lsonToJson(value);
6834
8015
  }
6835
- } else if (_optionalChain([update, 'access', _169 => _169.updates, 'access', _170 => _170[key], 'optionalAccess', _171 => _171.type]) === "delete") {
8016
+ } else if (_optionalChain([update, 'access', _198 => _198.updates, 'access', _199 => _199[key], 'optionalAccess', _200 => _200.type]) === "delete") {
6836
8017
  delete newState[key];
6837
8018
  }
6838
8019
  }
@@ -6864,161 +8045,6 @@ function legacy_patchImmutableNode(state, path, update) {
6864
8045
  }
6865
8046
  }
6866
8047
 
6867
- // src/lib/shallow.ts
6868
- function shallowArray(xs, ys) {
6869
- if (xs.length !== ys.length) {
6870
- return false;
6871
- }
6872
- for (let i = 0; i < xs.length; i++) {
6873
- if (!Object.is(xs[i], ys[i])) {
6874
- return false;
6875
- }
6876
- }
6877
- return true;
6878
- }
6879
- function shallowObj(objA, objB) {
6880
- 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]") {
6881
- return false;
6882
- }
6883
- const keysA = Object.keys(objA);
6884
- if (keysA.length !== Object.keys(objB).length) {
6885
- return false;
6886
- }
6887
- return keysA.every(
6888
- (key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
6889
- );
6890
- }
6891
- function shallow(a, b) {
6892
- if (Object.is(a, b)) {
6893
- return true;
6894
- }
6895
- const isArrayA = Array.isArray(a);
6896
- const isArrayB = Array.isArray(b);
6897
- if (isArrayA || isArrayB) {
6898
- if (!isArrayA || !isArrayB) {
6899
- return false;
6900
- }
6901
- return shallowArray(a, b);
6902
- }
6903
- return shallowObj(a, b);
6904
- }
6905
-
6906
- // src/lib/AsyncCache.ts
6907
- var noop = () => {
6908
- };
6909
- function isShallowEqual(a, b) {
6910
- if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
6911
- return false;
6912
- } else {
6913
- return shallow(a.data, b.data) && shallow(a.error, b.error);
6914
- }
6915
- }
6916
- function createCacheItem(key, asyncFunction, options) {
6917
- const $asyncFunction = async () => asyncFunction(key);
6918
- const context = {
6919
- isInvalid: true
6920
- };
6921
- let state = { isLoading: false };
6922
- let previousState = { isLoading: false };
6923
- const eventSource2 = makeEventSource();
6924
- function notify() {
6925
- const isEqual = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _172 => _172.isStateEqual]), () => ( isShallowEqual));
6926
- if (!isEqual(previousState, state)) {
6927
- previousState = state;
6928
- eventSource2.notify(state);
6929
- }
6930
- }
6931
- async function resolve() {
6932
- if (!context.promise) {
6933
- return;
6934
- }
6935
- try {
6936
- const data = await context.promise;
6937
- context.isInvalid = false;
6938
- state = {
6939
- isLoading: false,
6940
- data
6941
- };
6942
- } catch (error3) {
6943
- state = {
6944
- isLoading: false,
6945
- data: state.data,
6946
- error: error3
6947
- };
6948
- }
6949
- context.promise = void 0;
6950
- notify();
6951
- }
6952
- async function revalidate() {
6953
- context.isInvalid = true;
6954
- return get();
6955
- }
6956
- async function get() {
6957
- if (context.isInvalid) {
6958
- if (!context.promise) {
6959
- context.isInvalid = true;
6960
- context.promise = $asyncFunction();
6961
- state = { isLoading: true, data: state.data };
6962
- notify();
6963
- }
6964
- await resolve();
6965
- }
6966
- return getState();
6967
- }
6968
- function getState() {
6969
- return state;
6970
- }
6971
- return {
6972
- ...eventSource2.observable,
6973
- get,
6974
- getState,
6975
- revalidate
6976
- };
6977
- }
6978
- function createAsyncCache(asyncFunction, options) {
6979
- const cache = /* @__PURE__ */ new Map();
6980
- function create(key) {
6981
- let cacheItem = cache.get(key);
6982
- if (cacheItem) {
6983
- return cacheItem;
6984
- }
6985
- cacheItem = createCacheItem(key, asyncFunction, options);
6986
- cache.set(key, cacheItem);
6987
- return cacheItem;
6988
- }
6989
- function get(key) {
6990
- return create(key).get();
6991
- }
6992
- function getState(key) {
6993
- return _optionalChain([cache, 'access', _173 => _173.get, 'call', _174 => _174(key), 'optionalAccess', _175 => _175.getState, 'call', _176 => _176()]);
6994
- }
6995
- function revalidate(key) {
6996
- return create(key).revalidate();
6997
- }
6998
- function subscribe(key, callback) {
6999
- return _nullishCoalesce(create(key).subscribe(callback), () => ( noop));
7000
- }
7001
- function subscribeOnce(key, callback) {
7002
- return _nullishCoalesce(create(key).subscribeOnce(callback), () => ( noop));
7003
- }
7004
- function has(key) {
7005
- return cache.has(key);
7006
- }
7007
- function clear() {
7008
- cache.clear();
7009
- }
7010
- return {
7011
- create,
7012
- get,
7013
- getState,
7014
- revalidate,
7015
- subscribe,
7016
- subscribeOnce,
7017
- has,
7018
- clear
7019
- };
7020
- }
7021
-
7022
8048
  // src/lib/Poller.ts
7023
8049
  function makePoller(callback) {
7024
8050
  let context = {
@@ -7108,19 +8134,43 @@ function makePoller(callback) {
7108
8134
  };
7109
8135
  }
7110
8136
 
7111
- // src/lib/stringify.ts
7112
- function stringify(object, ...args) {
7113
- if (typeof object !== "object" || object === null || Array.isArray(object)) {
7114
- return JSON.stringify(object, ...args);
8137
+ // src/lib/shallow.ts
8138
+ function shallowArray(xs, ys) {
8139
+ if (xs.length !== ys.length) {
8140
+ return false;
7115
8141
  }
7116
- const sortedObject = Object.keys(object).sort().reduce(
7117
- (sortedObject2, key) => {
7118
- sortedObject2[key] = object[key];
7119
- return sortedObject2;
7120
- },
7121
- {}
8142
+ for (let i = 0; i < xs.length; i++) {
8143
+ if (!Object.is(xs[i], ys[i])) {
8144
+ return false;
8145
+ }
8146
+ }
8147
+ return true;
8148
+ }
8149
+ function shallowObj(objA, objB) {
8150
+ 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]") {
8151
+ return false;
8152
+ }
8153
+ const keysA = Object.keys(objA);
8154
+ if (keysA.length !== Object.keys(objB).length) {
8155
+ return false;
8156
+ }
8157
+ return keysA.every(
8158
+ (key) => Object.prototype.hasOwnProperty.call(objB, key) && Object.is(objA[key], objB[key])
7122
8159
  );
7123
- return JSON.stringify(sortedObject, ...args);
8160
+ }
8161
+ function shallow(a, b) {
8162
+ if (Object.is(a, b)) {
8163
+ return true;
8164
+ }
8165
+ const isArrayA = Array.isArray(a);
8166
+ const isArrayB = Array.isArray(b);
8167
+ if (isArrayA || isArrayB) {
8168
+ if (!isArrayA || !isArrayB) {
8169
+ return false;
8170
+ }
8171
+ return shallowArray(a, b);
8172
+ }
8173
+ return shallowObj(a, b);
7124
8174
  }
7125
8175
 
7126
8176
  // src/index.ts
@@ -7175,5 +8225,13 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
7175
8225
 
7176
8226
 
7177
8227
 
7178
- 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.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;
8228
+
8229
+
8230
+
8231
+
8232
+
8233
+
8234
+
8235
+
8236
+ 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.addReaction = addReaction; 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.convertToInboxNotificationData = convertToInboxNotificationData; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.deleteComment = deleteComment; 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.objectToQuery = objectToQuery; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.removeReaction = removeReaction; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.upsertComment = upsertComment; exports.withTimeout = withTimeout;
7179
8237
  //# sourceMappingURL=index.js.map