@liveblocks/core 1.10.0-beta2 → 1.10.0-beta4

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.10.0-beta2";
9
+ var PKG_VERSION = "1.10.0-beta4";
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,7 @@ 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["KICKED"] = 4100] = "KICKED";
664
672
  WebsocketCloseCodes2[WebsocketCloseCodes2["TOKEN_EXPIRED"] = 4109] = "TOKEN_EXPIRED";
665
673
  WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_WITHOUT_RETRY"] = 4999] = "CLOSE_WITHOUT_RETRY";
666
674
  return WebsocketCloseCodes2;
@@ -728,6 +736,7 @@ var StopRetrying = class extends Error {
728
736
  }
729
737
  };
730
738
  var LiveblocksError = class extends Error {
739
+ /** @internal */
731
740
  constructor(message, code) {
732
741
  super(message);
733
742
  this.code = code;
@@ -942,14 +951,16 @@ function createConnectionStateMachine(delegates, options) {
942
951
  // When the "open" event happens, we're ready to transition to the
943
952
  // OK state. This is done by resolving the Promise.
944
953
  //
945
- async (ctx) => {
954
+ async (ctx, signal) => {
946
955
  let capturedPrematureEvent = null;
956
+ let unconfirmedSocket = null;
947
957
  const connect$ = new Promise(
948
958
  (resolve, rej) => {
949
959
  if (ctx.authValue === null) {
950
960
  throw new Error("No auth authValue");
951
961
  }
952
962
  const socket = delegates.createSocket(ctx.authValue);
963
+ unconfirmedSocket = socket;
953
964
  function reject(event) {
954
965
  capturedPrematureEvent = event;
955
966
  socket.removeEventListener("message", onSocketMessage);
@@ -1005,12 +1016,18 @@ function createConnectionStateMachine(delegates, options) {
1005
1016
  //
1006
1017
  ([socket, unsub]) => {
1007
1018
  unsub();
1019
+ if (signal.aborted) {
1020
+ throw new Error("Aborted");
1021
+ }
1008
1022
  if (capturedPrematureEvent) {
1009
1023
  throw capturedPrematureEvent;
1010
1024
  }
1011
1025
  return socket;
1012
1026
  }
1013
- );
1027
+ ).catch((e) => {
1028
+ teardownSocket(unconfirmedSocket);
1029
+ throw e;
1030
+ });
1014
1031
  },
1015
1032
  // Only transition to OK state after a successfully opened WebSocket connection
1016
1033
  (okEvent) => ({
@@ -1325,7 +1342,7 @@ function createAuthManager(authOptions) {
1325
1342
  }
1326
1343
  return false;
1327
1344
  }
1328
- function getCachedToken(roomOptions) {
1345
+ function getCachedToken(requestOptions) {
1329
1346
  const now = Math.ceil(Date.now() / 1e3);
1330
1347
  for (let i = tokens.length - 1; i >= 0; i--) {
1331
1348
  const token = tokens[i];
@@ -1338,11 +1355,15 @@ function createAuthManager(authOptions) {
1338
1355
  if (token.parsed.k === "id" /* ID_TOKEN */) {
1339
1356
  return token;
1340
1357
  } else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
1341
- if (!roomOptions) {
1358
+ if (!requestOptions.roomId && Object.entries(token.parsed.perms).length === 0) {
1342
1359
  return token;
1343
1360
  }
1344
1361
  for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
1345
- if (resource.includes("*") && roomOptions.roomId.startsWith(resource.replace("*", "")) || roomOptions.roomId === resource && hasCorrespondingScopes(roomOptions.requestedScope, scopes)) {
1362
+ if (!requestOptions.roomId) {
1363
+ if (resource.includes("*") && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
1364
+ return token;
1365
+ }
1366
+ } else if (resource.includes("*") && requestOptions.roomId.startsWith(resource.replace("*", "")) || requestOptions.roomId === resource && hasCorrespondingScopes(requestOptions.requestedScope, scopes)) {
1346
1367
  return token;
1347
1368
  }
1348
1369
  }
@@ -1350,7 +1371,7 @@ function createAuthManager(authOptions) {
1350
1371
  }
1351
1372
  return void 0;
1352
1373
  }
1353
- async function makeAuthRequest(roomId) {
1374
+ async function makeAuthRequest(options) {
1354
1375
  const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _36 => _36.polyfills, 'optionalAccess', _37 => _37.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
1355
1376
  if (authentication.type === "private") {
1356
1377
  if (fetcher === void 0) {
@@ -1359,9 +1380,10 @@ function createAuthManager(authOptions) {
1359
1380
  );
1360
1381
  }
1361
1382
  const response = await fetchAuthEndpoint(fetcher, authentication.url, {
1362
- room: roomId
1383
+ room: options.roomId
1363
1384
  });
1364
1385
  const parsed = parseAuthToken(response.token);
1386
+ verifyTokenPermissions(parsed, options);
1365
1387
  if (seenTokens.has(parsed.raw)) {
1366
1388
  throw new StopRetrying(
1367
1389
  "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported."
@@ -1370,10 +1392,12 @@ function createAuthManager(authOptions) {
1370
1392
  return parsed;
1371
1393
  }
1372
1394
  if (authentication.type === "custom") {
1373
- const response = await authentication.callback(roomId);
1395
+ const response = await authentication.callback(options.roomId);
1374
1396
  if (response && typeof response === "object") {
1375
1397
  if (typeof response.token === "string") {
1376
- return parseAuthToken(response.token);
1398
+ const parsed = parseAuthToken(response.token);
1399
+ verifyTokenPermissions(parsed, options);
1400
+ return parsed;
1377
1401
  } else if (typeof response.error === "string") {
1378
1402
  const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
1379
1403
  if (response.error === "forbidden") {
@@ -1391,25 +1415,42 @@ function createAuthManager(authOptions) {
1391
1415
  "Unexpected authentication type. Must be private or custom."
1392
1416
  );
1393
1417
  }
1394
- async function getAuthValue(roomOptions) {
1418
+ function verifyTokenPermissions(parsedToken, options) {
1419
+ if (!options.roomId && parsedToken.parsed.k === "acc" /* ACCESS_TOKEN */) {
1420
+ if (Object.entries(parsedToken.parsed.perms).length === 0) {
1421
+ return;
1422
+ }
1423
+ for (const [resource, scopes] of Object.entries(
1424
+ parsedToken.parsed.perms
1425
+ )) {
1426
+ if (resource.includes("*") && hasCorrespondingScopes(options.requestedScope, scopes)) {
1427
+ return;
1428
+ }
1429
+ }
1430
+ throw new StopRetrying(
1431
+ "The issued access token doesn't grant enough permissions. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/access-tokens-not-enough-permissions"
1432
+ );
1433
+ }
1434
+ }
1435
+ async function getAuthValue(requestOptions) {
1395
1436
  if (authentication.type === "public") {
1396
1437
  return { type: "public", publicApiKey: authentication.publicApiKey };
1397
1438
  }
1398
- const cachedToken = getCachedToken(roomOptions);
1439
+ const cachedToken = getCachedToken(requestOptions);
1399
1440
  if (cachedToken !== void 0) {
1400
1441
  return { type: "secret", token: cachedToken };
1401
1442
  }
1402
1443
  let currentPromise;
1403
- if (roomOptions) {
1404
- currentPromise = requestPromises.get(roomOptions.roomId);
1444
+ if (requestOptions.roomId) {
1445
+ currentPromise = requestPromises.get(requestOptions.roomId);
1405
1446
  if (currentPromise === void 0) {
1406
- currentPromise = makeAuthRequest(roomOptions.roomId);
1407
- requestPromises.set(roomOptions.roomId, currentPromise);
1447
+ currentPromise = makeAuthRequest(requestOptions);
1448
+ requestPromises.set(requestOptions.roomId, currentPromise);
1408
1449
  }
1409
1450
  } else {
1410
1451
  currentPromise = requestPromises.get("liveblocks-user-token");
1411
1452
  if (currentPromise === void 0) {
1412
- currentPromise = makeAuthRequest();
1453
+ currentPromise = makeAuthRequest(requestOptions);
1413
1454
  requestPromises.set("liveblocks-user-token", currentPromise);
1414
1455
  }
1415
1456
  }
@@ -1424,8 +1465,8 @@ function createAuthManager(authOptions) {
1424
1465
  }
1425
1466
  return { type: "secret", token };
1426
1467
  } finally {
1427
- if (roomOptions) {
1428
- requestPromises.delete(roomOptions.roomId);
1468
+ if (requestOptions.roomId) {
1469
+ requestPromises.delete(requestOptions.roomId);
1429
1470
  } else {
1430
1471
  requestPromises.delete("liveblocks-user-token");
1431
1472
  }
@@ -1996,22 +2037,56 @@ function convertToInboxNotificationData(data) {
1996
2037
  readAt
1997
2038
  };
1998
2039
  }
2040
+ function convertToThreadDeleteInfo(data) {
2041
+ const deletedAt = new Date(data.deletedAt);
2042
+ return {
2043
+ ...data,
2044
+ deletedAt
2045
+ };
2046
+ }
2047
+ function convertToInboxNotificationDeleteInfo(data) {
2048
+ const deletedAt = new Date(data.deletedAt);
2049
+ return {
2050
+ ...data,
2051
+ deletedAt
2052
+ };
2053
+ }
2054
+
2055
+ // src/lib/url.ts
2056
+ function toURLSearchParams(params) {
2057
+ const result = new URLSearchParams();
2058
+ for (const [key, value] of Object.entries(params)) {
2059
+ if (value !== void 0 && value !== null) {
2060
+ result.set(key, value.toString());
2061
+ }
2062
+ }
2063
+ return result;
2064
+ }
2065
+ function urljoin(baseUrl, path, params) {
2066
+ const url = new URL(path, baseUrl);
2067
+ if (params !== void 0) {
2068
+ url.search = (params instanceof URLSearchParams ? params : toURLSearchParams(params)).toString();
2069
+ }
2070
+ return url.toString();
2071
+ }
1999
2072
 
2000
2073
  // src/notifications.ts
2001
2074
  var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY = 50;
2002
- function createInboxNotificationsApi({
2075
+ function createNotificationsApi({
2003
2076
  baseUrl,
2004
2077
  authManager,
2005
2078
  currentUserIdStore,
2006
2079
  fetcher
2007
2080
  }) {
2008
- async function fetchJson(endpoint, options) {
2009
- const authValue = await authManager.getAuthValue();
2081
+ async function fetchJson(endpoint, options, params) {
2082
+ const authValue = await authManager.getAuthValue({
2083
+ requestedScope: "comments:read"
2084
+ });
2010
2085
  if (authValue.type === "secret" && authValue.token.parsed.k === "acc" /* ACCESS_TOKEN */) {
2011
2086
  const userId = authValue.token.parsed.uid;
2012
2087
  currentUserIdStore.set(() => userId);
2013
2088
  }
2014
- const url = new URL(`/v2/c${endpoint}`, baseUrl);
2089
+ const url = urljoin(baseUrl, `/v2/c${endpoint}`, params);
2015
2090
  const response = await fetcher(url.toString(), {
2016
2091
  ...options,
2017
2092
  headers: {
@@ -2047,13 +2122,24 @@ function createInboxNotificationsApi({
2047
2122
  return body;
2048
2123
  }
2049
2124
  async function getInboxNotifications(options) {
2050
- const queryParams = toURLSearchParams({ limit: _optionalChain([options, 'optionalAccess', _48 => _48.limit]) });
2051
- const json = await fetchJson(`/inbox-notifications?${queryParams.toString()}`);
2125
+ const json = await fetchJson("/inbox-notifications", void 0, {
2126
+ limit: _optionalChain([options, 'optionalAccess', _48 => _48.limit]),
2127
+ since: _optionalChain([options, 'optionalAccess', _49 => _49.since, 'optionalAccess', _50 => _50.toISOString, 'call', _51 => _51()])
2128
+ });
2052
2129
  return {
2053
2130
  threads: json.threads.map((thread) => convertToThreadData(thread)),
2054
2131
  inboxNotifications: json.inboxNotifications.map(
2055
2132
  (notification) => convertToInboxNotificationData(notification)
2056
- )
2133
+ ),
2134
+ deletedThreads: json.deletedThreads.map(
2135
+ (info) => convertToThreadDeleteInfo(info)
2136
+ ),
2137
+ deletedInboxNotifications: json.deletedInboxNotifications.map(
2138
+ (info) => convertToInboxNotificationDeleteInfo(info)
2139
+ ),
2140
+ meta: {
2141
+ requestedAt: new Date(json.meta.requestedAt)
2142
+ }
2057
2143
  };
2058
2144
  }
2059
2145
  async function getUnreadInboxNotificationsCount() {
@@ -2096,15 +2182,6 @@ function createInboxNotificationsApi({
2096
2182
  markInboxNotificationAsRead
2097
2183
  };
2098
2184
  }
2099
- function toURLSearchParams(params) {
2100
- const result = new URLSearchParams();
2101
- for (const [key, value] of Object.entries(params)) {
2102
- if (value !== void 0 && value !== null) {
2103
- result.set(key, value.toString());
2104
- }
2105
- }
2106
- return result;
2107
- }
2108
2185
 
2109
2186
  // src/lib/position.ts
2110
2187
  var MIN_CODE = 32;
@@ -2479,7 +2556,7 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
2479
2556
  return [
2480
2557
  {
2481
2558
  type: 8 /* CREATE_REGISTER */,
2482
- opId: _optionalChain([pool, 'optionalAccess', _49 => _49.generateOpId, 'call', _50 => _50()]),
2559
+ opId: _optionalChain([pool, 'optionalAccess', _52 => _52.generateOpId, 'call', _53 => _53()]),
2483
2560
  id: this._id,
2484
2561
  parentId,
2485
2562
  parentKey,
@@ -2581,7 +2658,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2581
2658
  const ops = [];
2582
2659
  const op = {
2583
2660
  id: this._id,
2584
- opId: _optionalChain([pool, 'optionalAccess', _51 => _51.generateOpId, 'call', _52 => _52()]),
2661
+ opId: _optionalChain([pool, 'optionalAccess', _54 => _54.generateOpId, 'call', _55 => _55()]),
2585
2662
  type: 2 /* CREATE_LIST */,
2586
2663
  parentId,
2587
2664
  parentKey
@@ -2858,7 +2935,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2858
2935
  _applyInsertUndoRedo(op) {
2859
2936
  const { id, parentKey: key } = op;
2860
2937
  const child = creationOpToLiveNode(op);
2861
- if (_optionalChain([this, 'access', _53 => _53._pool, 'optionalAccess', _54 => _54.getNode, 'call', _55 => _55(id)]) !== void 0) {
2938
+ if (_optionalChain([this, 'access', _56 => _56._pool, 'optionalAccess', _57 => _57.getNode, 'call', _58 => _58(id)]) !== void 0) {
2862
2939
  return { modified: false };
2863
2940
  }
2864
2941
  child._attach(id, nn(this._pool));
@@ -2866,8 +2943,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
2866
2943
  const existingItemIndex = this._indexOfPosition(key);
2867
2944
  let newKey = key;
2868
2945
  if (existingItemIndex !== -1) {
2869
- const before2 = _optionalChain([this, 'access', _56 => _56._items, 'access', _57 => _57[existingItemIndex], 'optionalAccess', _58 => _58._parentPos]);
2870
- const after2 = _optionalChain([this, 'access', _59 => _59._items, 'access', _60 => _60[existingItemIndex + 1], 'optionalAccess', _61 => _61._parentPos]);
2946
+ const before2 = _optionalChain([this, 'access', _59 => _59._items, 'access', _60 => _60[existingItemIndex], 'optionalAccess', _61 => _61._parentPos]);
2947
+ const after2 = _optionalChain([this, 'access', _62 => _62._items, 'access', _63 => _63[existingItemIndex + 1], 'optionalAccess', _64 => _64._parentPos]);
2871
2948
  newKey = makePosition(before2, after2);
2872
2949
  child._setParentLink(this, newKey);
2873
2950
  }
@@ -2882,7 +2959,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2882
2959
  _applySetUndoRedo(op) {
2883
2960
  const { id, parentKey: key } = op;
2884
2961
  const child = creationOpToLiveNode(op);
2885
- if (_optionalChain([this, 'access', _62 => _62._pool, 'optionalAccess', _63 => _63.getNode, 'call', _64 => _64(id)]) !== void 0) {
2962
+ if (_optionalChain([this, 'access', _65 => _65._pool, 'optionalAccess', _66 => _66.getNode, 'call', _67 => _67(id)]) !== void 0) {
2886
2963
  return { modified: false };
2887
2964
  }
2888
2965
  this._unacknowledgedSets.set(key, nn(op.opId));
@@ -3004,7 +3081,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3004
3081
  } else {
3005
3082
  this._items[existingItemIndex]._setParentLink(
3006
3083
  this,
3007
- makePosition(newKey, _optionalChain([this, 'access', _65 => _65._items, 'access', _66 => _66[existingItemIndex + 1], 'optionalAccess', _67 => _67._parentPos]))
3084
+ makePosition(newKey, _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]))
3008
3085
  );
3009
3086
  const previousIndex = this._items.indexOf(child);
3010
3087
  child._setParentLink(this, newKey);
@@ -3030,7 +3107,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3030
3107
  if (existingItemIndex !== -1) {
3031
3108
  this._items[existingItemIndex]._setParentLink(
3032
3109
  this,
3033
- makePosition(newKey, _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]))
3110
+ makePosition(newKey, _optionalChain([this, 'access', _71 => _71._items, 'access', _72 => _72[existingItemIndex + 1], 'optionalAccess', _73 => _73._parentPos]))
3034
3111
  );
3035
3112
  }
3036
3113
  child._setParentLink(this, newKey);
@@ -3049,7 +3126,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3049
3126
  if (existingItemIndex !== -1) {
3050
3127
  this._items[existingItemIndex]._setParentLink(
3051
3128
  this,
3052
- makePosition(newKey, _optionalChain([this, 'access', _71 => _71._items, 'access', _72 => _72[existingItemIndex + 1], 'optionalAccess', _73 => _73._parentPos]))
3129
+ makePosition(newKey, _optionalChain([this, 'access', _74 => _74._items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]))
3053
3130
  );
3054
3131
  }
3055
3132
  child._setParentLink(this, newKey);
@@ -3077,7 +3154,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3077
3154
  if (existingItemIndex !== -1) {
3078
3155
  this._items[existingItemIndex]._setParentLink(
3079
3156
  this,
3080
- makePosition(newKey, _optionalChain([this, 'access', _74 => _74._items, 'access', _75 => _75[existingItemIndex + 1], 'optionalAccess', _76 => _76._parentPos]))
3157
+ makePosition(newKey, _optionalChain([this, 'access', _77 => _77._items, 'access', _78 => _78[existingItemIndex + 1], 'optionalAccess', _79 => _79._parentPos]))
3081
3158
  );
3082
3159
  }
3083
3160
  child._setParentLink(this, newKey);
@@ -3135,7 +3212,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3135
3212
  * @param element The element to add to the end of the LiveList.
3136
3213
  */
3137
3214
  push(element) {
3138
- _optionalChain([this, 'access', _77 => _77._pool, 'optionalAccess', _78 => _78.assertStorageIsWritable, 'call', _79 => _79()]);
3215
+ _optionalChain([this, 'access', _80 => _80._pool, 'optionalAccess', _81 => _81.assertStorageIsWritable, 'call', _82 => _82()]);
3139
3216
  return this.insert(element, this.length);
3140
3217
  }
3141
3218
  /**
@@ -3144,7 +3221,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3144
3221
  * @param index The index at which you want to insert the element.
3145
3222
  */
3146
3223
  insert(element, index) {
3147
- _optionalChain([this, 'access', _80 => _80._pool, 'optionalAccess', _81 => _81.assertStorageIsWritable, 'call', _82 => _82()]);
3224
+ _optionalChain([this, 'access', _83 => _83._pool, 'optionalAccess', _84 => _84.assertStorageIsWritable, 'call', _85 => _85()]);
3148
3225
  if (index < 0 || index > this._items.length) {
3149
3226
  throw new Error(
3150
3227
  `Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
@@ -3174,7 +3251,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3174
3251
  * @param targetIndex The index where the element should be after moving.
3175
3252
  */
3176
3253
  move(index, targetIndex) {
3177
- _optionalChain([this, 'access', _83 => _83._pool, 'optionalAccess', _84 => _84.assertStorageIsWritable, 'call', _85 => _85()]);
3254
+ _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
3178
3255
  if (targetIndex < 0) {
3179
3256
  throw new Error("targetIndex cannot be less than 0");
3180
3257
  }
@@ -3232,7 +3309,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3232
3309
  * @param index The index of the element to delete
3233
3310
  */
3234
3311
  delete(index) {
3235
- _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
3312
+ _optionalChain([this, 'access', _89 => _89._pool, 'optionalAccess', _90 => _90.assertStorageIsWritable, 'call', _91 => _91()]);
3236
3313
  if (index < 0 || index >= this._items.length) {
3237
3314
  throw new Error(
3238
3315
  `Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -3265,7 +3342,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3265
3342
  }
3266
3343
  }
3267
3344
  clear() {
3268
- _optionalChain([this, 'access', _89 => _89._pool, 'optionalAccess', _90 => _90.assertStorageIsWritable, 'call', _91 => _91()]);
3345
+ _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
3269
3346
  if (this._pool) {
3270
3347
  const ops = [];
3271
3348
  const reverseOps = [];
@@ -3299,7 +3376,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3299
3376
  }
3300
3377
  }
3301
3378
  set(index, item) {
3302
- _optionalChain([this, 'access', _92 => _92._pool, 'optionalAccess', _93 => _93.assertStorageIsWritable, 'call', _94 => _94()]);
3379
+ _optionalChain([this, 'access', _95 => _95._pool, 'optionalAccess', _96 => _96.assertStorageIsWritable, 'call', _97 => _97()]);
3303
3380
  if (index < 0 || index >= this._items.length) {
3304
3381
  throw new Error(
3305
3382
  `Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -3447,7 +3524,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
3447
3524
  _shiftItemPosition(index, key) {
3448
3525
  const shiftedPosition = makePosition(
3449
3526
  key,
3450
- this._items.length > index + 1 ? _optionalChain([this, 'access', _95 => _95._items, 'access', _96 => _96[index + 1], 'optionalAccess', _97 => _97._parentPos]) : void 0
3527
+ this._items.length > index + 1 ? _optionalChain([this, 'access', _98 => _98._items, 'access', _99 => _99[index + 1], 'optionalAccess', _100 => _100._parentPos]) : void 0
3451
3528
  );
3452
3529
  this._items[index]._setParentLink(this, shiftedPosition);
3453
3530
  }
@@ -3576,7 +3653,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3576
3653
  const ops = [];
3577
3654
  const op = {
3578
3655
  id: this._id,
3579
- opId: _optionalChain([pool, 'optionalAccess', _98 => _98.generateOpId, 'call', _99 => _99()]),
3656
+ opId: _optionalChain([pool, 'optionalAccess', _101 => _101.generateOpId, 'call', _102 => _102()]),
3580
3657
  type: 7 /* CREATE_MAP */,
3581
3658
  parentId,
3582
3659
  parentKey
@@ -3723,7 +3800,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3723
3800
  * @param value The value of the element to add. Should be serializable to JSON.
3724
3801
  */
3725
3802
  set(key, value) {
3726
- _optionalChain([this, 'access', _100 => _100._pool, 'optionalAccess', _101 => _101.assertStorageIsWritable, 'call', _102 => _102()]);
3803
+ _optionalChain([this, 'access', _103 => _103._pool, 'optionalAccess', _104 => _104.assertStorageIsWritable, 'call', _105 => _105()]);
3727
3804
  const oldValue = this._map.get(key);
3728
3805
  if (oldValue) {
3729
3806
  oldValue._detach();
@@ -3769,7 +3846,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
3769
3846
  * @returns true if an element existed and has been removed, or false if the element does not exist.
3770
3847
  */
3771
3848
  delete(key) {
3772
- _optionalChain([this, 'access', _103 => _103._pool, 'optionalAccess', _104 => _104.assertStorageIsWritable, 'call', _105 => _105()]);
3849
+ _optionalChain([this, 'access', _106 => _106._pool, 'optionalAccess', _107 => _107.assertStorageIsWritable, 'call', _108 => _108()]);
3773
3850
  const item = this._map.get(key);
3774
3851
  if (item === void 0) {
3775
3852
  return false;
@@ -3948,7 +4025,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
3948
4025
  if (this._id === void 0) {
3949
4026
  throw new Error("Cannot serialize item is not attached");
3950
4027
  }
3951
- const opId = _optionalChain([pool, 'optionalAccess', _106 => _106.generateOpId, 'call', _107 => _107()]);
4028
+ const opId = _optionalChain([pool, 'optionalAccess', _109 => _109.generateOpId, 'call', _110 => _110()]);
3952
4029
  const ops = [];
3953
4030
  const op = {
3954
4031
  type: 4 /* CREATE_OBJECT */,
@@ -4226,7 +4303,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4226
4303
  * @param value The value of the property to add
4227
4304
  */
4228
4305
  set(key, value) {
4229
- _optionalChain([this, 'access', _108 => _108._pool, 'optionalAccess', _109 => _109.assertStorageIsWritable, 'call', _110 => _110()]);
4306
+ _optionalChain([this, 'access', _111 => _111._pool, 'optionalAccess', _112 => _112.assertStorageIsWritable, 'call', _113 => _113()]);
4230
4307
  this.update({ [key]: value });
4231
4308
  }
4232
4309
  /**
@@ -4241,7 +4318,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4241
4318
  * @param key The key of the property to delete
4242
4319
  */
4243
4320
  delete(key) {
4244
- _optionalChain([this, 'access', _111 => _111._pool, 'optionalAccess', _112 => _112.assertStorageIsWritable, 'call', _113 => _113()]);
4321
+ _optionalChain([this, 'access', _114 => _114._pool, 'optionalAccess', _115 => _115.assertStorageIsWritable, 'call', _116 => _116()]);
4245
4322
  const keyAsString = key;
4246
4323
  const oldValue = this._map.get(keyAsString);
4247
4324
  if (oldValue === void 0) {
@@ -4294,7 +4371,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
4294
4371
  * @param patch The object used to overrides properties
4295
4372
  */
4296
4373
  update(patch) {
4297
- _optionalChain([this, 'access', _114 => _114._pool, 'optionalAccess', _115 => _115.assertStorageIsWritable, 'call', _116 => _116()]);
4374
+ _optionalChain([this, 'access', _117 => _117._pool, 'optionalAccess', _118 => _118.assertStorageIsWritable, 'call', _119 => _119()]);
4298
4375
  if (this._pool === void 0 || this._id === void 0) {
4299
4376
  for (const key in patch) {
4300
4377
  const newValue = patch[key];
@@ -4938,15 +5015,15 @@ function installBackgroundTabSpy() {
4938
5015
  const doc = typeof document !== "undefined" ? document : void 0;
4939
5016
  const inBackgroundSince = { current: null };
4940
5017
  function onVisibilityChange() {
4941
- if (_optionalChain([doc, 'optionalAccess', _117 => _117.visibilityState]) === "hidden") {
5018
+ if (_optionalChain([doc, 'optionalAccess', _120 => _120.visibilityState]) === "hidden") {
4942
5019
  inBackgroundSince.current = _nullishCoalesce(inBackgroundSince.current, () => ( Date.now()));
4943
5020
  } else {
4944
5021
  inBackgroundSince.current = null;
4945
5022
  }
4946
5023
  }
4947
- _optionalChain([doc, 'optionalAccess', _118 => _118.addEventListener, 'call', _119 => _119("visibilitychange", onVisibilityChange)]);
5024
+ _optionalChain([doc, 'optionalAccess', _121 => _121.addEventListener, 'call', _122 => _122("visibilitychange", onVisibilityChange)]);
4948
5025
  const unsub = () => {
4949
- _optionalChain([doc, 'optionalAccess', _120 => _120.removeEventListener, 'call', _121 => _121("visibilitychange", onVisibilityChange)]);
5026
+ _optionalChain([doc, 'optionalAccess', _123 => _123.removeEventListener, 'call', _124 => _124("visibilitychange", onVisibilityChange)]);
4950
5027
  };
4951
5028
  return [inBackgroundSince, unsub];
4952
5029
  }
@@ -4959,12 +5036,12 @@ var CommentsApiError = class extends Error {
4959
5036
  }
4960
5037
  };
4961
5038
  function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
4962
- async function fetchCommentsApi(endpoint, options) {
5039
+ async function fetchCommentsApi(endpoint, params, options) {
4963
5040
  const authValue = await getAuthValue();
4964
- return fetchClientApi(roomId, endpoint, authValue, options);
5041
+ return fetchClientApi(roomId, endpoint, authValue, options, params);
4965
5042
  }
4966
- async function fetchJson(endpoint, options) {
4967
- const response = await fetchCommentsApi(endpoint, options);
5043
+ async function fetchJson(endpoint, options, params) {
5044
+ const response = await fetchCommentsApi(endpoint, params, options);
4968
5045
  if (!response.ok) {
4969
5046
  if (response.status >= 400 && response.status < 600) {
4970
5047
  let error3;
@@ -4990,25 +5067,48 @@ function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
4990
5067
  return body;
4991
5068
  }
4992
5069
  async function getThreads(options) {
4993
- const response = await fetchCommentsApi("/threads/search", {
4994
- body: JSON.stringify({
4995
- ..._optionalChain([options, 'optionalAccess', _122 => _122.query, 'optionalAccess', _123 => _123.metadata]) && { metadata: options.query.metadata }
4996
- }),
4997
- headers: {
4998
- "Content-Type": "application/json"
5070
+ const response = await fetchCommentsApi(
5071
+ "/threads/search",
5072
+ {
5073
+ since: _optionalChain([options, 'optionalAccess', _125 => _125.since, 'optionalAccess', _126 => _126.toISOString, 'call', _127 => _127()])
4999
5074
  },
5000
- method: "POST"
5001
- });
5075
+ {
5076
+ body: JSON.stringify({
5077
+ ..._optionalChain([options, 'optionalAccess', _128 => _128.query, 'optionalAccess', _129 => _129.metadata]) && { metadata: options.query.metadata }
5078
+ }),
5079
+ headers: {
5080
+ "Content-Type": "application/json"
5081
+ },
5082
+ method: "POST"
5083
+ }
5084
+ );
5002
5085
  if (response.ok) {
5003
5086
  const json = await response.json();
5004
5087
  return {
5005
5088
  threads: json.data.map((thread) => convertToThreadData(thread)),
5006
5089
  inboxNotifications: json.inboxNotifications.map(
5007
5090
  (notification) => convertToInboxNotificationData(notification)
5008
- )
5091
+ ),
5092
+ deletedThreads: json.deletedThreads.map(
5093
+ (info) => convertToThreadDeleteInfo(info)
5094
+ ),
5095
+ deletedInboxNotifications: json.deletedInboxNotifications.map(
5096
+ (info) => convertToInboxNotificationDeleteInfo(info)
5097
+ ),
5098
+ meta: {
5099
+ requestedAt: new Date(json.meta.requestedAt)
5100
+ }
5009
5101
  };
5010
5102
  } else if (response.status === 404) {
5011
- return { threads: [], inboxNotifications: [] };
5103
+ return {
5104
+ threads: [],
5105
+ inboxNotifications: [],
5106
+ deletedThreads: [],
5107
+ deletedInboxNotifications: [],
5108
+ meta: {
5109
+ requestedAt: /* @__PURE__ */ new Date()
5110
+ }
5111
+ };
5012
5112
  } else {
5013
5113
  throw new Error("There was an error while getting threads.");
5014
5114
  }
@@ -5110,7 +5210,7 @@ function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
5110
5210
  );
5111
5211
  return convertToCommentData(comment);
5112
5212
  }
5113
- async function deleteComment({
5213
+ async function deleteComment2({
5114
5214
  threadId,
5115
5215
  commentId
5116
5216
  }) {
@@ -5123,7 +5223,7 @@ function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
5123
5223
  }
5124
5224
  );
5125
5225
  }
5126
- async function addReaction({
5226
+ async function addReaction2({
5127
5227
  threadId,
5128
5228
  commentId,
5129
5229
  emoji
@@ -5142,7 +5242,7 @@ function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
5142
5242
  );
5143
5243
  return convertToCommentUserReaction(reaction);
5144
5244
  }
5145
- async function removeReaction({
5245
+ async function removeReaction2({
5146
5246
  threadId,
5147
5247
  commentId,
5148
5248
  emoji
@@ -5163,11 +5263,12 @@ function createCommentsApi(roomId, getAuthValue, fetchClientApi) {
5163
5263
  editThreadMetadata,
5164
5264
  createComment,
5165
5265
  editComment,
5166
- deleteComment,
5167
- addReaction,
5168
- removeReaction
5266
+ deleteComment: deleteComment2,
5267
+ addReaction: addReaction2,
5268
+ removeReaction: removeReaction2
5169
5269
  };
5170
5270
  }
5271
+ var MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY2 = 50;
5171
5272
  function createRoom(options, config) {
5172
5273
  const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
5173
5274
  const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
@@ -5353,7 +5454,7 @@ function createRoom(options, config) {
5353
5454
  }
5354
5455
  },
5355
5456
  assertStorageIsWritable: () => {
5356
- const scopes = _optionalChain([context, 'access', _124 => _124.dynamicSessionInfo, 'access', _125 => _125.current, 'optionalAccess', _126 => _126.scopes]);
5457
+ const scopes = _optionalChain([context, 'access', _130 => _130.dynamicSessionInfo, 'access', _131 => _131.current, 'optionalAccess', _132 => _132.scopes]);
5357
5458
  if (scopes === void 0) {
5358
5459
  return;
5359
5460
  }
@@ -5383,17 +5484,18 @@ function createRoom(options, config) {
5383
5484
  ydoc: makeEventSource(),
5384
5485
  comments: makeEventSource()
5385
5486
  };
5386
- async function fetchClientApi(roomId, endpoint, authValue, options2) {
5387
- const url = new URL(
5487
+ async function fetchClientApi(roomId, endpoint, authValue, options2, params) {
5488
+ const url = urljoin(
5489
+ config.baseUrl,
5388
5490
  `/v2/c/rooms/${encodeURIComponent(roomId)}${endpoint}`,
5389
- config.baseUrl
5491
+ params
5390
5492
  );
5391
- const fetcher = _optionalChain([config, 'access', _127 => _127.polyfills, 'optionalAccess', _128 => _128.fetch]) || /* istanbul ignore next */
5493
+ const fetcher = _optionalChain([config, 'access', _133 => _133.polyfills, 'optionalAccess', _134 => _134.fetch]) || /* istanbul ignore next */
5392
5494
  fetch;
5393
- return await fetcher(url.toString(), {
5495
+ return await fetcher(url, {
5394
5496
  ...options2,
5395
5497
  headers: {
5396
- ..._optionalChain([options2, 'optionalAccess', _129 => _129.headers]),
5498
+ ..._optionalChain([options2, 'optionalAccess', _135 => _135.headers]),
5397
5499
  Authorization: `Bearer ${getAuthBearerHeaderFromAuthValue(authValue)}`
5398
5500
  }
5399
5501
  });
@@ -5420,7 +5522,7 @@ function createRoom(options, config) {
5420
5522
  }
5421
5523
  function sendMessages(messages) {
5422
5524
  const serializedPayload = JSON.stringify(messages);
5423
- const nonce = _optionalChain([context, 'access', _130 => _130.dynamicSessionInfo, 'access', _131 => _131.current, 'optionalAccess', _132 => _132.nonce]);
5525
+ const nonce = _optionalChain([context, 'access', _136 => _136.dynamicSessionInfo, 'access', _137 => _137.current, 'optionalAccess', _138 => _138.nonce]);
5424
5526
  if (config.unstable_fallbackToHTTP && nonce) {
5425
5527
  const size = new TextEncoder().encode(serializedPayload).length;
5426
5528
  if (size > MAX_SOCKET_MESSAGE_SIZE) {
@@ -5682,7 +5784,7 @@ function createRoom(options, config) {
5682
5784
  }
5683
5785
  context.myPresence.patch(patch);
5684
5786
  if (context.activeBatch) {
5685
- if (_optionalChain([options2, 'optionalAccess', _133 => _133.addToHistory])) {
5787
+ if (_optionalChain([options2, 'optionalAccess', _139 => _139.addToHistory])) {
5686
5788
  context.activeBatch.reverseOps.unshift({
5687
5789
  type: "presence",
5688
5790
  data: oldValues
@@ -5692,7 +5794,7 @@ function createRoom(options, config) {
5692
5794
  } else {
5693
5795
  flushNowOrSoon();
5694
5796
  batchUpdates(() => {
5695
- if (_optionalChain([options2, 'optionalAccess', _134 => _134.addToHistory])) {
5797
+ if (_optionalChain([options2, 'optionalAccess', _140 => _140.addToHistory])) {
5696
5798
  addToUndoStack(
5697
5799
  [{ type: "presence", data: oldValues }],
5698
5800
  doNotBatchUpdates
@@ -5890,7 +5992,7 @@ function createRoom(options, config) {
5890
5992
  if (process.env.NODE_ENV !== "production") {
5891
5993
  const traces = /* @__PURE__ */ new Set();
5892
5994
  for (const opId of message.opIds) {
5893
- const trace = _optionalChain([context, 'access', _135 => _135.opStackTraces, 'optionalAccess', _136 => _136.get, 'call', _137 => _137(opId)]);
5995
+ const trace = _optionalChain([context, 'access', _141 => _141.opStackTraces, 'optionalAccess', _142 => _142.get, 'call', _143 => _143(opId)]);
5894
5996
  if (trace) {
5895
5997
  traces.add(trace);
5896
5998
  }
@@ -6019,7 +6121,7 @@ ${Array.from(traces).join("\n\n")}`
6019
6121
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
6020
6122
  createOrUpdateRootFromMessage(message, doNotBatchUpdates);
6021
6123
  applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
6022
- _optionalChain([_resolveStoragePromise, 'optionalCall', _138 => _138()]);
6124
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _144 => _144()]);
6023
6125
  notifyStorageStatus();
6024
6126
  eventHub.storageDidLoad.notify();
6025
6127
  }
@@ -6218,7 +6320,7 @@ ${Array.from(traces).join("\n\n")}`
6218
6320
  delegates.authenticate,
6219
6321
  fetchClientApi
6220
6322
  );
6221
- async function fetchJson(endpoint, options2) {
6323
+ async function fetchNotificationsJson(endpoint, options2) {
6222
6324
  const authValue = await delegates.authenticate();
6223
6325
  const response = await fetchClientApi(
6224
6326
  config.roomId,
@@ -6228,44 +6330,73 @@ ${Array.from(traces).join("\n\n")}`
6228
6330
  );
6229
6331
  if (!response.ok) {
6230
6332
  if (response.status >= 400 && response.status < 600) {
6231
- let errorMessage = "";
6333
+ let error3;
6232
6334
  try {
6233
6335
  const errorBody = await response.json();
6234
- errorMessage = errorBody.message;
6235
- } catch (error3) {
6236
- errorMessage = response.statusText;
6336
+ error3 = new NotificationsApiError(
6337
+ errorBody.message,
6338
+ response.status,
6339
+ errorBody
6340
+ );
6341
+ } catch (e7) {
6342
+ error3 = new NotificationsApiError(
6343
+ response.statusText,
6344
+ response.status
6345
+ );
6237
6346
  }
6238
- throw new Error(
6239
- `Request failed with status ${response.status}: ${errorMessage}`
6240
- );
6347
+ throw error3;
6241
6348
  }
6242
6349
  }
6243
6350
  let body;
6244
6351
  try {
6245
6352
  body = await response.json();
6246
- } catch (e7) {
6353
+ } catch (e8) {
6247
6354
  body = {};
6248
6355
  }
6249
6356
  return body;
6250
6357
  }
6251
6358
  function getRoomNotificationSettings() {
6252
- return fetchJson("/notification-settings");
6359
+ return fetchNotificationsJson(
6360
+ "/notification-settings"
6361
+ );
6253
6362
  }
6254
6363
  function updateRoomNotificationSettings(settings) {
6255
- return fetchJson("/notification-settings", {
6364
+ return fetchNotificationsJson(
6365
+ "/notification-settings",
6366
+ {
6367
+ method: "POST",
6368
+ body: JSON.stringify(settings),
6369
+ headers: {
6370
+ "Content-Type": "application/json"
6371
+ }
6372
+ }
6373
+ );
6374
+ }
6375
+ async function markInboxNotificationsAsRead(inboxNotificationIds) {
6376
+ await fetchNotificationsJson("/inbox-notifications/read", {
6256
6377
  method: "POST",
6257
- body: JSON.stringify(settings),
6258
6378
  headers: {
6259
6379
  "Content-Type": "application/json"
6260
- }
6380
+ },
6381
+ body: JSON.stringify({ inboxNotificationIds })
6261
6382
  });
6262
6383
  }
6384
+ const batchedMarkInboxNotificationsAsRead = new Batch(
6385
+ async (batchedInboxNotificationIds) => {
6386
+ const inboxNotificationIds = batchedInboxNotificationIds.flat();
6387
+ await markInboxNotificationsAsRead(inboxNotificationIds);
6388
+ return inboxNotificationIds;
6389
+ },
6390
+ { delay: MARK_INBOX_NOTIFICATIONS_AS_READ_BATCH_DELAY2 }
6391
+ );
6392
+ async function markInboxNotificationAsRead(inboxNotificationId) {
6393
+ await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
6394
+ }
6263
6395
  return Object.defineProperty(
6264
6396
  {
6265
- /* NOTE: Exposing internals here only to allow testing implementation details in unit tests */
6266
6397
  [kInternal]: {
6267
6398
  get presenceBuffer() {
6268
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _139 => _139.buffer, 'access', _140 => _140.presenceUpdates, 'optionalAccess', _141 => _141.data]), () => ( null)));
6399
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _145 => _145.buffer, 'access', _146 => _146.presenceUpdates, 'optionalAccess', _147 => _147.data]), () => ( null)));
6269
6400
  },
6270
6401
  // prettier-ignore
6271
6402
  get undoStack() {
@@ -6284,6 +6415,14 @@ ${Array.from(traces).join("\n\n")}`
6284
6415
  // These exist only for our E2E testing app
6285
6416
  explicitClose: (event) => managedSocket._privateSendMachineEvent({ type: "EXPLICIT_SOCKET_CLOSE", event }),
6286
6417
  rawSend: (data) => managedSocket.send(data)
6418
+ },
6419
+ comments: {
6420
+ ...commentsApi
6421
+ },
6422
+ notifications: {
6423
+ getRoomNotificationSettings,
6424
+ updateRoomNotificationSettings,
6425
+ markInboxNotificationAsRead
6287
6426
  }
6288
6427
  },
6289
6428
  id: config.roomId,
@@ -6321,12 +6460,7 @@ ${Array.from(traces).join("\n\n")}`
6321
6460
  getSelf: () => self.current,
6322
6461
  // Presence
6323
6462
  getPresence: () => context.myPresence.current,
6324
- getOthers: () => context.others.current,
6325
- // Comments
6326
- ...commentsApi,
6327
- // Notifications
6328
- getRoomNotificationSettings,
6329
- updateRoomNotificationSettings
6463
+ getOthers: () => context.others.current
6330
6464
  },
6331
6465
  // Explictly make the internal field non-enumerable, to avoid aggressive
6332
6466
  // freezing when used with Immer
@@ -6411,7 +6545,7 @@ function makeClassicSubscribeFn(events) {
6411
6545
  }
6412
6546
  if (isLiveNode(first)) {
6413
6547
  const node = first;
6414
- if (_optionalChain([options, 'optionalAccess', _142 => _142.isDeep])) {
6548
+ if (_optionalChain([options, 'optionalAccess', _148 => _148.isDeep])) {
6415
6549
  const storageCallback = second;
6416
6550
  return subscribeToLiveStructureDeeply(node, storageCallback);
6417
6551
  } else {
@@ -6466,28 +6600,6 @@ function createClientStore() {
6466
6600
  inboxNotifications: {},
6467
6601
  notificationSettings: {}
6468
6602
  });
6469
- function mergeThreads(existingThreads, newThreads) {
6470
- const updatedThreads = { ...existingThreads };
6471
- Object.entries(newThreads).forEach(([id, thread]) => {
6472
- const existingThread = updatedThreads[id];
6473
- if (existingThread) {
6474
- const result = compareThreads(existingThread, thread);
6475
- if (result === 1)
6476
- return;
6477
- }
6478
- updatedThreads[id] = thread;
6479
- });
6480
- return updatedThreads;
6481
- }
6482
- function mergeNotifications(existingInboxNotifications, newInboxNotifications) {
6483
- const inboxNotifications = Object.values({
6484
- ...existingInboxNotifications,
6485
- ...newInboxNotifications
6486
- });
6487
- return Object.fromEntries(
6488
- inboxNotifications.map((notification) => [notification.id, notification])
6489
- );
6490
- }
6491
6603
  return {
6492
6604
  ...store,
6493
6605
  deleteThread(threadId) {
@@ -6516,21 +6628,19 @@ function createClientStore() {
6516
6628
  };
6517
6629
  });
6518
6630
  },
6519
- updateThreadsAndNotifications(threads, inboxNotifications, queryKey) {
6631
+ updateThreadsAndNotifications(threads, inboxNotifications, deletedThreads, deletedInboxNotifications, queryKey) {
6520
6632
  store.set((state) => ({
6521
6633
  ...state,
6522
- threads: mergeThreads(
6523
- state.threads,
6524
- Object.fromEntries(threads.map((thread) => [thread.id, thread]))
6525
- ),
6526
- inboxNotifications: mergeNotifications(
6634
+ threads: applyThreadUpdates(state.threads, {
6635
+ newThreads: threads,
6636
+ deletedThreads
6637
+ }),
6638
+ inboxNotifications: applyNotificationsUpdates(
6527
6639
  state.inboxNotifications,
6528
- Object.fromEntries(
6529
- inboxNotifications.map((notification) => [
6530
- notification.id,
6531
- notification
6532
- ])
6533
- )
6640
+ {
6641
+ newInboxNotifications: inboxNotifications,
6642
+ deletedNotifications: deletedInboxNotifications
6643
+ }
6534
6644
  ),
6535
6645
  queries: queryKey !== void 0 ? {
6536
6646
  ...state.queries,
@@ -6540,6 +6650,21 @@ function createClientStore() {
6540
6650
  } : state.queries
6541
6651
  }));
6542
6652
  },
6653
+ updateRoomInboxNotificationSettings(roomId, settings, queryKey) {
6654
+ store.set((state) => ({
6655
+ ...state,
6656
+ notificationSettings: {
6657
+ ...state.notificationSettings,
6658
+ [roomId]: settings
6659
+ },
6660
+ queries: {
6661
+ ...state.queries,
6662
+ [queryKey]: {
6663
+ isLoading: false
6664
+ }
6665
+ }
6666
+ }));
6667
+ },
6543
6668
  pushOptimisticUpdate(optimisticUpdate) {
6544
6669
  store.set((state) => ({
6545
6670
  ...state,
@@ -6600,8 +6725,15 @@ function applyOptimisticUpdates(state) {
6600
6725
  if (thread === void 0) {
6601
6726
  break;
6602
6727
  }
6728
+ if (thread.deletedAt !== void 0) {
6729
+ break;
6730
+ }
6731
+ if (thread.updatedAt !== void 0 && thread.updatedAt > optimisticUpdate.updatedAt) {
6732
+ break;
6733
+ }
6603
6734
  result.threads[thread.id] = {
6604
6735
  ...thread,
6736
+ updatedAt: optimisticUpdate.updatedAt,
6605
6737
  metadata: {
6606
6738
  ...thread.metadata,
6607
6739
  ...optimisticUpdate.metadata
@@ -6614,16 +6746,17 @@ function applyOptimisticUpdates(state) {
6614
6746
  if (thread === void 0) {
6615
6747
  break;
6616
6748
  }
6617
- result.threads[thread.id] = {
6618
- ...thread,
6619
- comments: [...thread.comments, optimisticUpdate.comment]
6620
- // TODO: Handle replace comment
6621
- };
6622
- if (!optimisticUpdate.inboxNotificationId) {
6749
+ result.threads[thread.id] = upsertComment(
6750
+ thread,
6751
+ optimisticUpdate.comment
6752
+ );
6753
+ const inboxNotification = Object.values(result.inboxNotifications).find(
6754
+ (notification) => notification.threadId === thread.id
6755
+ );
6756
+ if (inboxNotification === void 0) {
6623
6757
  break;
6624
6758
  }
6625
- const inboxNotification = result.inboxNotifications[optimisticUpdate.inboxNotificationId];
6626
- result.inboxNotifications[optimisticUpdate.inboxNotificationId] = {
6759
+ result.inboxNotifications[inboxNotification.id] = {
6627
6760
  ...inboxNotification,
6628
6761
  notifiedAt: optimisticUpdate.comment.createdAt,
6629
6762
  readAt: optimisticUpdate.comment.createdAt
@@ -6631,20 +6764,14 @@ function applyOptimisticUpdates(state) {
6631
6764
  break;
6632
6765
  }
6633
6766
  case "edit-comment": {
6634
- const thread = result.threads[optimisticUpdate.threadId];
6767
+ const thread = result.threads[optimisticUpdate.comment.threadId];
6635
6768
  if (thread === void 0) {
6636
6769
  break;
6637
6770
  }
6638
- result.threads[thread.id] = {
6639
- ...thread,
6640
- comments: thread.comments.map(
6641
- (comment) => comment.id === optimisticUpdate.commentId ? {
6642
- ...comment,
6643
- editedAt: optimisticUpdate.editedAt,
6644
- body: optimisticUpdate.body
6645
- } : comment
6646
- )
6647
- };
6771
+ result.threads[thread.id] = upsertComment(
6772
+ thread,
6773
+ optimisticUpdate.comment
6774
+ );
6648
6775
  break;
6649
6776
  }
6650
6777
  case "delete-comment": {
@@ -6652,21 +6779,11 @@ function applyOptimisticUpdates(state) {
6652
6779
  if (thread === void 0) {
6653
6780
  break;
6654
6781
  }
6655
- result.threads[thread.id] = {
6656
- ...thread,
6657
- comments: thread.comments.map(
6658
- (comment) => comment.id === optimisticUpdate.commentId ? {
6659
- ...comment,
6660
- deletedAt: optimisticUpdate.deletedAt,
6661
- body: void 0
6662
- } : comment
6663
- )
6664
- };
6665
- if (!result.threads[thread.id].comments.some(
6666
- (comment) => comment.deletedAt === void 0
6667
- )) {
6668
- delete result.threads[thread.id];
6669
- }
6782
+ result.threads[thread.id] = deleteComment(
6783
+ thread,
6784
+ optimisticUpdate.commentId,
6785
+ optimisticUpdate.deletedAt
6786
+ );
6670
6787
  break;
6671
6788
  }
6672
6789
  case "add-reaction": {
@@ -6674,43 +6791,11 @@ function applyOptimisticUpdates(state) {
6674
6791
  if (thread === void 0) {
6675
6792
  break;
6676
6793
  }
6677
- result.threads[thread.id] = {
6678
- ...thread,
6679
- comments: thread.comments.map((comment) => {
6680
- if (comment.id === optimisticUpdate.commentId) {
6681
- if (comment.reactions.some(
6682
- (reaction) => reaction.emoji === optimisticUpdate.emoji
6683
- )) {
6684
- return {
6685
- ...comment,
6686
- reactions: comment.reactions.map(
6687
- (reaction) => reaction.emoji === optimisticUpdate.emoji ? {
6688
- ...reaction,
6689
- users: [
6690
- ...reaction.users,
6691
- { id: optimisticUpdate.userId }
6692
- ]
6693
- } : reaction
6694
- )
6695
- };
6696
- } else {
6697
- return {
6698
- ...comment,
6699
- reactions: [
6700
- ...comment.reactions,
6701
- {
6702
- emoji: optimisticUpdate.emoji,
6703
- createdAt: optimisticUpdate.createdAt,
6704
- users: [{ id: optimisticUpdate.userId }]
6705
- }
6706
- ]
6707
- };
6708
- }
6709
- } else {
6710
- return comment;
6711
- }
6712
- })
6713
- };
6794
+ result.threads[thread.id] = addReaction(
6795
+ thread,
6796
+ optimisticUpdate.commentId,
6797
+ optimisticUpdate.reaction
6798
+ );
6714
6799
  break;
6715
6800
  }
6716
6801
  case "remove-reaction": {
@@ -6718,37 +6803,13 @@ function applyOptimisticUpdates(state) {
6718
6803
  if (thread === void 0) {
6719
6804
  break;
6720
6805
  }
6721
- result.threads[thread.id] = {
6722
- ...thread,
6723
- comments: thread.comments.map((comment) => {
6724
- if (comment.id !== optimisticUpdate.commentId) {
6725
- return comment;
6726
- }
6727
- const reactionIndex = comment.reactions.findIndex(
6728
- (reaction) => reaction.emoji === optimisticUpdate.emoji
6729
- );
6730
- let reactions = comment.reactions;
6731
- if (reactionIndex >= 0 && comment.reactions[reactionIndex].users.some(
6732
- (user) => user.id === optimisticUpdate.userId
6733
- )) {
6734
- if (comment.reactions[reactionIndex].users.length <= 1) {
6735
- reactions = [...comment.reactions];
6736
- reactions.splice(reactionIndex, 1);
6737
- } else {
6738
- reactions[reactionIndex] = {
6739
- ...reactions[reactionIndex],
6740
- users: reactions[reactionIndex].users.filter(
6741
- (user) => user.id !== optimisticUpdate.userId
6742
- )
6743
- };
6744
- }
6745
- }
6746
- return {
6747
- ...comment,
6748
- reactions
6749
- };
6750
- })
6751
- };
6806
+ result.threads[thread.id] = removeReaction(
6807
+ thread,
6808
+ optimisticUpdate.commentId,
6809
+ optimisticUpdate.emoji,
6810
+ optimisticUpdate.userId,
6811
+ optimisticUpdate.removedAt
6812
+ );
6752
6813
  break;
6753
6814
  }
6754
6815
  case "mark-inbox-notification-as-read": {
@@ -6777,6 +6838,222 @@ function applyOptimisticUpdates(state) {
6777
6838
  }
6778
6839
  return result;
6779
6840
  }
6841
+ function applyThreadUpdates(existingThreads, updates) {
6842
+ const updatedThreads = { ...existingThreads };
6843
+ updates.newThreads.forEach((thread) => {
6844
+ const existingThread = updatedThreads[thread.id];
6845
+ if (existingThread) {
6846
+ const result = compareThreads(existingThread, thread);
6847
+ if (result === 1)
6848
+ return;
6849
+ }
6850
+ updatedThreads[thread.id] = thread;
6851
+ });
6852
+ updates.deletedThreads.forEach(({ id, deletedAt }) => {
6853
+ const existingThread = updatedThreads[id];
6854
+ if (existingThread === void 0)
6855
+ return;
6856
+ existingThread.deletedAt = deletedAt;
6857
+ existingThread.updatedAt = deletedAt;
6858
+ existingThread.comments = [];
6859
+ });
6860
+ return updatedThreads;
6861
+ }
6862
+ function applyNotificationsUpdates(existingInboxNotifications, updates) {
6863
+ const updatedInboxNotifications = { ...existingInboxNotifications };
6864
+ updates.newInboxNotifications.forEach((notification) => {
6865
+ const existingNotification = updatedInboxNotifications[notification.id];
6866
+ if (existingNotification) {
6867
+ const result = compareInboxNotifications(
6868
+ existingNotification,
6869
+ notification
6870
+ );
6871
+ if (result === 1)
6872
+ return;
6873
+ }
6874
+ updatedInboxNotifications[notification.id] = notification;
6875
+ });
6876
+ updates.deletedNotifications.forEach(
6877
+ ({ id }) => delete updatedInboxNotifications[id]
6878
+ );
6879
+ return updatedInboxNotifications;
6880
+ }
6881
+ function compareInboxNotifications(inboxNotificationA, inboxNotificationB) {
6882
+ if (inboxNotificationA.notifiedAt > inboxNotificationB.notifiedAt) {
6883
+ return 1;
6884
+ } else if (inboxNotificationA.notifiedAt < inboxNotificationB.notifiedAt) {
6885
+ return -1;
6886
+ }
6887
+ if (inboxNotificationA.readAt && inboxNotificationB.readAt) {
6888
+ return inboxNotificationA.readAt > inboxNotificationB.readAt ? 1 : inboxNotificationA.readAt < inboxNotificationB.readAt ? -1 : 0;
6889
+ } else if (inboxNotificationA.readAt || inboxNotificationB.readAt) {
6890
+ return inboxNotificationA.readAt ? 1 : -1;
6891
+ }
6892
+ return 0;
6893
+ }
6894
+ function upsertComment(thread, comment) {
6895
+ if (thread.deletedAt !== void 0) {
6896
+ return thread;
6897
+ }
6898
+ if (comment.threadId !== thread.id) {
6899
+ warn(
6900
+ `Comment ${comment.id} does not belong to thread ${thread.id}`
6901
+ );
6902
+ return thread;
6903
+ }
6904
+ const existingComment = thread.comments.find(
6905
+ (existingComment2) => existingComment2.id === comment.id
6906
+ );
6907
+ if (existingComment === void 0) {
6908
+ const updatedAt = new Date(
6909
+ Math.max(_optionalChain([thread, 'access', _149 => _149.updatedAt, 'optionalAccess', _150 => _150.getTime, 'call', _151 => _151()]) || 0, comment.createdAt.getTime())
6910
+ );
6911
+ const updatedThread = {
6912
+ ...thread,
6913
+ updatedAt,
6914
+ comments: [...thread.comments, comment]
6915
+ };
6916
+ return updatedThread;
6917
+ }
6918
+ if (existingComment.deletedAt !== void 0) {
6919
+ return thread;
6920
+ }
6921
+ if (existingComment.editedAt === void 0 || comment.editedAt === void 0 || existingComment.editedAt <= comment.editedAt) {
6922
+ const updatedComments = thread.comments.map(
6923
+ (existingComment2) => existingComment2.id === comment.id ? comment : existingComment2
6924
+ );
6925
+ const updatedThread = {
6926
+ ...thread,
6927
+ updatedAt: new Date(
6928
+ Math.max(
6929
+ _optionalChain([thread, 'access', _152 => _152.updatedAt, 'optionalAccess', _153 => _153.getTime, 'call', _154 => _154()]) || 0,
6930
+ _optionalChain([comment, 'access', _155 => _155.editedAt, 'optionalAccess', _156 => _156.getTime, 'call', _157 => _157()]) || comment.createdAt.getTime()
6931
+ )
6932
+ ),
6933
+ comments: updatedComments
6934
+ };
6935
+ return updatedThread;
6936
+ }
6937
+ return thread;
6938
+ }
6939
+ function deleteComment(thread, commentId, deletedAt) {
6940
+ if (thread.deletedAt !== void 0) {
6941
+ return thread;
6942
+ }
6943
+ const existingComment = thread.comments.find(
6944
+ (comment) => comment.id === commentId
6945
+ );
6946
+ if (existingComment === void 0) {
6947
+ return thread;
6948
+ }
6949
+ if (existingComment.deletedAt !== void 0) {
6950
+ return thread;
6951
+ }
6952
+ const updatedComments = thread.comments.map(
6953
+ (comment) => comment.id === commentId ? {
6954
+ ...comment,
6955
+ deletedAt,
6956
+ body: void 0
6957
+ } : comment
6958
+ );
6959
+ if (!updatedComments.some((comment) => comment.deletedAt === void 0)) {
6960
+ return {
6961
+ ...thread,
6962
+ deletedAt,
6963
+ updatedAt: deletedAt,
6964
+ comments: []
6965
+ };
6966
+ }
6967
+ return {
6968
+ ...thread,
6969
+ updatedAt: deletedAt,
6970
+ comments: updatedComments
6971
+ };
6972
+ }
6973
+ function addReaction(thread, commentId, reaction) {
6974
+ if (thread.deletedAt !== void 0) {
6975
+ return thread;
6976
+ }
6977
+ const existingComment = thread.comments.find(
6978
+ (comment) => comment.id === commentId
6979
+ );
6980
+ if (existingComment === void 0) {
6981
+ return thread;
6982
+ }
6983
+ if (existingComment.deletedAt !== void 0) {
6984
+ return thread;
6985
+ }
6986
+ const updatedComments = thread.comments.map(
6987
+ (comment) => comment.id === commentId ? {
6988
+ ...comment,
6989
+ reactions: upsertReaction(comment.reactions, reaction)
6990
+ } : comment
6991
+ );
6992
+ return {
6993
+ ...thread,
6994
+ updatedAt: new Date(
6995
+ Math.max(reaction.createdAt.getTime(), _optionalChain([thread, 'access', _158 => _158.updatedAt, 'optionalAccess', _159 => _159.getTime, 'call', _160 => _160()]) || 0)
6996
+ ),
6997
+ comments: updatedComments
6998
+ };
6999
+ }
7000
+ function removeReaction(thread, commentId, emoji, userId, removedAt) {
7001
+ if (thread.deletedAt !== void 0) {
7002
+ return thread;
7003
+ }
7004
+ const existingComment = thread.comments.find(
7005
+ (comment) => comment.id === commentId
7006
+ );
7007
+ if (existingComment === void 0) {
7008
+ return thread;
7009
+ }
7010
+ if (existingComment.deletedAt !== void 0) {
7011
+ return thread;
7012
+ }
7013
+ const updatedComments = thread.comments.map(
7014
+ (comment) => comment.id === commentId ? {
7015
+ ...comment,
7016
+ reactions: comment.reactions.map(
7017
+ (reaction) => reaction.emoji === emoji ? {
7018
+ ...reaction,
7019
+ users: reaction.users.filter((user) => user.id !== userId)
7020
+ } : reaction
7021
+ ).filter((reaction) => reaction.users.length > 0)
7022
+ // Remove reactions with no users left
7023
+ } : comment
7024
+ );
7025
+ return {
7026
+ ...thread,
7027
+ updatedAt: new Date(
7028
+ Math.max(removedAt.getTime(), _optionalChain([thread, 'access', _161 => _161.updatedAt, 'optionalAccess', _162 => _162.getTime, 'call', _163 => _163()]) || 0)
7029
+ ),
7030
+ comments: updatedComments
7031
+ };
7032
+ }
7033
+ function upsertReaction(reactions, reaction) {
7034
+ const existingReaction = reactions.find(
7035
+ (existingReaction2) => existingReaction2.emoji === reaction.emoji
7036
+ );
7037
+ if (existingReaction === void 0) {
7038
+ return [
7039
+ ...reactions,
7040
+ {
7041
+ emoji: reaction.emoji,
7042
+ createdAt: reaction.createdAt,
7043
+ users: [{ id: reaction.userId }]
7044
+ }
7045
+ ];
7046
+ }
7047
+ if (existingReaction.users.some((user) => user.id === reaction.userId) === false) {
7048
+ return reactions.map(
7049
+ (existingReaction2) => existingReaction2.emoji === reaction.emoji ? {
7050
+ ...existingReaction2,
7051
+ users: [...existingReaction2.users, { id: reaction.userId }]
7052
+ } : existingReaction2
7053
+ );
7054
+ }
7055
+ return reactions;
7056
+ }
6780
7057
 
6781
7058
  // src/client.ts
6782
7059
  var MIN_THROTTLE = 16;
@@ -6866,12 +7143,12 @@ function createClient(options) {
6866
7143
  createSocket: makeCreateSocketDelegateForRoom(
6867
7144
  roomId,
6868
7145
  baseUrl,
6869
- _optionalChain([clientOptions, 'access', _143 => _143.polyfills, 'optionalAccess', _144 => _144.WebSocket])
7146
+ _optionalChain([clientOptions, 'access', _164 => _164.polyfills, 'optionalAccess', _165 => _165.WebSocket])
6870
7147
  ),
6871
7148
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
6872
7149
  })),
6873
7150
  enableDebugLogging: clientOptions.enableDebugLogging,
6874
- unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _145 => _145.unstable_batchedUpdates]),
7151
+ unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _166 => _166.unstable_batchedUpdates]),
6875
7152
  baseUrl,
6876
7153
  unstable_fallbackToHTTP: !!clientOptions.unstable_fallbackToHTTP,
6877
7154
  unstable_streamData: !!clientOptions.unstable_streamData
@@ -6887,7 +7164,7 @@ function createClient(options) {
6887
7164
  const shouldConnect = _nullishCoalesce(_nullishCoalesce(options2.autoConnect, () => ( options2.shouldInitiallyConnect)), () => ( true));
6888
7165
  if (shouldConnect) {
6889
7166
  if (typeof atob === "undefined") {
6890
- if (_optionalChain([clientOptions, 'access', _146 => _146.polyfills, 'optionalAccess', _147 => _147.atob]) === void 0) {
7167
+ if (_optionalChain([clientOptions, 'access', _167 => _167.polyfills, 'optionalAccess', _168 => _168.atob]) === void 0) {
6891
7168
  throw new Error(
6892
7169
  "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"
6893
7170
  );
@@ -6903,11 +7180,11 @@ function createClient(options) {
6903
7180
  return room;
6904
7181
  }
6905
7182
  function getRoom(roomId) {
6906
- const room = _optionalChain([roomsById, 'access', _148 => _148.get, 'call', _149 => _149(roomId), 'optionalAccess', _150 => _150.room]);
7183
+ const room = _optionalChain([roomsById, 'access', _169 => _169.get, 'call', _170 => _170(roomId), 'optionalAccess', _171 => _171.room]);
6907
7184
  return room ? room : null;
6908
7185
  }
6909
7186
  function forceLeave(roomId) {
6910
- const unsubs = _nullishCoalesce(_optionalChain([roomsById, 'access', _151 => _151.get, 'call', _152 => _152(roomId), 'optionalAccess', _153 => _153.unsubs]), () => ( /* @__PURE__ */ new Set()));
7187
+ const unsubs = _nullishCoalesce(_optionalChain([roomsById, 'access', _172 => _172.get, 'call', _173 => _173(roomId), 'optionalAccess', _174 => _174.unsubs]), () => ( /* @__PURE__ */ new Set()));
6911
7188
  for (const unsub of unsubs) {
6912
7189
  unsub();
6913
7190
  }
@@ -6926,9 +7203,9 @@ function createClient(options) {
6926
7203
  getUnreadInboxNotificationsCount,
6927
7204
  markAllInboxNotificationsAsRead,
6928
7205
  markInboxNotificationAsRead
6929
- } = createInboxNotificationsApi({
7206
+ } = createNotificationsApi({
6930
7207
  baseUrl,
6931
- fetcher: _optionalChain([clientOptions, 'access', _154 => _154.polyfills, 'optionalAccess', _155 => _155.fetch]) || /* istanbul ignore next */
7208
+ fetcher: _optionalChain([clientOptions, 'access', _175 => _175.polyfills, 'optionalAccess', _176 => _176.fetch]) || /* istanbul ignore next */
6932
7209
  fetch,
6933
7210
  authManager,
6934
7211
  currentUserIdStore
@@ -6942,7 +7219,7 @@ function createClient(options) {
6942
7219
  const usersStore = createBatchStore(
6943
7220
  async (batchedUserIds) => {
6944
7221
  const userIds = batchedUserIds.flat();
6945
- const users = await _optionalChain([resolveUsers, 'optionalCall', _156 => _156({ userIds })]);
7222
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _177 => _177({ userIds })]);
6946
7223
  warnIfNoResolveUsers();
6947
7224
  return _nullishCoalesce(users, () => ( userIds.map(() => void 0)));
6948
7225
  },
@@ -6956,7 +7233,7 @@ function createClient(options) {
6956
7233
  const roomsInfoStore = createBatchStore(
6957
7234
  async (batchedRoomIds) => {
6958
7235
  const roomIds = batchedRoomIds.flat();
6959
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _157 => _157({ roomIds })]);
7236
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _178 => _178({ roomIds })]);
6960
7237
  warnIfNoResolveRoomsInfo();
6961
7238
  return _nullishCoalesce(roomsInfo, () => ( roomIds.map(() => void 0)));
6962
7239
  },
@@ -6971,18 +7248,22 @@ function createClient(options) {
6971
7248
  leave: forceLeave,
6972
7249
  // New, preferred API
6973
7250
  enterRoom,
6974
- // Notifications API
6975
- getInboxNotifications,
6976
- getUnreadInboxNotificationsCount,
6977
- markAllInboxNotificationsAsRead,
6978
- markInboxNotificationAsRead,
6979
7251
  // Internal
6980
7252
  [kInternal]: {
7253
+ notifications: {
7254
+ getInboxNotifications,
7255
+ getUnreadInboxNotificationsCount,
7256
+ markAllInboxNotificationsAsRead,
7257
+ markInboxNotificationAsRead
7258
+ },
6981
7259
  currentUserIdStore,
6982
7260
  resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
6983
7261
  cacheStore,
6984
7262
  usersStore,
6985
- roomsInfoStore
7263
+ roomsInfoStore,
7264
+ getRoomIds() {
7265
+ return Array.from(roomsById.keys());
7266
+ }
6986
7267
  }
6987
7268
  },
6988
7269
  kInternal,
@@ -7069,7 +7350,7 @@ var commentBodyElementsTypes = {
7069
7350
  mention: "inline"
7070
7351
  };
7071
7352
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
7072
- if (!body || !_optionalChain([body, 'optionalAccess', _158 => _158.content])) {
7353
+ if (!body || !_optionalChain([body, 'optionalAccess', _179 => _179.content])) {
7073
7354
  return;
7074
7355
  }
7075
7356
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -7079,13 +7360,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
7079
7360
  for (const block of body.content) {
7080
7361
  if (type === "all" || type === "block") {
7081
7362
  if (guard(block)) {
7082
- _optionalChain([visitor, 'optionalCall', _159 => _159(block)]);
7363
+ _optionalChain([visitor, 'optionalCall', _180 => _180(block)]);
7083
7364
  }
7084
7365
  }
7085
7366
  if (type === "all" || type === "inline") {
7086
7367
  for (const inline of block.children) {
7087
7368
  if (guard(inline)) {
7088
- _optionalChain([visitor, 'optionalCall', _160 => _160(inline)]);
7369
+ _optionalChain([visitor, 'optionalCall', _181 => _181(inline)]);
7089
7370
  }
7090
7371
  }
7091
7372
  }
@@ -7110,7 +7391,7 @@ async function resolveUsersInCommentBody(body, resolveUsers) {
7110
7391
  userIds
7111
7392
  });
7112
7393
  for (const [index, userId] of userIds.entries()) {
7113
- const user = _optionalChain([users, 'optionalAccess', _161 => _161[index]]);
7394
+ const user = _optionalChain([users, 'optionalAccess', _182 => _182[index]]);
7114
7395
  if (user) {
7115
7396
  resolvedUsers.set(userId, user);
7116
7397
  }
@@ -7233,7 +7514,7 @@ var stringifyCommentBodyPlainElements = {
7233
7514
  text: ({ element }) => element.text,
7234
7515
  link: ({ element }) => element.url,
7235
7516
  mention: ({ element, user }) => {
7236
- return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _162 => _162.name]), () => ( element.id))}`;
7517
+ return `@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _183 => _183.name]), () => ( element.id))}`;
7237
7518
  }
7238
7519
  };
7239
7520
  var stringifyCommentBodyHtmlElements = {
@@ -7263,7 +7544,7 @@ var stringifyCommentBodyHtmlElements = {
7263
7544
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.url}</a>`;
7264
7545
  },
7265
7546
  mention: ({ element, user }) => {
7266
- return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _163 => _163.name]), () => ( element.id))}</span>`;
7547
+ return html`<span data-mention>@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _184 => _184.name]), () => ( element.id))}</span>`;
7267
7548
  }
7268
7549
  };
7269
7550
  var stringifyCommentBodyMarkdownElements = {
@@ -7293,19 +7574,19 @@ var stringifyCommentBodyMarkdownElements = {
7293
7574
  return markdown`[${element.url}](${href})`;
7294
7575
  },
7295
7576
  mention: ({ element, user }) => {
7296
- return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _164 => _164.name]), () => ( element.id))}`;
7577
+ return markdown`@${_nullishCoalesce(_optionalChain([user, 'optionalAccess', _185 => _185.name]), () => ( element.id))}`;
7297
7578
  }
7298
7579
  };
7299
7580
  async function stringifyCommentBody(body, options) {
7300
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _165 => _165.format]), () => ( "plain"));
7301
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _166 => _166.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
7581
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _186 => _186.format]), () => ( "plain"));
7582
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _187 => _187.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
7302
7583
  const elements = {
7303
7584
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
7304
- ..._optionalChain([options, 'optionalAccess', _167 => _167.elements])
7585
+ ..._optionalChain([options, 'optionalAccess', _188 => _188.elements])
7305
7586
  };
7306
7587
  const resolvedUsers = await resolveUsersInCommentBody(
7307
7588
  body,
7308
- _optionalChain([options, 'optionalAccess', _168 => _168.resolveUsers])
7589
+ _optionalChain([options, 'optionalAccess', _189 => _189.resolveUsers])
7309
7590
  );
7310
7591
  const blocks = body.content.flatMap((block, blockIndex) => {
7311
7592
  switch (block.type) {
@@ -7580,12 +7861,12 @@ function legacy_patchImmutableNode(state, path, update) {
7580
7861
  }
7581
7862
  const newState = Object.assign({}, state);
7582
7863
  for (const key in update.updates) {
7583
- if (_optionalChain([update, 'access', _169 => _169.updates, 'access', _170 => _170[key], 'optionalAccess', _171 => _171.type]) === "update") {
7864
+ if (_optionalChain([update, 'access', _190 => _190.updates, 'access', _191 => _191[key], 'optionalAccess', _192 => _192.type]) === "update") {
7584
7865
  const val = update.node.get(key);
7585
7866
  if (val !== void 0) {
7586
7867
  newState[key] = lsonToJson(val);
7587
7868
  }
7588
- } else if (_optionalChain([update, 'access', _172 => _172.updates, 'access', _173 => _173[key], 'optionalAccess', _174 => _174.type]) === "delete") {
7869
+ } else if (_optionalChain([update, 'access', _193 => _193.updates, 'access', _194 => _194[key], 'optionalAccess', _195 => _195.type]) === "delete") {
7589
7870
  delete newState[key];
7590
7871
  }
7591
7872
  }
@@ -7646,12 +7927,12 @@ function legacy_patchImmutableNode(state, path, update) {
7646
7927
  }
7647
7928
  const newState = Object.assign({}, state);
7648
7929
  for (const key in update.updates) {
7649
- if (_optionalChain([update, 'access', _175 => _175.updates, 'access', _176 => _176[key], 'optionalAccess', _177 => _177.type]) === "update") {
7930
+ if (_optionalChain([update, 'access', _196 => _196.updates, 'access', _197 => _197[key], 'optionalAccess', _198 => _198.type]) === "update") {
7650
7931
  const value = update.node.get(key);
7651
7932
  if (value !== void 0) {
7652
7933
  newState[key] = lsonToJson(value);
7653
7934
  }
7654
- } else if (_optionalChain([update, 'access', _178 => _178.updates, 'access', _179 => _179[key], 'optionalAccess', _180 => _180.type]) === "delete") {
7935
+ } else if (_optionalChain([update, 'access', _199 => _199.updates, 'access', _200 => _200[key], 'optionalAccess', _201 => _201.type]) === "delete") {
7655
7936
  delete newState[key];
7656
7937
  }
7657
7938
  }
@@ -7865,5 +8146,9 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
7865
8146
 
7866
8147
 
7867
8148
 
7868
- exports.ClientMsgCode = ClientMsgCode; exports.CommentsApiError = CommentsApiError; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.NotificationsApiError = NotificationsApiError; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.ackOp = ackOp; exports.applyOptimisticUpdates = applyOptimisticUpdates; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.cloneLson = cloneLson; exports.console = fancy_console_exports; exports.convertToCommentData = convertToCommentData; exports.convertToCommentUserReaction = convertToCommentUserReaction; exports.convertToThreadData = convertToThreadData; exports.createClient = createClient; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.getMentionedIdsFromCommentBody = getMentionedIdsFromCommentBody; exports.isChildCrdt = isChildCrdt; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isLiveNode = isLiveNode; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.kInternal = kInternal; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.nn = nn; exports.patchLiveObjectKey = patchLiveObjectKey; exports.raise = raise; exports.shallow = shallow; exports.stringify = stringify; exports.stringifyCommentBody = stringifyCommentBody; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.withTimeout = withTimeout;
8149
+
8150
+
8151
+
8152
+
8153
+ 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.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.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;
7869
8154
  //# sourceMappingURL=index.js.map