@liveblocks/core 3.6.1-preview1 → 3.7.0-preview1

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 = "3.6.1-preview1";
9
+ var PKG_VERSION = "3.7.0-preview1";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -851,6 +851,38 @@ function convertToSubscriptionDeleteInfo(data) {
851
851
  deletedAt
852
852
  };
853
853
  }
854
+ function convertToGroupData(data) {
855
+ const createdAt = new Date(data.createdAt);
856
+ const updatedAt = new Date(data.updatedAt);
857
+ const members = data.members.map((member) => ({
858
+ ...member,
859
+ addedAt: new Date(member.addedAt)
860
+ }));
861
+ return {
862
+ ...data,
863
+ createdAt,
864
+ updatedAt,
865
+ members
866
+ };
867
+ }
868
+
869
+ // src/lib/assert.ts
870
+ function assertNever(_value, errmsg) {
871
+ throw new Error(errmsg);
872
+ }
873
+ function assert(condition, errmsg) {
874
+ if (process.env.NODE_ENV !== "production") {
875
+ if (!condition) {
876
+ const err = new Error(errmsg);
877
+ err.name = "Assertion failure";
878
+ throw err;
879
+ }
880
+ }
881
+ }
882
+ function nn(value, errmsg = "Expected value to be non-nullable") {
883
+ assert(value !== null && value !== void 0, errmsg);
884
+ return value;
885
+ }
854
886
 
855
887
  // src/lib/fancy-console.ts
856
888
  var fancy_console_exports = {};
@@ -1128,11 +1160,20 @@ function createBatchStore(batch2) {
1128
1160
  });
1129
1161
  }
1130
1162
  }
1163
+ function fill(input, data) {
1164
+ const cacheKey = getCacheKey(input);
1165
+ update(cacheKey, { isLoading: false, data });
1166
+ }
1131
1167
  function getItemState(input) {
1132
1168
  const cacheKey = getCacheKey(input);
1133
1169
  const cache = signal.get();
1134
1170
  return cache.get(cacheKey);
1135
1171
  }
