@liveblocks/emails 2.25.0-aiprivatebeta9 → 3.1.0-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,9 +3,15 @@ import { detectDupes } from "@liveblocks/core";
3
3
 
4
4
  // src/version.ts
5
5
  var PKG_NAME = "@liveblocks/emails";
6
- var PKG_VERSION = "2.25.0-aiprivatebeta9";
6
+ var PKG_VERSION = "3.1.0-alpha1";
7
7
  var PKG_FORMAT = "esm";
8
8
 
9
+ // src/text-mention-notification.tsx
10
+ import {
11
+ html,
12
+ htmlSafe
13
+ } from "@liveblocks/core";
14
+
9
15
  // ../../node_modules/lib0/map.js
10
16
  var create = () => /* @__PURE__ */ new Map();
11
17
  var copy = (m) => {
@@ -7693,9 +7699,6 @@ function createBatchUsersResolver({
7693
7699
  };
7694
7700
  }
7695
7701
 
7696
- // src/liveblocks-text-editor.tsx
7697
- import { html, htmlSafe } from "@liveblocks/core";
7698
-
7699
7702
  // src/lib/constants.ts
7700
7703
  var MENTION_CHARACTER = "@";
7701
7704
 
@@ -7927,8 +7930,7 @@ function findTiptapMentionNodeWithContext({
7927
7930
  };
7928
7931
  }
7929
7932
 
7930
- // src/liveblocks-text-editor.tsx
7931
- import { jsx, jsxs } from "react/jsx-runtime";
7933
+ // src/liveblocks-text-editor.ts
7932
7934
  var baseLiveblocksTextEditorTextFormat = {
7933
7935
  bold: false,
7934
7936
  italic: false,
@@ -7967,7 +7969,8 @@ var transformLexicalMentionNodeWithContext = (mentionNodeWithContext) => {
7967
7969
  } else if (node.group === "decorator" && isSerializedMentionNode(node)) {
7968
7970
  textEditorNodes.push({
7969
7971
  type: "mention",
7970
- userId: node.attributes.__userId
7972
+ kind: "user",
7973
+ id: node.attributes.__userId
7971
7974
  });
7972
7975
  }
7973
7976
  }
@@ -7975,7 +7978,8 @@ var transformLexicalMentionNodeWithContext = (mentionNodeWithContext) => {
7975
7978
  transform(before);
7976
7979
  textEditorNodes.push({
7977
7980
  type: "mention",
7978
- userId: mention.attributes.__userId
7981
+ kind: "user",
7982
+ id: mention.attributes.__userId
7979
7983
  });
7980
7984
  transform(after);
7981
7985
  return textEditorNodes;
@@ -8008,7 +8012,8 @@ var transformTiptapMentionNodeWithContext = (mentionNodeWithContext) => {
8008
8012
  } else if (isSerializedMentionNode2(node)) {
8009
8013
  textEditorNodes.push({
8010
8014
  type: "mention",
8011
- userId: node.attrs.id
8015
+ kind: "user",
8016
+ id: node.attrs.id
8012
8017
  });
8013
8018
  }
8014
8019
  }
@@ -8016,7 +8021,8 @@ var transformTiptapMentionNodeWithContext = (mentionNodeWithContext) => {
8016
8021
  transform(before);
8017
8022
  textEditorNodes.push({
8018
8023
  type: "mention",
8019
- userId: mention.attrs.id
8024
+ kind: "user",
8025
+ id: mention.attrs.id
8020
8026
  });
8021
8027
  transform(after);
8022
8028
  return textEditorNodes;
@@ -8042,8 +8048,8 @@ var resolveUsersInLiveblocksTextEditorNodes = async (nodes, resolveUsers) => {
8042
8048
  }
8043
8049
  const mentionedUserIds = /* @__PURE__ */ new Set();
8044
8050
  for (const node of nodes) {
8045
- if (node.type === "mention") {
8046
- mentionedUserIds.add(node.userId);
8051
+ if (node.type === "mention" && node.kind === "user") {
8052
+ mentionedUserIds.add(node.id);
8047
8053
  }
8048
8054
  }
8049
8055
  const userIds = Array.from(mentionedUserIds);
@@ -8058,119 +8064,35 @@ var resolveUsersInLiveblocksTextEditorNodes = async (nodes, resolveUsers) => {
8058
8064
  }
8059
8065
  return resolvedUsers;
8060
8066
  };
8061
- var baseComponents = {
8062
- Container: ({ children }) => /* @__PURE__ */ jsx("div", { children }),
8063
- Mention: ({ element, user }) => /* @__PURE__ */ jsxs("span", { "data-mention": true, children: [
8064
- MENTION_CHARACTER,
8065
- user?.name ?? element.userId
8066
- ] }),
8067
- Text: ({ element }) => {
8068
- let children = element.text;
8069
- if (element.bold) {
8070
- children = /* @__PURE__ */ jsx("strong", { children });
8071
- }
8072
- if (element.italic) {
8073
- children = /* @__PURE__ */ jsx("em", { children });
8074
- }
8075
- if (element.strikethrough) {
8076
- children = /* @__PURE__ */ jsx("s", { children });
8077
- }
8078
- if (element.code) {
8079
- children = /* @__PURE__ */ jsx("code", { children });
8080
- }
8081
- return /* @__PURE__ */ jsx("span", { children });
8082
- }
8083
- };
8084
- async function convertTextEditorNodesAsReact(nodes, options) {
8085
- const Components = {
8086
- ...baseComponents,
8087
- ...options?.components
8088
- };
8089
- const resolvedUsers = await resolveUsersInLiveblocksTextEditorNodes(
8090
- nodes,
8091
- options?.resolveUsers
8092
- );
8093
- const children = nodes.map((node, index) => {
8094
- switch (node.type) {
8095
- case "mention":
8096
- return /* @__PURE__ */ jsx(
8097
- Components.Mention,
8098
- {
8099
- element: node,
8100
- user: resolvedUsers.get(node.userId)
8101
- },
8102
- `lb-text-editor-mention-${index}-${node.userId}`
8103
- );
8104
- case "text":
8105
- return /* @__PURE__ */ jsx(
8106
- Components.Text,
8107
- {
8108
- element: node
8109
- },
8110
- `lb-text-editor-text-${index}`
8111
- );
8112
- }
8113
- });
8114
- return /* @__PURE__ */ jsx(Components.Container, { children }, "lb-text-editor-container");
8115
- }
8116
- var baseStyles = {
8117
- container: {
8118
- fontSize: "14px"
8119
- },
8120
- strong: {
8121
- fontWeight: 500
8122
- },
8123
- code: {
8124
- fontFamily: 'ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Mono", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Consolas", "Courier New", monospace',
8125
- backgroundColor: "rgba(0,0,0,0.05)",
8126
- border: "solid 1px rgba(0,0,0,0.1)",
8127
- borderRadius: "4px"
8128
- },
8129
- mention: {
8130
- color: "blue"
8131
- }
8132
- };
8133
- async function convertTextEditorNodesAsHtml(nodes, options) {
8134
- const styles = { ...baseStyles, ...options?.styles };
8067
+
8068
+ // src/mention-content.tsx
8069
+ import { assertNever } from "@liveblocks/core";
8070
+ async function convertMentionContent(nodes, options) {
8135
8071
  const resolvedUsers = await resolveUsersInLiveblocksTextEditorNodes(
8136
8072
  nodes,
8137
8073
  options?.resolveUsers
8138
8074
  );
8139
- const children = nodes.map((node) => {
8075
+ const blocks = nodes.map((node, index) => {
8140
8076
  switch (node.type) {
8141
8077
  case "mention": {
8142
- const user = resolvedUsers.get(node.userId);
8143
- return html`<span data-mention style="${toInlineCSSString(styles.mention)}">${MENTION_CHARACTER}${user?.name ? html`${user?.name}` : node.userId}</span>`;
8078
+ if (node.kind !== "user") {
8079
+ return assertNever(node.kind, "Unknown mention kind");
8080
+ }
8081
+ return options.elements.mention(
8082
+ { node, user: resolvedUsers.get(node.id) },
8083
+ index
8084
+ );
8144
8085
  }
8145
8086
  case "text": {
8146
- let children2 = node.text;
8147
- if (!children2) {
8148
- return html`${children2}`;
8149
- }
8150
- if (node.bold) {
8151
- children2 = html`<strong style="${toInlineCSSString(styles.strong)}">${children2}</strong>`;
8152
- }
8153
- if (node.italic) {
8154
- children2 = html`<em>${children2}</em>`;
8155
- }
8156
- if (node.strikethrough) {
8157
- children2 = html`<s>${children2}</s>`;
8158
- }
8159
- if (node.code) {
8160
- children2 = html`<code style="${toInlineCSSString(styles.code)}">${children2}</code>`;
8161
- }
8162
- return html`${children2}`;
8087
+ return options.elements.text({ node }, index);
8163
8088
  }
8164
8089
  }
8165
- }).join("");
8166
- const content = [
8167
- // prettier-ignore
8168
- html`<div style="${toInlineCSSString(styles.container)}">${htmlSafe(children)}</div>`
8169
- ];
8170
- return content.join("\n");
8090
+ });
8091
+ return options.elements.container({ children: blocks });
8171
8092
  }
8172
8093
 
8173
8094
  // src/text-mention-notification.tsx
8095
+ import { jsx, jsxs } from "react/jsx-runtime";
8174
8096
  var extractTextMentionNotificationData = async ({
8175
8097
  client,
8176
8098
  event
@@ -8213,7 +8135,8 @@ var extractTextMentionNotificationData = async ({
8213
8135
  editor: "lexical",
8214
8136
  mentionNodeWithContext,
8215
8137
  createdAt: mentionCreatedAt,
8216
- userId: mentionAuthorUserId
8138
+ userId,
8139
+ createdBy: mentionAuthorUserId
8217
8140
  };
8218
8141
  }
8219
8142
  case "tiptap": {
@@ -8230,26 +8153,31 @@ var extractTextMentionNotificationData = async ({
8230
8153
  editor: "tiptap",
8231
8154
  mentionNodeWithContext,
8232
8155
  createdAt: mentionCreatedAt,
8233
- userId: mentionAuthorUserId
8156
+ userId,
8157
+ createdBy: mentionAuthorUserId
8234
8158
  };
8235
8159
  }
8236
8160
  }
8237
8161
  };
8238
- var prepareTextMentionNotificationEmailBaseData = async ({
8239
- client,
8240
- event,
8241
- options = {}
8242
- }) => {
8162
+ async function prepareTextMentionNotificationEmail(client, event, options, elements, callerName) {
8243
8163
  const { roomId, mentionId } = event.data;
8244
- const roomInfo = options.resolveRoomInfo ? await options.resolveRoomInfo({ roomId }) : void 0;
8245
- const resolvedRoomInfo = {
8246
- ...roomInfo,
8247
- name: roomInfo?.name ?? roomId
8248
- };
8249
8164
  const data = await extractTextMentionNotificationData({ client, event });
8250
8165
  if (data === null) {
8251
8166
  return null;
8252
8167
  }
8168
+ const roomInfo = options.resolveRoomInfo ? await options.resolveRoomInfo({ roomId: event.data.roomId }) : void 0;
8169
+ const resolvedRoomInfo = {
8170
+ ...roomInfo,
8171
+ name: roomInfo?.name ?? event.data.roomId
8172
+ };
8173
+ const batchUsersResolver = createBatchUsersResolver({
8174
+ resolveUsers: options.resolveUsers,
8175
+ callerName
8176
+ });
8177
+ const authorsInfoPromise = resolveAuthorsInfo({
8178
+ userIds: [data.createdBy],
8179
+ resolveUsers: batchUsersResolver.resolveUsers
8180
+ });
8253
8181
  let textEditorNodes = [];
8254
8182
  switch (data.editor) {
8255
8183
  case "lexical": {
@@ -8267,113 +8195,156 @@ var prepareTextMentionNotificationEmailBaseData = async ({
8267
8195
  break;
8268
8196
  }
8269
8197
  }
8270
- return {
8271
- mention: {
8272
- id: mentionId,
8273
- roomId,
8274
- textEditorNodes,
8275
- createdAt: data.createdAt,
8276
- userId: data.userId
8277
- },
8278
- roomInfo: resolvedRoomInfo
8279
- };
8280
- };
8281
- async function prepareTextMentionNotificationEmailAsReact(client, event, options = {}) {
8282
- const data = await prepareTextMentionNotificationEmailBaseData({
8283
- client,
8284
- event,
8285
- options: {
8286
- resolveRoomInfo: options.resolveRoomInfo
8287
- }
8288
- });
8289
- if (data === null) {
8290
- return null;
8291
- }
8292
- const { mention, roomInfo } = data;
8293
- const batchUsersResolver = createBatchUsersResolver({
8294
- resolveUsers: options.resolveUsers,
8295
- callerName: "prepareTextMentionNotificationEmailAsReact"
8296
- });
8297
- const authorsInfoPromise = resolveAuthorsInfo({
8298
- userIds: [mention.userId],
8299
- resolveUsers: batchUsersResolver.resolveUsers
8300
- });
8301
- const contentPromise = convertTextEditorNodesAsReact(
8302
- mention.textEditorNodes,
8198
+ const contentPromise = convertMentionContent(
8199
+ textEditorNodes,
8303
8200
  {
8304
8201
  resolveUsers: batchUsersResolver.resolveUsers,
8305
- components: options.components
8202
+ elements
8306
8203
  }
8307
8204
  );
8308
8205
  await batchUsersResolver.resolve();
8309
- const [authorsInfo, reactContent] = await Promise.all([
8206
+ const [authorsInfo, content] = await Promise.all([
8310
8207
  authorsInfoPromise,
8311
8208
  contentPromise
8312
8209
  ]);
8313
- const authorInfo = authorsInfo.get(mention.userId);
8210
+ const authorInfo = authorsInfo.get(data.createdBy);
8314
8211
  return {
8315
8212
  mention: {
8316
- id: mention.id,
8213
+ // TODO: When introducing new mention kinds (e.g. group mentions), this should be updated
8214
+ kind: "user",
8215
+ id: data.userId,
8216
+ textMentionId: mentionId,
8217
+ roomId,
8317
8218
  author: {
8318
- id: mention.userId,
8319
- info: authorInfo ?? { name: mention.userId }
8219
+ id: data.createdBy,
8220
+ info: authorInfo ?? { name: data.createdBy }
8320
8221
  },
8321
- roomId: mention.roomId,
8322
- reactContent,
8323
- createdAt: mention.createdAt
8222
+ content,
8223
+ createdAt: data.createdAt
8324
8224
  },
8325
- roomInfo
8225
+ roomInfo: resolvedRoomInfo
8326
8226
  };
8327
8227
  }
8328
- async function prepareTextMentionNotificationEmailAsHtml(client, event, options = {}) {
8329
- const data = await prepareTextMentionNotificationEmailBaseData({
8228
+ var baseComponents = {
8229
+ Container: ({ children }) => /* @__PURE__ */ jsx("div", { children }),
8230
+ Mention: ({ element, user }) => /* @__PURE__ */ jsxs("span", { "data-mention": true, children: [
8231
+ MENTION_CHARACTER,
8232
+ user?.name ?? element.id
8233
+ ] }),
8234
+ Text: ({ element }) => {
8235
+ let children = element.text;
8236
+ if (element.bold) {
8237
+ children = /* @__PURE__ */ jsx("strong", { children });
8238
+ }
8239
+ if (element.italic) {
8240
+ children = /* @__PURE__ */ jsx("em", { children });
8241
+ }
8242
+ if (element.strikethrough) {
8243
+ children = /* @__PURE__ */ jsx("s", { children });
8244
+ }
8245
+ if (element.code) {
8246
+ children = /* @__PURE__ */ jsx("code", { children });
8247
+ }
8248
+ return /* @__PURE__ */ jsx("span", { children });
8249
+ }
8250
+ };
8251
+ async function prepareTextMentionNotificationEmailAsReact(client, event, options = {}) {
8252
+ const Components = { ...baseComponents, ...options.components };
8253
+ const data = await prepareTextMentionNotificationEmail(
8330
8254
  client,
8331
8255
  event,
8332
- options: {
8333
- resolveRoomInfo: options.resolveRoomInfo
8334
- }
8335
- });
8256
+ {
8257
+ resolveRoomInfo: options.resolveRoomInfo,
8258
+ resolveUsers: options.resolveUsers
8259
+ },
8260
+ {
8261
+ container: ({ children }) => /* @__PURE__ */ jsx(Components.Container, { children }, "lb-text-editor-container"),
8262
+ mention: ({ node, user }, index) => /* @__PURE__ */ jsx(
8263
+ Components.Mention,
8264
+ {
8265
+ element: node,
8266
+ user
8267
+ },
8268
+ `lb-text-editor-mention-${index}`
8269
+ ),
8270
+ text: ({ node }, index) => /* @__PURE__ */ jsx(Components.Text, { element: node }, `lb-text-editor-text-${index}`)
8271
+ },
8272
+ "prepareTextMentionNotificationEmailAsReact"
8273
+ );
8336
8274
  if (data === null) {
8337
8275
  return null;
8338
8276
  }
8339
- const { mention, roomInfo } = data;
8340
- const batchUsersResolver = createBatchUsersResolver({
8341
- resolveUsers: options.resolveUsers,
8342
- callerName: "prepareTextMentionNotificationEmailAsHtml"
8343
- });
8344
- const authorsInfoPromise = resolveAuthorsInfo({
8345
- userIds: [mention.userId],
8346
- resolveUsers: batchUsersResolver.resolveUsers
8347
- });
8348
- const contentPromise = convertTextEditorNodesAsHtml(mention.textEditorNodes, {
8349
- resolveUsers: batchUsersResolver.resolveUsers,
8350
- styles: options.styles
8351
- });
8352
- await batchUsersResolver.resolve();
8353
- const [authorsInfo, htmlContent] = await Promise.all([
8354
- authorsInfoPromise,
8355
- contentPromise
8356
- ]);
8357
- const authorInfo = authorsInfo.get(mention.userId);
8358
- return {
8359
- mention: {
8360
- id: mention.id,
8361
- author: {
8362
- id: mention.userId,
8363
- info: authorInfo ?? { name: mention.userId }
8277
+ return data;
8278
+ }
8279
+ var baseStyles = {
8280
+ container: {
8281
+ fontSize: "14px"
8282
+ },
8283
+ strong: {
8284
+ fontWeight: 500
8285
+ },
8286
+ code: {
8287
+ fontFamily: 'ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Mono", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Consolas", "Courier New", monospace',
8288
+ backgroundColor: "rgba(0,0,0,0.05)",
8289
+ border: "solid 1px rgba(0,0,0,0.1)",
8290
+ borderRadius: "4px"
8291
+ },
8292
+ mention: {
8293
+ color: "blue"
8294
+ }
8295
+ };
8296
+ async function prepareTextMentionNotificationEmailAsHtml(client, event, options = {}) {
8297
+ const styles = { ...baseStyles, ...options.styles };
8298
+ const data = await prepareTextMentionNotificationEmail(
8299
+ client,
8300
+ event,
8301
+ {
8302
+ resolveRoomInfo: options.resolveRoomInfo,
8303
+ resolveUsers: options.resolveUsers
8304
+ },
8305
+ {
8306
+ container: ({ children }) => {
8307
+ const content = [
8308
+ // prettier-ignore
8309
+ html`<div style="${toInlineCSSString(styles.container)}">${htmlSafe(children.join(""))}</div>`
8310
+ ];
8311
+ return content.join("\n");
8364
8312
  },
8365
- roomId: mention.roomId,
8366
- htmlContent,
8367
- createdAt: mention.createdAt
8313
+ mention: ({ node, user }) => {
8314
+ return html`<span data-mention style="${toInlineCSSString(styles.mention)}">${MENTION_CHARACTER}${user?.name ? html`${user?.name}` : node.id}</span>`;
8315
+ },
8316
+ text: ({ node }) => {
8317
+ let children = node.text;
8318
+ if (!children) {
8319
+ return html`${children}`;
8320
+ }
8321
+ if (node.bold) {
8322
+ children = html`<strong style="${toInlineCSSString(styles.strong)}">${children}</strong>`;
8323
+ }
8324
+ if (node.italic) {
8325
+ children = html`<em>${children}</em>`;
8326
+ }
8327
+ if (node.strikethrough) {
8328
+ children = html`<s>${children}</s>`;
8329
+ }
8330
+ if (node.code) {
8331
+ children = html`<code style="${toInlineCSSString(styles.code)}">${children}</code>`;
8332
+ }
8333
+ return html`${children}`;
8334
+ }
8368
8335
  },
8369
- roomInfo
8370
- };
8336
+ "prepareTextMentionNotificationEmailAsHtml"
8337
+ );
8338
+ if (data === null) {
8339
+ return null;
8340
+ }
8341
+ return data;
8371
8342
  }
8372
8343
 
8373
8344
  // src/thread-notification.tsx
8374
8345
  import {
8375
8346
  generateCommentUrl,
8376
- getMentionedIdsFromCommentBody,
8347
+ getMentionsFromCommentBody,
8377
8348
  html as html2,
8378
8349
  htmlSafe as htmlSafe2
8379
8350
  } from "@liveblocks/core";
@@ -8470,8 +8441,11 @@ var getLastUnreadCommentWithMention = ({
8470
8441
  mentionedUserId
8471
8442
  }) => {
8472
8443
  return Array.from(comments).reverse().filter((c) => c.userId !== mentionedUserId).find((c) => {
8473
- const mentionedUserIds = getMentionedIdsFromCommentBody(c.body);
8474
- return mentionedUserIds.includes(mentionedUserId);
8444
+ const mentions = getMentionsFromCommentBody(
8445
+ c.body,
8446
+ (mention) => mention.kind === "user" && mention.id === mentionedUserId
8447
+ );
8448
+ return mentions.length > 0;
8475
8449
  }) ?? null;
8476
8450
  };
8477
8451
  var extractThreadNotificationData = async ({
@@ -8667,23 +8641,7 @@ async function prepareThreadNotificationEmailAsHtml(client, event, options = {})
8667
8641
  if (data === null) {
8668
8642
  return null;
8669
8643
  }
8670
- switch (data.type) {
8671
- case "unreadMention": {
8672
- return {
8673
- ...data,
8674
- comment: { ...data.comment, htmlBody: data.comment.body }
8675
- };
8676
- }
8677
- case "unreadReplies": {
8678
- return {
8679
- ...data,
8680
- comments: data.comments.map((comment) => ({
8681
- ...comment,
8682
- htmlBody: comment.body
8683
- }))
8684
- };
8685
- }
8686
- }
8644
+ return data;
8687
8645
  }
8688
8646
  var baseComponents2 = {
8689
8647
  Container: ({ children }) => /* @__PURE__ */ jsx2("div", { children }),
@@ -8751,23 +8709,7 @@ async function prepareThreadNotificationEmailAsReact(client, event, options = {}
8751
8709
  if (data === null) {
8752
8710
  return null;
8753
8711
  }
8754
- switch (data.type) {
8755
- case "unreadMention": {
8756
- return {
8757
- ...data,
8758
- comment: { ...data.comment, reactBody: data.comment.body }
8759
- };
8760
- }
8761
- case "unreadReplies": {
8762
- return {
8763
- ...data,
8764
- comments: data.comments.map((comment) => ({
8765
- ...comment,
8766
- reactBody: comment.body
8767
- }))
8768
- };
8769
- }
8770
- }
8712
+ return data;
8771
8713
  }
8772
8714
 
8773
8715
  // src/index.ts