@liveblocks/emails 3.6.0 → 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.cjs CHANGED
@@ -3,7 +3,7 @@ var _core = require('@liveblocks/core');
3
3
 
4
4
  // src/version.ts
5
5
  var PKG_NAME = "@liveblocks/emails";
6
- var PKG_VERSION = "3.6.0";
6
+ var PKG_VERSION = "3.7.0-preview1";
7
7
  var PKG_FORMAT = "cjs";
8
8
 
9
9
  // src/text-mention-notification.tsx
@@ -12,6 +12,10 @@ var PKG_FORMAT = "cjs";
12
12
 
13
13
 
14
14
 
15
+
16
+ // src/lexical-editor.ts
17
+
18
+
15
19
  // ../../node_modules/lib0/map.js
16
20
  var create = () => /* @__PURE__ */ new Map();
17
21
  var copy = (m) => {
@@ -7524,6 +7528,16 @@ var isSerializedMentionNode = (node) => {
7524
7528
  const attributes = node.attributes;
7525
7529
  return isMentionNodeType(node.type) && isMentionNodeAttributeType(attributes.__type) && isMentionNodeAttributeId(attributes.__id) && isString(attributes.__userId);
7526
7530
  };
7531
+ var isGroupMentionNodeType = (type) => {
7532
+ return type === "lb-group-mention";
7533
+ };
7534
+ var isGroupMentionNodeAttributeType = (type) => {
7535
+ return isString(type) && type === "lb-group-mention";
7536
+ };
7537
+ var isSerializedGroupMentionNode = (node) => {
7538
+ const attributes = node.attributes;
7539
+ return isGroupMentionNodeType(node.type) && isGroupMentionNodeAttributeType(attributes.__type) && isMentionNodeAttributeId(attributes.__id) && isString(attributes.__groupId) && (attributes.__userIds === void 0 || Array.isArray(attributes.__userIds));
7540
+ };
7527
7541
  var isFlattenedLexicalElementNodeMarker = (node) => {
7528
7542
  return node.group === "element-marker";
7529
7543
  };
@@ -7551,14 +7565,13 @@ var flattenLexicalTree = (nodes) => {
7551
7565
  };
7552
7566
  function findLexicalMentionNodeWithContext({
7553
7567
  root,
7554
- mentionedUserId,
7555
- mentionId
7568
+ textMentionId
7556
7569
  }) {
7557
7570
  const nodes = flattenLexicalTree(root.children);
7558
7571
  let mentionNodeIndex = -1;
7559
7572
  for (let i = 0; i < nodes.length; i++) {
7560
7573
  const node = nodes[i];
7561
- if (node.group === "decorator" && isSerializedMentionNode(node) && node.attributes.__id === mentionId && node.attributes.__userId === mentionedUserId) {
7574
+ if (node.group === "decorator" && (isSerializedMentionNode(node) || isSerializedGroupMentionNode(node)) && node.attributes.__id === textMentionId) {
7562
7575
  mentionNodeIndex = i;
7563
7576
  break;
7564
7577
  }
@@ -7595,112 +7608,112 @@ function findLexicalMentionNodeWithContext({
7595
7608
  mention: mentionNode
7596
7609
  };
7597
7610
  }
7598
-
7599
- // src/lib/authors.ts
7600
- var resolveAuthorsInfo = async ({
7601
- userIds,
7602
- resolveUsers
7603
- }) => {
7604
- const resolvedUsers = /* @__PURE__ */ new Map();
7605
- if (!resolveUsers) {
7606
- return resolvedUsers;
7607
- }
7608
- const users = await resolveUsers({ userIds });
7609
- for (const [index, userId] of userIds.entries()) {
7610
- const user = _optionalChain([users, 'optionalAccess', _5 => _5[index]]);
7611
- if (user) {
7612
- resolvedUsers.set(userId, user);
7613
- }
7614
- }
7615
- return resolvedUsers;
7616
- };
7617
-
7618
- // src/lib/batch-users-resolver.ts
7619
-
7620
-
7621
- // src/lib/warning.ts
7622
- var createDevelopmentWarning = (condition, ...args2) => {
7623
- let hasWarned = false;
7624
- if (process.env.NODE_ENV !== "production") {
7625
- return () => {
7626
- if (!hasWarned && (typeof condition === "function" ? condition() : condition)) {
7627
- console.warn(...args2);
7628
- hasWarned = true;
7629
- }
7611
+ function getMentionDataFromLexicalNode(node) {
7612
+ if (isSerializedMentionNode(node)) {
7613
+ return {
7614
+ kind: "user",
7615
+ id: node.attributes.__userId
7630
7616
  };
7631
- } else {
7632
- return () => {
7617
+ } else if (isSerializedGroupMentionNode(node)) {
7618
+ return {
7619
+ kind: "group",
7620
+ id: node.attributes.__groupId,
7621
+ userIds: node.attributes.__userIds
7633
7622
  };
7634
7623
  }
7635
- };
7624
+ _core.assertNever.call(void 0, node, "Unknown mention kind");
7625
+ }
7636
7626
 
7637
- // src/lib/batch-users-resolver.ts
7638
- var BatchUsersResolver = (_class = class {
7639
-
7640
-
7627
+ // src/lib/batch-resolvers.ts
7628
+
7629
+ function getResolvedForId(id2, ids, results) {
7630
+ const index = ids.indexOf(id2);
7631
+ return _optionalChain([results, 'optionalAccess', _5 => _5[index]]);
7632
+ }
7633
+ var BatchResolver = (_class = class {
7634
+ __init() {this.ids = /* @__PURE__ */ new Set()}
7635
+ __init2() {this.results = /* @__PURE__ */ new Map()}
7636
+ __init3() {this.isResolved = false}
7641
7637
 
7642
7638
 
7643
7639
 
7644
7640
 
7645
- constructor(resolveUsers) {;_class.prototype.__init.call(this);
7641
+ constructor(callback, missingCallbackWarning) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);
7642
+ this.callback = callback;
7646
7643
  const { promise, resolve } = _core.Promise_withResolvers.call(void 0, );
7647
- this.isResolved = false;
7648
- this.markAsResolved = resolve;
7649
- this.resolvePromise = promise;
7650
- this.primeResolveUsersFn = resolveUsers;
7651
- this.usersById = /* @__PURE__ */ new Map();
7652
- this.warnAsAlreadyResolved = createDevelopmentWarning(
7653
- true,
7654
- "Batch users resolver promise already resolved. It can only resolve once."
7655
- );
7644
+ this.promise = promise;
7645
+ this.resolvePromise = resolve;
7646
+ this.missingCallbackWarning = missingCallbackWarning;
7656
7647
  }
7657
- __init() {this.resolveUsers = async (args2) => {
7648
+ /**
7649
+ * Add IDs to the batch and return a promise that resolves when the entire batch is resolved.
7650
+ * It can't be called after the batch is resolved.
7651
+ */
7652
+ async get(ids) {
7658
7653
  if (this.isResolved) {
7659
- this.warnAsAlreadyResolved();
7660
- return void 0;
7661
- }
7662
- for (const userId of args2.userIds) {
7663
- this.usersById.set(userId, void 0);
7654
+ throw new Error("Batch has already been resolved.");
7664
7655
  }
7665
- await this.resolvePromise;
7666
- return args2.userIds.map((userId) => this.usersById.get(userId));
7667
- }}
7656
+ ids.forEach((id2) => this.ids.add(id2));
7657
+ await this.promise;
7658
+ return ids.map((id2) => this.results.get(id2));
7659
+ }
7660
+ #resolveBatch() {
7661
+ this.isResolved = true;
7662
+ this.resolvePromise();
7663
+ }
7664
+ /**
7665
+ * Resolve all the IDs in the batch.
7666
+ * It can only be called once.
7667
+ */
7668
7668
  async resolve() {
7669
7669
  if (this.isResolved) {
7670
- this.warnAsAlreadyResolved();
7670
+ throw new Error("Batch has already been resolved.");
7671
+ }
7672
+ if (!this.callback) {
7673
+ _core.warnOnce.call(void 0, this.missingCallbackWarning);
7674
+ this.#resolveBatch();
7671
7675
  return;
7672
7676
  }
7673
- const userIds = Array.from(this.usersById.keys());
7674
- const users = await _optionalChain([this, 'access', _6 => _6.primeResolveUsersFn, 'optionalCall', _7 => _7({ userIds })]);
7675
- for (const [index, userId] of userIds.entries()) {
7676
- const user = _optionalChain([users, 'optionalAccess', _8 => _8[index]]);
7677
- this.usersById.set(userId, user);
7677
+ const ids = Array.from(this.ids);
7678
+ try {
7679
+ const results = this.callback ? await this.callback(ids) : void 0;
7680
+ if (results !== void 0) {
7681
+ if (!Array.isArray(results)) {
7682
+ throw new Error("Callback must return an array.");
7683
+ } else if (ids.length !== results.length) {
7684
+ throw new Error(
7685
+ `Callback must return an array of the same length as the number of provided items. Expected ${ids.length}, but got ${results.length}.`
7686
+ );
7687
+ }
7688
+ }
7689
+ ids.forEach((id2, index) => {
7690
+ this.results.set(id2, _optionalChain([results, 'optionalAccess', _6 => _6[index]]));
7691
+ });
7692
+ } catch (error) {
7693
+ this.#resolveBatch();
7694
+ throw error;
7678
7695
  }
7679
- this.isResolved = true;
7680
- this.markAsResolved();
7696
+ this.#resolveBatch();
7681
7697
  }
7682
7698
  }, _class);
7683
7699
  function createBatchUsersResolver({
7684
7700
  resolveUsers,
7685
7701
  callerName
7686
7702
  }) {
7687
- const warnIfNoResolveUsers = createDevelopmentWarning(
7688
- () => !resolveUsers,
7689
- `Set "resolveUsers" option in "${callerName}" to specify users info`
7703
+ return new BatchResolver(
7704
+ resolveUsers ? (userIds) => resolveUsers({ userIds }) : void 0,
7705
+ `Set "resolveUsers" in "${callerName}" to specify users info`
7706
+ );
7707
+ }
7708
+ function createBatchGroupsInfoResolver({
7709
+ resolveGroupsInfo,
7710
+ callerName
7711
+ }) {
7712
+ return new BatchResolver(
7713
+ resolveGroupsInfo ? (groupIds) => resolveGroupsInfo({ groupIds }) : void 0,
7714
+ `Set "resolveGroupsInfo" in "${callerName}" to specify groups info`
7690
7715
  );
7691
- const batchUsersResolver = new BatchUsersResolver(resolveUsers);
7692
- const resolve = async () => {
7693
- warnIfNoResolveUsers();
7694
- await batchUsersResolver.resolve();
7695
- };
7696
- return {
7697
- resolveUsers: batchUsersResolver.resolveUsers,
7698
- resolve
7699
- };
7700
7716
  }
7701
-
7702
- // src/lib/constants.ts
7703
- var MENTION_CHARACTER = "@";
7704
7717
 
7705
7718
  // src/lib/css-properties.ts
7706
7719
  var VENDORS_PREFIXES = new RegExp(/^(webkit|moz|ms|o)-/);
@@ -7789,6 +7802,9 @@ function toInlineCSSString(styles) {
7789
7802
  return inline;
7790
7803
  }
7791
7804
 
7805
+ // src/tiptap-editor.ts
7806
+
7807
+
7792
7808
  // ../../node_modules/y-prosemirror/src/lib.js
7793
7809
  function yXmlFragmentToProsemirrorJSON(xmlFragment) {
7794
7810
  const items = xmlFragment.toArray();
@@ -7861,6 +7877,9 @@ var isSerializedTextNode = (node) => {
7861
7877
  var isSerializedMentionNode2 = (node) => {
7862
7878
  return node.type === "liveblocksMention" && isMentionNodeAttributeId(node.attrs.notificationId);
7863
7879
  };
7880
+ var isSerializedGroupMentionNode2 = (node) => {
7881
+ return node.type === "liveblocksGroupMention" && isMentionNodeAttributeId(node.attrs.notificationId);
7882
+ };
7864
7883
  var isSerializedParagraphNode = (node) => {
7865
7884
  return node.type === "paragraph" && typeof node.content !== "undefined";
7866
7885
  };
@@ -7870,7 +7889,7 @@ var isFlattenedTiptapParagraphNodeMarker = (node) => {
7870
7889
  var flattenTiptapTree = (nodes) => {
7871
7890
  let flattenNodes = [];
7872
7891
  for (const node of nodes) {
7873
- if (isSerializedEmptyParagraphNode(node) || isSerializedHardBreakNode(node) || isSerializedTextNode(node) || isSerializedMentionNode2(node)) {
7892
+ if (isSerializedEmptyParagraphNode(node) || isSerializedHardBreakNode(node) || isSerializedTextNode(node) || isSerializedMentionNode2(node) || isSerializedGroupMentionNode2(node)) {
7874
7893
  flattenNodes = [...flattenNodes, node];
7875
7894
  } else if (isSerializedParagraphNode(node)) {
7876
7895
  flattenNodes = [
@@ -7891,14 +7910,13 @@ var flattenTiptapTree = (nodes) => {
7891
7910
  };
7892
7911
  function findTiptapMentionNodeWithContext({
7893
7912
  root,
7894
- mentionedUserId,
7895
- mentionId
7913
+ textMentionId
7896
7914
  }) {
7897
7915
  const nodes = flattenTiptapTree(root.content);
7898
7916
  let mentionNodeIndex = -1;
7899
7917
  for (let i = 0; i < nodes.length; i++) {
7900
7918
  const node = nodes[i];
7901
- if (!isFlattenedTiptapParagraphNodeMarker(node) && isSerializedMentionNode2(node) && node.attrs.notificationId === mentionId && node.attrs.id === mentionedUserId) {
7919
+ if (!isFlattenedTiptapParagraphNodeMarker(node) && (isSerializedMentionNode2(node) || isSerializedGroupMentionNode2(node)) && node.attrs.notificationId === textMentionId) {
7902
7920
  mentionNodeIndex = i;
7903
7921
  break;
7904
7922
  }
@@ -7929,6 +7947,35 @@ function findTiptapMentionNodeWithContext({
7929
7947
  mention: mentionNode
7930
7948
  };
7931
7949
  }
7950
+ function deserializeGroupUserIds(userIds) {
7951
+ if (typeof userIds !== "string") {
7952
+ return void 0;
7953
+ }
7954
+ try {
7955
+ const parsedUserIds = JSON.parse(userIds);
7956
+ if (Array.isArray(parsedUserIds)) {
7957
+ return parsedUserIds;
7958
+ }
7959
+ return void 0;
7960
+ } catch (e2) {
7961
+ return void 0;
7962
+ }
7963
+ }
7964
+ function getMentionDataFromTiptapNode(node) {
7965
+ if (isSerializedMentionNode2(node)) {
7966
+ return {
7967
+ kind: "user",
7968
+ id: node.attrs.id
7969
+ };
7970
+ } else if (isSerializedGroupMentionNode2(node)) {
7971
+ return {
7972
+ kind: "group",
7973
+ id: node.attrs.id,
7974
+ userIds: deserializeGroupUserIds(node.attrs.userIds)
7975
+ };
7976
+ }
7977
+ _core.assertNever.call(void 0, node, "Unknown mention kind");
7978
+ }
7932
7979
 
7933
7980
  // src/liveblocks-text-editor.ts
7934
7981
  var baseLiveblocksTextEditorTextFormat = {
@@ -7972,14 +8019,20 @@ var transformLexicalMentionNodeWithContext = (mentionNodeWithContext) => {
7972
8019
  kind: "user",
7973
8020
  id: node.attributes.__userId
7974
8021
  });
8022
+ } else if (node.group === "decorator" && isSerializedGroupMentionNode(node)) {
8023
+ textEditorNodes.push({
8024
+ type: "mention",
8025
+ kind: "group",
8026
+ id: node.attributes.__groupId
8027
+ });
7975
8028
  }
7976
8029
  }
7977
8030
  };
7978
8031
  transform(before);
7979
8032
  textEditorNodes.push({
7980
8033
  type: "mention",
7981
- kind: "user",
7982
- id: mention.attributes.__userId
8034
+ kind: mention.type === "lb-group-mention" ? "group" : "user",
8035
+ id: mention.type === "lb-group-mention" ? mention.attributes.__groupId : mention.attributes.__userId
7983
8036
  });
7984
8037
  transform(after);
7985
8038
  return textEditorNodes;
@@ -8015,13 +8068,19 @@ var transformTiptapMentionNodeWithContext = (mentionNodeWithContext) => {
8015
8068
  kind: "user",
8016
8069
  id: node.attrs.id
8017
8070
  });
8071
+ } else if (isSerializedGroupMentionNode2(node)) {
8072
+ textEditorNodes.push({
8073
+ type: "mention",
8074
+ kind: "group",
8075
+ id: node.attrs.id
8076
+ });
8018
8077
  }
8019
8078
  }
8020
8079
  };
8021
8080
  transform(before);
8022
8081
  textEditorNodes.push({
8023
8082
  type: "mention",
8024
- kind: "user",
8083
+ kind: mention.type === "liveblocksGroupMention" ? "group" : "user",
8025
8084
  id: mention.attrs.id
8026
8085
  });
8027
8086
  transform(after);
@@ -8041,19 +8100,32 @@ function transformAsLiveblocksTextEditorNodes(transformableMention) {
8041
8100
  }
8042
8101
  }
8043
8102
  }
8044
- var resolveUsersInLiveblocksTextEditorNodes = async (nodes, resolveUsers) => {
8103
+ var resolveMentionsInLiveblocksTextEditorNodes = async (nodes, resolveUsers, resolveGroupsInfo) => {
8045
8104
  const resolvedUsers = /* @__PURE__ */ new Map();
8046
- if (!resolveUsers) {
8047
- return resolvedUsers;
8105
+ const resolvedGroupsInfo = /* @__PURE__ */ new Map();
8106
+ if (!resolveUsers && !resolveGroupsInfo) {
8107
+ return {
8108
+ users: resolvedUsers,
8109
+ groups: resolvedGroupsInfo
8110
+ };
8048
8111
  }
8049
8112
  const mentionedUserIds = /* @__PURE__ */ new Set();
8113
+ const mentionedGroupIds = /* @__PURE__ */ new Set();
8050
8114
  for (const node of nodes) {
8051
- if (node.type === "mention" && node.kind === "user") {
8052
- mentionedUserIds.add(node.id);
8115
+ if (node.type === "mention") {
8116
+ if (node.kind === "user") {
8117
+ mentionedUserIds.add(node.id);
8118
+ } else if (node.kind === "group") {
8119
+ mentionedGroupIds.add(node.id);
8120
+ }
8053
8121
  }
8054
8122
  }
8055
8123
  const userIds = Array.from(mentionedUserIds);
8056
- const users = await resolveUsers({ userIds });
8124
+ const groupIds = Array.from(mentionedGroupIds);
8125
+ const [users, groups] = await Promise.all([
8126
+ resolveUsers && userIds.length > 0 ? resolveUsers({ userIds }) : void 0,
8127
+ resolveGroupsInfo && groupIds.length > 0 ? resolveGroupsInfo({ groupIds }) : void 0
8128
+ ]);
8057
8129
  if (users) {
8058
8130
  for (const [index, userId] of userIds.entries()) {
8059
8131
  const user = users[index];
@@ -8062,24 +8134,36 @@ var resolveUsersInLiveblocksTextEditorNodes = async (nodes, resolveUsers) => {
8062
8134
  }
8063
8135
  }
8064
8136
  }
8065
- return resolvedUsers;
8137
+ if (groups) {
8138
+ for (const [index, groupId] of groupIds.entries()) {
8139
+ const group = groups[index];
8140
+ if (group) {
8141
+ resolvedGroupsInfo.set(groupId, group);
8142
+ }
8143
+ }
8144
+ }
8145
+ return {
8146
+ users: resolvedUsers,
8147
+ groups: resolvedGroupsInfo
8148
+ };
8066
8149
  };
8067
8150
 
8068
- // src/mention-content.tsx
8069
-
8070
- async function convertMentionContent(nodes, options) {
8071
- const resolvedUsers = await resolveUsersInLiveblocksTextEditorNodes(
8151
+ // src/text-mention-content.tsx
8152
+ async function convertTextMentionContent(nodes, options) {
8153
+ const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInLiveblocksTextEditorNodes(
8072
8154
  nodes,
8073
- _optionalChain([options, 'optionalAccess', _9 => _9.resolveUsers])
8155
+ _optionalChain([options, 'optionalAccess', _7 => _7.resolveUsers]),
8156
+ _optionalChain([options, 'optionalAccess', _8 => _8.resolveGroupsInfo])
8074
8157
  );
8075
8158
  const blocks = nodes.map((node, index) => {
8076
8159
  switch (node.type) {
8077
8160
  case "mention": {
8078
- if (node.kind !== "user") {
8079
- return _core.assertNever.call(void 0, node.kind, "Unknown mention kind");
8080
- }
8081
8161
  return options.elements.mention(
8082
- { node, user: resolvedUsers.get(node.id) },
8162
+ {
8163
+ node,
8164
+ user: node.kind === "user" ? resolvedUsers.get(node.id) : void 0,
8165
+ group: node.kind === "group" ? resolvedGroupsInfo.get(node.id) : void 0
8166
+ },
8083
8167
  index
8084
8168
  );
8085
8169
  }
@@ -8125,17 +8209,19 @@ var extractTextMentionNotificationData = async ({
8125
8209
  const state = getSerializedLexicalState({ buffer, key });
8126
8210
  const mentionNodeWithContext = findLexicalMentionNodeWithContext({
8127
8211
  root: state,
8128
- mentionedUserId: userId,
8129
- mentionId: inboxNotification.mentionId
8212
+ textMentionId: inboxNotification.mentionId
8130
8213
  });
8131
8214
  if (mentionNodeWithContext === null) {
8132
8215
  return null;
8133
8216
  }
8217
+ const mentionData = getMentionDataFromLexicalNode(
8218
+ mentionNodeWithContext.mention
8219
+ );
8134
8220
  return {
8135
8221
  editor: "lexical",
8136
8222
  mentionNodeWithContext,
8223
+ mentionData,
8137
8224
  createdAt: mentionCreatedAt,
8138
- userId,
8139
8225
  createdBy: mentionAuthorUserId
8140
8226
  };
8141
8227
  }
@@ -8143,17 +8229,19 @@ var extractTextMentionNotificationData = async ({
8143
8229
  const state = getSerializedTiptapState({ buffer, key });
8144
8230
  const mentionNodeWithContext = findTiptapMentionNodeWithContext({
8145
8231
  root: state,
8146
- mentionedUserId: userId,
8147
- mentionId: inboxNotification.mentionId
8232
+ textMentionId: inboxNotification.mentionId
8148
8233
  });
8149
8234
  if (mentionNodeWithContext === null) {
8150
8235
  return null;
8151
8236
  }
8237
+ const mentionData = getMentionDataFromTiptapNode(
8238
+ mentionNodeWithContext.mention
8239
+ );
8152
8240
  return {
8153
8241
  editor: "tiptap",
8154
8242
  mentionNodeWithContext,
8243
+ mentionData,
8155
8244
  createdAt: mentionCreatedAt,
8156
- userId,
8157
8245
  createdBy: mentionAuthorUserId
8158
8246
  };
8159
8247
  }
@@ -8168,16 +8256,18 @@ async function prepareTextMentionNotificationEmail(client, event, options, eleme
8168
8256
  const roomInfo = options.resolveRoomInfo ? await options.resolveRoomInfo({ roomId: event.data.roomId }) : void 0;
8169
8257
  const resolvedRoomInfo = {
8170
8258
  ...roomInfo,
8171
- name: _nullishCoalesce(_optionalChain([roomInfo, 'optionalAccess', _10 => _10.name]), () => ( event.data.roomId))
8259
+ name: _nullishCoalesce(_optionalChain([roomInfo, 'optionalAccess', _9 => _9.name]), () => ( event.data.roomId))
8172
8260
  };
8173
8261
  const batchUsersResolver = createBatchUsersResolver({
8174
8262
  resolveUsers: options.resolveUsers,
8175
8263
  callerName
8176
8264
  });
8177
- const authorsInfoPromise = resolveAuthorsInfo({
8178
- userIds: [data.createdBy],
8179
- resolveUsers: batchUsersResolver.resolveUsers
8265
+ const batchGroupsInfoResolver = createBatchGroupsInfoResolver({
8266
+ resolveGroupsInfo: options.resolveGroupsInfo,
8267
+ callerName
8180
8268
  });
8269
+ const authorsIds = [data.createdBy];
8270
+ const authorsInfoPromise = batchUsersResolver.get(authorsIds);
8181
8271
  let textEditorNodes = [];
8182
8272
  switch (data.editor) {
8183
8273
  case "lexical": {
@@ -8195,24 +8285,24 @@ async function prepareTextMentionNotificationEmail(client, event, options, eleme
8195
8285
  break;
8196
8286
  }
8197
8287
  }
8198
- const contentPromise = convertMentionContent(
8288
+ const contentPromise = convertTextMentionContent(
8199
8289
  textEditorNodes,
8200
8290
  {
8201
- resolveUsers: batchUsersResolver.resolveUsers,
8291
+ resolveUsers: ({ userIds }) => batchUsersResolver.get(userIds),
8292
+ resolveGroupsInfo: ({ groupIds }) => batchGroupsInfoResolver.get(groupIds),
8202
8293
  elements
8203
8294
  }
8204
8295
  );
8205
8296
  await batchUsersResolver.resolve();
8297
+ await batchGroupsInfoResolver.resolve();
8206
8298
  const [authorsInfo, content] = await Promise.all([
8207
8299
  authorsInfoPromise,
8208
8300
  contentPromise
8209
8301
  ]);
8210
- const authorInfo = authorsInfo.get(data.createdBy);
8302
+ const authorInfo = getResolvedForId(data.createdBy, authorsIds, authorsInfo);
8211
8303
  return {
8212
8304
  mention: {
8213
- // TODO: When introducing new mention kinds (e.g. group mentions), this should be updated
8214
- kind: "user",
8215
- id: data.userId,
8305
+ ...data.mentionData,
8216
8306
  textMentionId: mentionId,
8217
8307
  roomId,
8218
8308
  author: {
@@ -8227,9 +8317,9 @@ async function prepareTextMentionNotificationEmail(client, event, options, eleme
8227
8317
  }
8228
8318
  var baseComponents = {
8229
8319
  Container: ({ children }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children }),
8230
- Mention: ({ element, user }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "data-mention": true, children: [
8231
- MENTION_CHARACTER,
8232
- _nullishCoalesce(_optionalChain([user, 'optionalAccess', _11 => _11.name]), () => ( element.id))
8320
+ Mention: ({ element, user, group }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "data-mention": true, children: [
8321
+ _core.MENTION_CHARACTER,
8322
+ _nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _10 => _10.name]), () => ( _optionalChain([group, 'optionalAccess', _11 => _11.name]))), () => ( element.id))
8233
8323
  ] }),
8234
8324
  Text: ({ element }) => {
8235
8325
  let children = element.text;
@@ -8310,8 +8400,8 @@ async function prepareTextMentionNotificationEmailAsHtml(client, event, options
8310
8400
  ];
8311
8401
  return content.join("\n");
8312
8402
  },
8313
- mention: ({ node, user }) => {
8314
- return _core.html`<span data-mention style="${toInlineCSSString(styles.mention)}">${MENTION_CHARACTER}${_optionalChain([user, 'optionalAccess', _12 => _12.name]) ? _core.html`${_optionalChain([user, 'optionalAccess', _13 => _13.name])}` : node.id}</span>`;
8403
+ mention: ({ node, user, group }) => {
8404
+ return _core.html`<span data-mention style="${toInlineCSSString(styles.mention)}">${_core.MENTION_CHARACTER}${_optionalChain([user, 'optionalAccess', _12 => _12.name]) ? _core.html`${_optionalChain([user, 'optionalAccess', _13 => _13.name])}` : _optionalChain([group, 'optionalAccess', _14 => _14.name]) ? _core.html`${_optionalChain([group, 'optionalAccess', _15 => _15.name])}` : node.id}</span>`;
8315
8405
  },
8316
8406
  text: ({ node }) => {
8317
8407
  let children = node.text;
@@ -8349,6 +8439,7 @@ async function prepareTextMentionNotificationEmailAsHtml(client, event, options
8349
8439
 
8350
8440
 
8351
8441
 
8442
+
8352
8443
  // src/comment-body.tsx
8353
8444
 
8354
8445
 
@@ -8358,9 +8449,10 @@ async function prepareTextMentionNotificationEmailAsHtml(client, event, options
8358
8449
 
8359
8450
 
8360
8451
  async function convertCommentBody(body, options) {
8361
- const resolvedUsers = await _core.resolveUsersInCommentBody.call(void 0,
8452
+ const { users: resolvedUsers, groups: resolvedGroupsInfo } = await _core.resolveMentionsInCommentBody.call(void 0,
8362
8453
  body,
8363
- _optionalChain([options, 'optionalAccess', _14 => _14.resolveUsers])
8454
+ _optionalChain([options, 'optionalAccess', _16 => _16.resolveUsers]),
8455
+ _optionalChain([options, 'optionalAccess', _17 => _17.resolveGroupsInfo])
8364
8456
  );
8365
8457
  const blocks = body.content.map((block, index) => {
8366
8458
  switch (block.type) {
@@ -8370,7 +8462,8 @@ async function convertCommentBody(body, options) {
8370
8462
  return options.elements.mention(
8371
8463
  {
8372
8464
  element: inline,
8373
- user: resolvedUsers.get(inline.id)
8465
+ user: inline.kind === "user" ? resolvedUsers.get(inline.id) : void 0,
8466
+ group: inline.kind === "group" ? resolvedGroupsInfo.get(inline.id) : void 0
8374
8467
  },
8375
8468
  inlineIndex
8376
8469
  );
@@ -8447,17 +8540,54 @@ var getUnreadComments = ({
8447
8540
  return c.createdAt >= notificationTriggerAt && c.createdAt <= inboxNotification.notifiedAt;
8448
8541
  });
8449
8542
  };
8543
+ async function getAllUserGroups(client, userId) {
8544
+ const groups = /* @__PURE__ */ new Map();
8545
+ let cursor = void 0;
8546
+ while (true) {
8547
+ const { nextCursor, data } = await client.getUserGroups({
8548
+ userId,
8549
+ startingAfter: cursor
8550
+ });
8551
+ for (const group of data) {
8552
+ groups.set(group.id, group);
8553
+ }
8554
+ if (!nextCursor) {
8555
+ break;
8556
+ }
8557
+ cursor = nextCursor;
8558
+ }
8559
+ return groups;
8560
+ }
8450
8561
  var getLastUnreadCommentWithMention = ({
8451
8562
  comments,
8563
+ groups,
8452
8564
  mentionedUserId
8453
8565
  }) => {
8454
- return _nullishCoalesce(Array.from(comments).reverse().filter((c) => c.userId !== mentionedUserId).find((c) => {
8455
- const mentions = _core.getMentionsFromCommentBody.call(void 0,
8456
- c.body,
8457
- (mention) => mention.kind === "user" && mention.id === mentionedUserId
8458
- );
8459
- return mentions.length > 0;
8460
- }), () => ( null));
8566
+ if (!comments.length) {
8567
+ return null;
8568
+ }
8569
+ for (let i = comments.length - 1; i >= 0; i--) {
8570
+ const comment = comments[i];
8571
+ if (comment.userId === mentionedUserId) {
8572
+ continue;
8573
+ }
8574
+ const mentions = _core.getMentionsFromCommentBody.call(void 0, comment.body);
8575
+ for (const mention of mentions) {
8576
+ if (mention.kind === "user" && mention.id === mentionedUserId) {
8577
+ return comment;
8578
+ }
8579
+ if (mention.kind === "group" && _optionalChain([mention, 'access', _18 => _18.userIds, 'optionalAccess', _19 => _19.includes, 'call', _20 => _20(mentionedUserId)])) {
8580
+ return comment;
8581
+ }
8582
+ if (mention.kind === "group" && mention.userIds === void 0) {
8583
+ const group = groups.get(mention.id);
8584
+ if (_optionalChain([group, 'optionalAccess', _21 => _21.members, 'access', _22 => _22.some, 'call', _23 => _23((member) => member.id === mentionedUserId)])) {
8585
+ return comment;
8586
+ }
8587
+ }
8588
+ }
8589
+ }
8590
+ return null;
8461
8591
  };
8462
8592
  var extractThreadNotificationData = async ({
8463
8593
  client,
@@ -8478,8 +8608,10 @@ var extractThreadNotificationData = async ({
8478
8608
  if (unreadComments.length <= 0) {
8479
8609
  return null;
8480
8610
  }
8611
+ const userGroups = await getAllUserGroups(client, userId);
8481
8612
  const lastUnreadCommentWithMention = getLastUnreadCommentWithMention({
8482
8613
  comments: unreadComments,
8614
+ groups: userGroups,
8483
8615
  mentionedUserId: userId
8484
8616
  });
8485
8617
  if (lastUnreadCommentWithMention !== null) {
@@ -8507,33 +8639,41 @@ async function prepareThreadNotificationEmail(client, event, options, elements,
8507
8639
  const roomInfo = options.resolveRoomInfo ? await options.resolveRoomInfo({ roomId: event.data.roomId }) : void 0;
8508
8640
  const resolvedRoomInfo = {
8509
8641
  ...roomInfo,
8510
- name: _nullishCoalesce(_optionalChain([roomInfo, 'optionalAccess', _15 => _15.name]), () => ( event.data.roomId))
8642
+ name: _nullishCoalesce(_optionalChain([roomInfo, 'optionalAccess', _24 => _24.name]), () => ( event.data.roomId))
8511
8643
  };
8512
8644
  const batchUsersResolver = createBatchUsersResolver({
8513
8645
  resolveUsers: options.resolveUsers,
8514
8646
  callerName
8515
8647
  });
8648
+ const batchGroupsInfoResolver = createBatchGroupsInfoResolver({
8649
+ resolveGroupsInfo: options.resolveGroupsInfo,
8650
+ callerName
8651
+ });
8516
8652
  switch (data.type) {
8517
8653
  case "unreadMention": {
8518
8654
  const { comment } = data;
8519
- const authorsInfoPromise = resolveAuthorsInfo({
8520
- userIds: [comment.userId],
8521
- resolveUsers: batchUsersResolver.resolveUsers
8522
- });
8655
+ const authorsIds = [comment.userId];
8656
+ const authorsInfoPromise = batchUsersResolver.get(authorsIds);
8523
8657
  const commentBodyPromise = convertCommentBody(comment.body, {
8524
- resolveUsers: batchUsersResolver.resolveUsers,
8658
+ resolveUsers: ({ userIds }) => batchUsersResolver.get(userIds),
8659
+ resolveGroupsInfo: ({ groupIds }) => batchGroupsInfoResolver.get(groupIds),
8525
8660
  elements
8526
8661
  });
8527
8662
  await batchUsersResolver.resolve();
8663
+ await batchGroupsInfoResolver.resolve();
8528
8664
  const [authorsInfo, commentBody] = await Promise.all([
8529
8665
  authorsInfoPromise,
8530
8666
  commentBodyPromise
8531
8667
  ]);
8532
- const authorInfo = authorsInfo.get(comment.userId);
8533
- const url = generateCommentUrl({
8534
- roomUrl: _optionalChain([roomInfo, 'optionalAccess', _16 => _16.url]),
8668
+ const authorInfo = getResolvedForId(
8669
+ comment.userId,
8670
+ authorsIds,
8671
+ authorsInfo
8672
+ );
8673
+ const url = _optionalChain([roomInfo, 'optionalAccess', _25 => _25.url]) ? generateCommentUrl({
8674
+ roomUrl: _optionalChain([roomInfo, 'optionalAccess', _26 => _26.url]),
8535
8675
  commentId: comment.id
8536
- });
8676
+ }) : void 0;
8537
8677
  return {
8538
8678
  type: "unreadMention",
8539
8679
  comment: {
@@ -8553,17 +8693,17 @@ async function prepareThreadNotificationEmail(client, event, options, elements,
8553
8693
  }
8554
8694
  case "unreadReplies": {
8555
8695
  const { comments } = data;
8556
- const authorsInfoPromise = resolveAuthorsInfo({
8557
- userIds: comments.map((c) => c.userId),
8558
- resolveUsers: batchUsersResolver.resolveUsers
8559
- });
8696
+ const authorsIds = comments.map((c) => c.userId);
8697
+ const authorsInfoPromise = batchUsersResolver.get(authorsIds);
8560
8698
  const commentBodiesPromises = comments.map(
8561
8699
  (c) => convertCommentBody(c.body, {
8562
- resolveUsers: batchUsersResolver.resolveUsers,
8700
+ resolveUsers: ({ userIds }) => batchUsersResolver.get(userIds),
8701
+ resolveGroupsInfo: ({ groupIds }) => batchGroupsInfoResolver.get(groupIds),
8563
8702
  elements
8564
8703
  })
8565
8704
  );
8566
8705
  await batchUsersResolver.resolve();
8706
+ await batchGroupsInfoResolver.resolve();
8567
8707
  const [authorsInfo, ...commentBodies] = await Promise.all([
8568
8708
  authorsInfoPromise,
8569
8709
  ...commentBodiesPromises
@@ -8571,10 +8711,14 @@ async function prepareThreadNotificationEmail(client, event, options, elements,
8571
8711
  return {
8572
8712
  type: "unreadReplies",
8573
8713
  comments: comments.map((comment, index) => {
8574
- const authorInfo = authorsInfo.get(comment.userId);
8714
+ const authorInfo = getResolvedForId(
8715
+ comment.userId,
8716
+ authorsIds,
8717
+ authorsInfo
8718
+ );
8575
8719
  const commentBody = commentBodies[index];
8576
8720
  const url = generateCommentUrl({
8577
- roomUrl: _optionalChain([roomInfo, 'optionalAccess', _17 => _17.url]),
8721
+ roomUrl: _optionalChain([roomInfo, 'optionalAccess', _27 => _27.url]),
8578
8722
  commentId: comment.id
8579
8723
  });
8580
8724
  return {
@@ -8616,12 +8760,13 @@ var baseStyles2 = {
8616
8760
  }
8617
8761
  };
8618
8762
  async function prepareThreadNotificationEmailAsHtml(client, event, options = {}) {
8619
- const styles = { ...baseStyles2, ..._optionalChain([options, 'optionalAccess', _18 => _18.styles]) };
8763
+ const styles = { ...baseStyles2, ..._optionalChain([options, 'optionalAccess', _28 => _28.styles]) };
8620
8764
  const data = await prepareThreadNotificationEmail(
8621
8765
  client,
8622
8766
  event,
8623
8767
  {
8624
8768
  resolveUsers: options.resolveUsers,
8769
+ resolveGroupsInfo: options.resolveGroupsInfo,
8625
8770
  resolveRoomInfo: options.resolveRoomInfo
8626
8771
  },
8627
8772
  {
@@ -8652,8 +8797,8 @@ async function prepareThreadNotificationEmailAsHtml(client, event, options = {})
8652
8797
  link: ({ element, href }) => {
8653
8798
  return _core.html`<a href="${href}" target="_blank" rel="noopener noreferrer" style="${toInlineCSSString(styles.link)}">${element.text ? _core.html`${element.text}` : element.url}</a>`;
8654
8799
  },
8655
- mention: ({ element, user }) => {
8656
- return _core.html`<span data-mention style="${toInlineCSSString(styles.mention)}">${MENTION_CHARACTER}${_optionalChain([user, 'optionalAccess', _19 => _19.name]) ? _core.html`${_optionalChain([user, 'optionalAccess', _20 => _20.name])}` : element.id}</span>`;
8800
+ mention: ({ element, user, group }) => {
8801
+ return _core.html`<span data-mention style="${toInlineCSSString(styles.mention)}">${_core.MENTION_CHARACTER}${_optionalChain([user, 'optionalAccess', _29 => _29.name]) ? _core.html`${_optionalChain([user, 'optionalAccess', _30 => _30.name])}` : _optionalChain([group, 'optionalAccess', _31 => _31.name]) ? _core.html`${_optionalChain([group, 'optionalAccess', _32 => _32.name])}` : element.id}</span>`;
8657
8802
  }
8658
8803
  },
8659
8804
  "prepareThreadNotificationEmailAsHtml"
@@ -8683,18 +8828,19 @@ var baseComponents2 = {
8683
8828
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children });
8684
8829
  },
8685
8830
  Link: ({ element, href }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href, target: "_blank", rel: "noopener noreferrer", children: _nullishCoalesce(element.text, () => ( element.url)) }),
8686
- Mention: ({ element, user }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "data-mention": true, children: [
8687
- MENTION_CHARACTER,
8688
- _nullishCoalesce(_optionalChain([user, 'optionalAccess', _21 => _21.name]), () => ( element.id))
8831
+ Mention: ({ element, user, group }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "data-mention": true, children: [
8832
+ _core.MENTION_CHARACTER,
8833
+ _nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _33 => _33.name]), () => ( _optionalChain([group, 'optionalAccess', _34 => _34.name]))), () => ( element.id))
8689
8834
  ] })
8690
8835
  };
8691
8836
  async function prepareThreadNotificationEmailAsReact(client, event, options = {}) {
8692
- const Components = { ...baseComponents2, ..._optionalChain([options, 'optionalAccess', _22 => _22.components]) };
8837
+ const Components = { ...baseComponents2, ..._optionalChain([options, 'optionalAccess', _35 => _35.components]) };
8693
8838
  const data = await prepareThreadNotificationEmail(
8694
8839
  client,
8695
8840
  event,
8696
8841
  {
8697
8842
  resolveUsers: options.resolveUsers,
8843
+ resolveGroupsInfo: options.resolveGroupsInfo,
8698
8844
  resolveRoomInfo: options.resolveRoomInfo
8699
8845
  },
8700
8846
  {
@@ -8715,11 +8861,12 @@ async function prepareThreadNotificationEmailAsReact(client, event, options = {}
8715
8861
  },
8716
8862
  `lb-comment-body-link-${index}`
8717
8863
  ),
8718
- mention: ({ element, user }, index) => element.id ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
8864
+ mention: ({ element, user, group }, index) => element.id ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
8719
8865
  Components.Mention,
8720
8866
  {
8721
8867
  element,
8722
- user
8868
+ user,
8869
+ group
8723
8870
  },
8724
8871
  `lb-comment-body-mention-${index}`
8725
8872
  ) : null