1172
+ function getData(input) {
1173
+ const cacheKey = getCacheKey(input);
1174
+ const cache = signal.get();
1175
+ return cache.get(cacheKey)?.data;
1176
+ }
1136
1177
  function _cacheKeys() {
1137
1178
  const cache = signal.get();
1138
1179
  return [...cache.keys()];
@@ -1140,7 +1181,9 @@ function createBatchStore(batch2) {
1140
1181
  return {
1141
1182
  subscribe: signal.subscribe,
1142
1183
  enqueue,
1184
+ fill,
1143
1185
  getItemState,
1186
+ getData,
1144
1187
  invalidate,
1145
1188
  batch: batch2,
1146
1189
  _cacheKeys
@@ -1962,6 +2005,9 @@ function createApiClient({
1962
2005
  return batch2.get(options.inboxNotificationId);
1963
2006
  }
1964
2007
  async function createTextMention(options) {
2008
+ if (options.mention.kind !== "user" && options.mention.kind !== "group") {
2009
+ return assertNever(options.mention, "Unexpected mention kind");
2010
+ }
1965
2011
  await httpClient.rawPost(
1966
2012
  url`/v2/c/rooms/${options.roomId}/text-mentions`,
1967
2013
  await authManager.getAuthValue({
@@ -1969,7 +2015,9 @@ function createApiClient({
1969
2015
  roomId: options.roomId
1970
2016
  }),
1971
2017
  {
1972
- userId: options.userId,
2018
+ userId: options.mention.kind === "user" ? options.mention.id : void 0,
2019
+ groupId: options.mention.kind === "group" ? options.mention.id : void 0,
2020
+ userIds: options.mention.kind === "group" ? options.mention.userIds : void 0,
1973
2021
  mentionId: options.mentionId
1974
2022
  }
1975
2023
  );
@@ -2108,6 +2156,10 @@ function createApiClient({
2108
2156
  limit: PAGE_SIZE
2109
2157
  }
2110
2158
  );
2159
+ const groups = json.groups.map(convertToGroupData);
2160
+ for (const group of groups) {
2161
+ groupsStore.fill(group.id, group);
2162
+ }
2111
2163
  return {
2112
2164
  inboxNotifications: json.inboxNotifications.map(
2113
2165
  convertToInboxNotificationData
@@ -2258,6 +2310,28 @@ function createApiClient({
2258
2310
  permissionHints: json.meta.permissionHints
2259
2311
  };
2260
2312
  }
2313
+ const batchedGetGroups = new Batch(
2314
+ async (batchedGroupIds) => {
2315
+ const groupIds = batchedGroupIds.flat();
2316
+ const { groups: plainGroups } = await httpClient.post(
2317
+ url`/v2/c/groups/find`,
2318
+ await authManager.getAuthValue({
2319
+ requestedScope: "comments:read"
2320
+ }),
2321
+ { groupIds }
2322
+ );
2323
+ const groups = /* @__PURE__ */ new Map();
2324
+ for (const group of plainGroups) {
2325
+ groups.set(group.id, convertToGroupData(group));
2326
+ }
2327
+ return groupIds.map((groupId) => groups.get(groupId));
2328
+ },
2329
+ { delay: 50 }
2330
+ );
2331
+ const groupsStore = createBatchStore(batchedGetGroups);
2332
+ function getGroup(groupId) {
2333
+ return batchedGetGroups.get(groupId);
2334
+ }
2261
2335
  return {
2262
2336
  // Room threads
2263
2337
  getThreads,
@@ -2311,6 +2385,9 @@ function createApiClient({
2311
2385
  // User threads
2312
2386
  getUserThreads_experimental,
2313
2387
  getUserThreadsSince_experimental,
2388
+ // Groups
2389
+ groupsStore,
2390
+ getGroup,
2314
2391
  // AI
2315
2392
  executeContextualPrompt
2316
2393
  };
@@ -2468,24 +2545,6 @@ var HttpClient = class {
2468
2545
  }
2469
2546
  };
2470
2547
 
2471
- // src/lib/assert.ts
2472
- function assertNever(_value, errmsg) {
2473
- throw new Error(errmsg);
2474
- }
2475
- function assert(condition, errmsg) {
2476
- if (process.env.NODE_ENV !== "production") {
2477
- if (!condition) {
2478
- const err = new Error(errmsg);
2479
- err.name = "Assertion failure";
2480
- throw err;
2481
- }
2482
- }
2483
- }
2484
- function nn(value, errmsg = "Expected value to be non-nullable") {
2485
- assert(value !== null && value !== void 0, errmsg);
2486
- return value;
2487
- }
2488
-
2489
2548
  // src/lib/fsm.ts
2490
2549
  function distance(state1, state2) {
2491
2550
  if (state1 === state2) {
@@ -5121,6 +5180,7 @@ async function fetchAuthEndpoint(fetch, endpoint, body) {
5121
5180
 
5122
5181
  // src/constants.ts
5123
5182
  var DEFAULT_BASE_URL = "https://api.liveblocks.io";
5183
+ var MENTION_CHARACTER = "@";
5124
5184
 
5125
5185
  // src/devtools/bridge.ts
5126
5186
  var _bridgeActive = false;
@@ -5340,6 +5400,22 @@ function unlinkDevTools(roomId) {
5340
5400
  });
5341
5401
  }
5342
5402
 
5403
+ // src/lib/warnings.ts
5404
+ var _emittedWarnings = /* @__PURE__ */ new Set();
5405
+ function warnOnce(message, key = message) {
5406
+ if (process.env.NODE_ENV !== "production") {
5407
+ if (!_emittedWarnings.has(key)) {
5408
+ _emittedWarnings.add(key);
5409
+ warn(message);
5410
+ }
5411
+ }
5412
+ }
5413
+ function warnOnceIf(condition, message, key = message) {
5414
+ if (typeof condition === "function" ? condition() : condition) {
5415
+ warnOnce(message, key);
5416
+ }
5417
+ }
5418
+
5343
5419
  // src/protocol/NotificationSettings.ts
5344
5420
  var kPlain = Symbol("notification-settings-plain");
5345
5421
  function createNotificationSettings(plain) {
@@ -6392,14 +6468,13 @@ var LiveList = class _LiveList extends AbstractCrdt {
6392
6468
  const previousKey = nn(child._parentKey);
6393
6469
  const previousIndex = this.#items.indexOf(child);
6394
6470
  const existingItemIndex = this._indexOfPosition(newKey);
6395
- let actualNewKey = newKey;
6396
6471
  if (existingItemIndex !== -1) {
6397
- actualNewKey = makePosition(
6398
- newKey,
6399
- this.#items[existingItemIndex + 1]?._parentPos
6472
+ this.#items[existingItemIndex]._setParentLink(
6473
+ this,
6474
+ makePosition(newKey, this.#items[existingItemIndex + 1]?._parentPos)
6400
6475
  );
6401
6476
  }
6402
- child._setParentLink(this, actualNewKey);
6477
+ child._setParentLink(this, newKey);
6403
6478
  this._sortItems();
6404
6479
  const newIndex = this.#items.indexOf(child);
6405
6480
  if (previousIndex === newIndex) {
@@ -8555,8 +8630,8 @@ function createRoom(options, config) {
8555
8630
  comments: makeEventSource(),
8556
8631
  roomWillDestroy: makeEventSource()
8557
8632
  };
8558
- async function createTextMention(userId, mentionId) {
8559
- return httpClient.createTextMention({ roomId, userId, mentionId });
8633
+ async function createTextMention(mentionId, mention) {
8634
+ return httpClient.createTextMention({ roomId, mentionId, mention });
8560
8635
  }
8561
8636
  async function deleteTextMention(mentionId) {
8562
8637
  return httpClient.deleteTextMention({ roomId, mentionId });
@@ -9877,6 +9952,7 @@ var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
9877
9952
  var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
9878
9953
  var RESOLVE_USERS_BATCH_DELAY = 50;
9879
9954
  var RESOLVE_ROOMS_INFO_BATCH_DELAY = 50;
9955
+ var RESOLVE_GROUPS_INFO_BATCH_DELAY = 50;
9880
9956
  function getBaseUrl(baseUrl) {
9881
9957
  if (typeof baseUrl === "string" && baseUrl.startsWith("http")) {
9882
9958
  return baseUrl;
@@ -9886,7 +9962,7 @@ function getBaseUrl(baseUrl) {
9886
9962
  }
9887
9963
  function createClient(options) {
9888
9964
  const clientOptions = options;
9889
- const throttleDelay = process.env.NODE_ENV !== "production" && clientOptions.__DANGEROUSLY_disableThrottling ? 0 : getThrottle(clientOptions.throttle ?? DEFAULT_THROTTLE);
9965
+ const throttleDelay = getThrottle(clientOptions.throttle ?? DEFAULT_THROTTLE);
9890
9966
  const lostConnectionTimeout = getLostConnectionTimeout(
9891
9967
  clientOptions.lostConnectionTimeout ?? DEFAULT_LOST_CONNECTION_TIMEOUT
9892
9968
  );
@@ -10034,15 +10110,14 @@ function createClient(options) {
10034
10110
  }
10035
10111
  }
10036
10112
  const resolveUsers = clientOptions.resolveUsers;
10037
- const warnIfNoResolveUsers = createDevelopmentWarning(
10038
- () => !resolveUsers,
10039
- "Set the resolveUsers option in createClient to specify user info."
10040
- );
10041
10113
  const batchedResolveUsers = new Batch(
10042
10114
  async (batchedUserIds) => {
10043
10115
  const userIds = batchedUserIds.flat();
10044
10116
  const users = await resolveUsers?.({ userIds });
10045
- warnIfNoResolveUsers();
10117
+ warnOnceIf(
10118
+ !resolveUsers,
10119
+ "Set the resolveUsers option in createClient to specify user info."
10120
+ );
10046
10121
  return users ?? userIds.map(() => void 0);
10047
10122
  },
10048
10123
  { delay: RESOLVE_USERS_BATCH_DELAY }
@@ -10052,15 +10127,14 @@ function createClient(options) {
10052
10127
  usersStore.invalidate(userIds);
10053
10128
  }
10054
10129
  const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
10055
- const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
10056
- () => !resolveRoomsInfo,
10057
- "Set the resolveRoomsInfo option in createClient to specify room info."
10058
- );
10059
10130
  const batchedResolveRoomsInfo = new Batch(
10060
10131
  async (batchedRoomIds) => {
10061
10132
  const roomIds = batchedRoomIds.flat();
10062
10133
  const roomsInfo = await resolveRoomsInfo?.({ roomIds });
10063
- warnIfNoResolveRoomsInfo();
10134
+ warnOnceIf(
10135
+ !resolveRoomsInfo,
10136
+ "Set the resolveRoomsInfo option in createClient to specify room info."
10137
+ );
10064
10138
  return roomsInfo ?? roomIds.map(() => void 0);
10065
10139
  },
10066
10140
  { delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
@@ -10069,6 +10143,23 @@ function createClient(options) {
10069
10143
  function invalidateResolvedRoomsInfo(roomIds) {
10070
10144
  roomsInfoStore.invalidate(roomIds);
10071
10145
  }
10146
+ const resolveGroupsInfo = clientOptions.resolveGroupsInfo;
10147
+ const batchedResolveGroupsInfo = new Batch(
10148
+ async (batchedGroupIds) => {
10149
+ const groupIds = batchedGroupIds.flat();
10150
+ const groupsInfo = await resolveGroupsInfo?.({ groupIds });
10151
+ warnOnceIf(
10152
+ !resolveGroupsInfo,
10153
+ "Set the resolveGroupsInfo option in createClient to specify group info."
10154
+ );
10155
+ return groupsInfo ?? groupIds.map(() => void 0);
10156
+ },
10157
+ { delay: RESOLVE_GROUPS_INFO_BATCH_DELAY }
10158
+ );
10159
+ const groupsInfoStore = createBatchStore(batchedResolveGroupsInfo);
10160
+ function invalidateResolvedGroupsInfo(groupIds) {
10161
+ groupsInfoStore.invalidate(groupIds);
10162
+ }
10072
10163
  const mentionSuggestionsCache = /* @__PURE__ */ new Map();
10073
10164
  function invalidateResolvedMentionSuggestions() {
10074
10165
  mentionSuggestionsCache.clear();
@@ -10144,6 +10235,7 @@ function createClient(options) {
10144
10235
  resolvers: {
10145
10236
  invalidateUsers: invalidateResolvedUsers,
10146
10237
  invalidateRoomsInfo: invalidateResolvedRoomsInfo,
10238
+ invalidateGroupsInfo: invalidateResolvedGroupsInfo,
10147
10239
  invalidateMentionSuggestions: invalidateResolvedMentionSuggestions
10148
10240
  },
10149
10241
  getSyncStatus,
@@ -10159,6 +10251,7 @@ function createClient(options) {
10159
10251
  resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
10160
10252
  usersStore,
10161
10253
  roomsInfoStore,
10254
+ groupsInfoStore,
10162
10255
  getRoomIds() {
10163
10256
  return Array.from(roomsById.keys());
10164
10257
  },
@@ -10210,20 +10303,6 @@ function getLostConnectionTimeout(value) {
10210
10303
  RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
10211
10304
  );
10212
10305
  }
10213
- function createDevelopmentWarning(condition, ...args) {
10214
- let hasWarned = false;
10215
- if (process.env.NODE_ENV !== "production") {
10216
- return () => {
10217
- if (!hasWarned && (typeof condition === "function" ? condition() : condition)) {
10218
- warn(...args);
10219
- hasWarned = true;
10220
- }
10221
- };
10222
- } else {
10223
- return () => {
10224
- };
10225
- }
10226
- }
10227
10306
 
10228
10307
  // src/comments/comment-body.ts
10229
10308
  function isCommentBodyParagraph(element) {
@@ -10288,25 +10367,42 @@ function getMentionsFromCommentBody(body, predicate) {
10288
10367
  });
10289
10368
  return mentions;
10290
10369
  }
10291
- async function resolveUsersInCommentBody(body, resolveUsers) {
10370
+ async function resolveMentionsInCommentBody(body, resolveUsers, resolveGroupsInfo) {
10292
10371
  const resolvedUsers = /* @__PURE__ */ new Map();
10293
- if (!resolveUsers) {
10294
- return resolvedUsers;
10372
+ const resolvedGroupsInfo = /* @__PURE__ */ new Map();
10373
+ if (!resolveUsers && !resolveGroupsInfo) {
10374
+ return {
10375
+ users: resolvedUsers,
10376
+ groups: resolvedGroupsInfo
10377
+ };
10295
10378
  }
10296
- const userIds = getMentionsFromCommentBody(
10297
- body,
10298
- (mention) => mention.kind === "user"
10299
- ).map((mention) => mention.id);
10300
- const users = await resolveUsers({
10301
- userIds
10302
- });
10303
- for (const [index, userId] of userIds.entries()) {
10304
- const user = users?.[index];
10305
- if (user) {
10306
- resolvedUsers.set(userId, user);
10379
+ const mentions = getMentionsFromCommentBody(body);
10380
+ const userIds = mentions.filter((mention) => mention.kind === "user").map((mention) => mention.id);
10381
+ const groupIds = mentions.filter((mention) => mention.kind === "group").map((mention) => mention.id);
10382
+ const [users, groups] = await Promise.all([
10383
+ resolveUsers && userIds.length > 0 ? resolveUsers({ userIds }) : void 0,
10384
+ resolveGroupsInfo && groupIds.length > 0 ? resolveGroupsInfo({ groupIds }) : void 0
10385
+ ]);
10386
+ if (users) {
10387
+ for (const [index, userId] of userIds.entries()) {
10388
+ const user = users[index];
10389
+ if (user) {
10390
+ resolvedUsers.set(userId, user);
10391
+ }
10392
+ }
10393
+ }
10394
+ if (groups) {
10395
+ for (const [index, groupId] of groupIds.entries()) {
10396
+ const group = groups[index];
10397
+ if (group) {
10398
+ resolvedGroupsInfo.set(groupId, group);
10399
+ }
10307
10400
  }
10308
10401
  }
10309
- return resolvedUsers;
10402
+ return {
10403
+ users: resolvedUsers,
10404
+ groups: resolvedGroupsInfo
10405
+ };
10310
10406
  }
10311
10407
  var htmlEscapables = {
10312
10408
  "&": "&",
@@ -10419,8 +10515,8 @@ var stringifyCommentBodyPlainElements = {
10419
10515
  paragraph: ({ children }) => children,
10420
10516
  text: ({ element }) => element.text,
10421
10517
  link: ({ element }) => element.text ?? element.url,
10422
- mention: ({ element, user }) => {
10423
- return `@${user?.name ?? element.id}`;
10518
+ mention: ({ element, user, group }) => {
10519
+ return `@${user?.name ?? group?.name ?? element.id}`;
10424
10520
  }
10425
10521
  };
10426
10522
  var stringifyCommentBodyHtmlElements = {
@@ -10449,8 +10545,8 @@ var stringifyCommentBodyHtmlElements = {
10449
10545
  link: ({ element, href }) => {
10450
10546
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
10451
10547
  },
10452
- mention: ({ element, user }) => {
10453
- return html`<span data-mention>@${user?.name ? html`${user?.name}` : element.id}</span>`;
10548
+ mention: ({ element, user, group }) => {
10549
+ return html`<span data-mention>@${user?.name ? html`${user?.name}` : group?.name ? html`${group?.name}` : element.id}</span>`;
10454
10550
  }
10455
10551
  };
10456
10552
  var stringifyCommentBodyMarkdownElements = {
@@ -10479,8 +10575,8 @@ var stringifyCommentBodyMarkdownElements = {
10479
10575
  link: ({ element, href }) => {
10480
10576
  return markdown`[${element.text ?? element.url}](${href})`;
10481
10577
  },
10482
- mention: ({ element, user }) => {
10483
- return markdown`@${user?.name ?? element.id}`;
10578
+ mention: ({ element, user, group }) => {
10579
+ return markdown`@${user?.name ?? group?.name ?? element.id}`;
10484
10580
  }
10485
10581
  };
10486
10582
  async function stringifyCommentBody(body, options) {
@@ -10490,9 +10586,10 @@ async function stringifyCommentBody(body, options) {
10490
10586
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
10491
10587
  ...options?.elements
10492
10588
  };
10493
- const resolvedUsers = await resolveUsersInCommentBody(
10589
+ const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
10494
10590
  body,
10495
- options?.resolveUsers
10591
+ options?.resolveUsers,
10592
+ options?.resolveGroupsInfo
10496
10593
  );
10497
10594
  const blocks = body.content.flatMap((block, blockIndex) => {
10498
10595
  switch (block.type) {
@@ -10503,7 +10600,8 @@ async function stringifyCommentBody(body, options) {
10503
10600
  elements.mention(
10504
10601
  {
10505
10602
  element: inline,
10506
- user: resolvedUsers.get(inline.id)
10603
+ user: inline.kind === "user" ? resolvedUsers.get(inline.id) : void 0,
10604
+ group: inline.kind === "group" ? resolvedGroupsInfo.get(inline.id) : void 0
10507
10605
  },
10508
10606
  inlineIndex
10509
10607
  )
@@ -11057,6 +11155,7 @@ export {
11057
11155
  LiveMap,
11058
11156
  LiveObject,
11059
11157
  LiveblocksError,
11158
+ MENTION_CHARACTER,
11060
11159
  MutableSignal,
11061
11160
  OpCode,
11062
11161
  Permission,
@@ -11080,6 +11179,7 @@ export {
11080
11179
  fancy_console_exports as console,
11081
11180
  convertToCommentData,
11082
11181
  convertToCommentUserReaction,
11182
+ convertToGroupData,
11083
11183
  convertToInboxNotificationData,
11084
11184
  convertToSubscriptionData,
11085
11185
  convertToThreadData,
@@ -11133,7 +11233,7 @@ export {
11133
11233
  patchLiveObjectKey,
11134
11234
  patchNotificationSettings,
11135
11235
  raise,
11136
- resolveUsersInCommentBody,
11236
+ resolveMentionsInCommentBody,
11137
11237
  sanitizeUrl,
11138
11238
  shallow,
11139
11239
  shallow2,
@@ -11145,6 +11245,8 @@ export {
11145
11245
  url,
11146
11246
  urljoin,
11147
11247
  wait,
11248
+ warnOnce,
11249
+ warnOnceIf,
11148
11250
  withTimeout
11149
11251
  };
11150
11252
  //# sourceMappingURL=index.js.map