@liveblocks/emails 2.12.2 → 2.13.0
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 +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/version.ts","../src/thread-notification.tsx","../src/comment-body.tsx","../src/lib/css-properties.ts","../src/comment-with-body.ts","../src/lib/batch-users-resolver.ts","../src/lib/warning.ts"],"names":[],"mappings":"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","sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n CommentBodyContainerComponentProps,\n CommentBodyLinkComponentProps,\n CommentBodyMentionComponentProps,\n CommentBodyParagraphComponentProps,\n CommentBodyTextComponentProps,\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nexport type {\n CommentEmailAsHtmlData,\n CommentEmailAsReactData,\n PrepareThreadNotificationEmailAsHtmlOptions,\n PrepareThreadNotificationEmailAsReactOptions,\n ResolveRoomInfoArgs,\n ThreadNotificationEmailDataAsHtml,\n ThreadNotificationEmailDataAsReact,\n} from \"./thread-notification\";\nexport {\n prepareThreadNotificationEmailAsHtml,\n prepareThreadNotificationEmailAsReact,\n} from \"./thread-notification\";\nexport type { ResolveUsersArgs } from \"@liveblocks/core\";\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/emails\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n","import type {\n BaseRoomInfo,\n BaseUserMeta,\n CommentBody,\n CommentData,\n DRI,\n DU,\n InboxNotificationData,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n generateCommentUrl,\n getMentionedIdsFromCommentBody,\n} from \"@liveblocks/core\";\nimport type { Liveblocks, ThreadNotificationEvent } from \"@liveblocks/node\";\nimport type React from \"react\";\n\nimport type {\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nimport {\n convertCommentBodyAsHtml,\n convertCommentBodyAsReact,\n} from \"./comment-body\";\nimport type { CommentDataWithBody } from \"./comment-with-body\";\nimport { filterCommentsWithBody } from \"./comment-with-body\";\nimport { createBatchUsersResolver } from \"./lib/batch-users-resolver\";\n\n/** @internal */\nexport const getUnreadComments = ({\n comments,\n inboxNotification,\n userId,\n}: {\n comments: CommentData[];\n inboxNotification: InboxNotificationData;\n userId: string;\n}): CommentDataWithBody[] => {\n const commentsWithBody = filterCommentsWithBody(comments);\n const readAt = inboxNotification.readAt;\n\n return commentsWithBody\n .filter((c) => c.userId !== userId)\n .filter((c) =>\n readAt\n ? c.createdAt > readAt && c.createdAt <= inboxNotification.notifiedAt\n : c.createdAt <= inboxNotification.notifiedAt\n );\n};\n\n/** @internal */\nexport const getLastUnreadCommentWithMention = ({\n comments,\n mentionedUserId,\n}: {\n comments: CommentDataWithBody[];\n mentionedUserId: string;\n}): CommentDataWithBody | null => {\n return (\n Array.from(comments)\n .reverse()\n .filter((c) => c.userId !== mentionedUserId)\n .find((c) => {\n const mentionedUserIds = getMentionedIdsFromCommentBody(c.body);\n return mentionedUserIds.includes(mentionedUserId);\n }) ?? null\n );\n};\n\nexport type ThreadNotificationData =\n | { type: \"unreadMention\"; comment: CommentDataWithBody }\n | { type: \"unreadReplies\"; comments: CommentDataWithBody[] };\n\n/** @internal */\nexport const extractThreadNotificationData = async ({\n client,\n event,\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n}): Promise<ThreadNotificationData | null> => {\n const { threadId, roomId, userId, inboxNotificationId } = event.data;\n const [thread, inboxNotification] = await Promise.all([\n client.getThread({ roomId, threadId }),\n client.getInboxNotification({ inboxNotificationId, userId }),\n ]);\n\n const unreadComments = getUnreadComments({\n comments: thread.comments,\n inboxNotification,\n userId,\n });\n\n if (unreadComments.length <= 0) {\n return null;\n }\n\n const lastUnreadCommentWithMention = getLastUnreadCommentWithMention({\n comments: unreadComments,\n mentionedUserId: userId,\n });\n if (lastUnreadCommentWithMention !== null) {\n return { type: \"unreadMention\", comment: lastUnreadCommentWithMention };\n }\n\n return {\n type: \"unreadReplies\",\n comments: unreadComments,\n };\n};\n\nexport type CommentEmailBaseData = {\n id: string;\n threadId: string;\n roomId: string;\n userId: string;\n createdAt: Date;\n url?: string;\n rawBody: CommentBody;\n};\n\nexport type ResolveRoomInfoArgs = {\n /**\n * The ID of the room to resolve\n */\n roomId: string;\n};\n\ntype PrepareThreadNotificationEmailBaseDataOptions = {\n /**\n * A function that returns room info from room IDs.\n */\n resolveRoomInfo?: (\n args: ResolveRoomInfoArgs\n ) => OptionalPromise<DRI | undefined>;\n};\n\nexport type ThreadNotificationEmailBaseData = (\n | { type: \"unreadMention\"; comment: CommentEmailBaseData }\n | { type: \"unreadReplies\"; comments: CommentEmailBaseData[] }\n) & { roomInfo: DRI };\n\n/** @internal */\nexport const makeCommentEmailBaseData = ({\n roomInfo,\n comment,\n}: {\n roomInfo: BaseRoomInfo | undefined;\n comment: CommentDataWithBody;\n}): CommentEmailBaseData => {\n const url = roomInfo?.url\n ? generateCommentUrl({\n roomUrl: roomInfo?.url,\n commentId: comment.id,\n })\n : undefined;\n\n return {\n id: comment.id,\n userId: comment.userId,\n threadId: comment.threadId,\n roomId: comment.roomId,\n createdAt: comment.createdAt,\n url,\n rawBody: comment.body,\n };\n};\n\n/** @internal */\nexport const prepareThreadNotificationEmailBaseData = async ({\n client,\n event,\n options = {},\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n options?: PrepareThreadNotificationEmailBaseDataOptions;\n}): Promise<ThreadNotificationEmailBaseData | null> => {\n const { roomId } = event.data;\n\n const roomInfo = options.resolveRoomInfo\n ? await options.resolveRoomInfo({ roomId })\n : undefined;\n const resolvedRoomInfo: DRI = {\n ...roomInfo,\n name: roomInfo?.name ?? roomId,\n };\n\n const data = await extractThreadNotificationData({ client, event });\n if (data === null) {\n return null;\n }\n\n switch (data.type) {\n case \"unreadMention\":\n return {\n type: \"unreadMention\",\n comment: makeCommentEmailBaseData({\n roomInfo,\n comment: data.comment,\n }),\n roomInfo: resolvedRoomInfo,\n };\n case \"unreadReplies\": {\n return {\n type: \"unreadReplies\",\n comments: data.comments.map((comment) =>\n makeCommentEmailBaseData({ roomInfo, comment })\n ),\n roomInfo: resolvedRoomInfo,\n };\n }\n }\n};\n\n/** @internal */\nconst resolveAuthorsInfo = async <U extends BaseUserMeta>({\n comments,\n resolveUsers,\n}: {\n comments: CommentEmailBaseData[];\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n}): Promise<Map<string, U[\"info\"]>> => {\n const resolvedAuthors = new Map<string, U[\"info\"]>();\n if (!resolveUsers) {\n return resolvedAuthors;\n }\n\n const userIds = comments.map((c) => c.userId);\n const users = await resolveUsers({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n if (user) {\n resolvedAuthors.set(userId, user);\n }\n }\n\n return resolvedAuthors;\n};\n\nexport type CommentEmailAsHtmlData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n htmlBody: string;\n};\n\nexport type CommentEmailAsReactData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n reactBody: React.ReactNode;\n};\n\ntype ThreadNotificationEmailUnreadRepliesData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadReplies\";\n comments: C[];\n};\n\ntype ThreadNotificationEmailUnreadMentionsData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadMention\";\n comment: C;\n};\n\n// Note: export for testing helpers\nexport type ThreadNotificationEmailData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = (\n | ThreadNotificationEmailUnreadRepliesData<U, C>\n | ThreadNotificationEmailUnreadMentionsData<U, C>\n) & { roomInfo: DRI };\n\nexport type PrepareThreadNotificationEmailAsHtmlOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The styles used to customize the html elements in the resulting html safe string inside a comment body.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n};\n\nexport type ThreadNotificationEmailDataAsHtml = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsHtmlData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as an html safe string.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info\n * and customize comment bodies html elements styles with inline CSS.\n *\n * It returns a `ThreadNotificationEmailDataAsHtml` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsHtml } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsHtml(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * styles,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsHtml(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsHtmlOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsHtml | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsHtml\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodyPromise = convertCommentBodyAsHtml(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyHtml] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsHtml(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyHtml = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml ?? \"\",\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n\nexport type PrepareThreadNotificationEmailAsReactOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The components used to customize the resulting React nodes inside a comment body.\n * Each components has priority over the base components inherited internally defined.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n};\n\nexport type ThreadNotificationEmailDataAsReact = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsReactData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as React nodes.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info and customize comment bodies React components.\n *\n * It returns a `ThreadNotificationEmailDataAsReact` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsReact } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsReact(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * components,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsReact(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsReactOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsReact | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsReact\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodyPromise = convertCommentBodyAsReact(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyReact] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsReact(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyReact = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact ?? null,\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n","import type {\n BaseUserMeta,\n CommentBody,\n CommentBodyLink,\n CommentBodyMention,\n CommentBodyText,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n html,\n htmlSafe,\n isCommentBodyLink,\n isCommentBodyMention,\n isCommentBodyText,\n resolveUsersInCommentBody,\n stringifyCommentBody,\n toAbsoluteUrl,\n} from \"@liveblocks/core\";\nimport React from \"react\";\n\nimport type { CSSProperties } from \"./lib/css-properties\";\nimport { toInlineCSSString } from \"./lib/css-properties\";\n\nexport type CommentBodyContainerComponentProps = {\n /**\n * The blocks of the comment body\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyParagraphComponentProps = {\n /**\n * The text content of the paragraph.\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyTextComponentProps = {\n /**\n * The text element.\n */\n element: CommentBodyText;\n};\n\nexport type CommentBodyLinkComponentProps = {\n /**\n * The link element.\n */\n element: CommentBodyLink;\n\n /**\n * The absolute URL of the link.\n */\n href: string;\n};\n\nexport type CommentBodyMentionComponentProps<U extends BaseUserMeta = DU> = {\n /**\n * The mention element.\n */\n element: CommentBodyMention;\n\n /**\n * The mention's user info, if the `resolvedUsers` option was provided.\n */\n user?: U[\"info\"];\n};\n\nexport type ConvertCommentBodyAsReactComponents<U extends BaseUserMeta = DU> = {\n /**\n *\n * The component used to act as a container to wrap comment body blocks,\n */\n Container: React.ComponentType<CommentBodyContainerComponentProps>;\n /**\n * The component used to display paragraphs.\n */\n Paragraph: React.ComponentType<CommentBodyParagraphComponentProps>;\n\n /**\n * The component used to display text elements.\n */\n Text: React.ComponentType<CommentBodyTextComponentProps>;\n\n /**\n * The component used to display links.\n */\n Link: React.ComponentType<CommentBodyLinkComponentProps>;\n\n /**\n * The component used to display mentions.\n */\n Mention: React.ComponentType<CommentBodyMentionComponentProps<U>>;\n};\n\nconst baseComponents: ConvertCommentBodyAsReactComponents<BaseUserMeta> = {\n Container: ({ children }) => <div>{children}</div>,\n Paragraph: ({ children }) => <p>{children}</p>,\n Text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children: React.ReactNode = element.text;\n\n if (element.bold) {\n children = <strong>{children}</strong>;\n }\n\n if (element.italic) {\n children = <em>{children}</em>;\n }\n\n if (element.strikethrough) {\n children = <s>{children}</s>;\n }\n\n if (element.code) {\n children = <code>{children}</code>;\n }\n\n return <span>{children}</span>;\n },\n Link: ({ element, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {element.text ?? element.url}\n </a>\n ),\n Mention: ({ element, user }) => (\n <span data-mention>@{user?.name ?? element.id}</span>\n ),\n};\n\nexport type ConvertCommentBodyAsReactOptions<U extends BaseUserMeta = DU> = {\n /**\n * The components used to customize the resulting React nodes. Each components has\n * priority over the base components inherited.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n /**\n * A function that returns user info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into React elements\n */\nexport async function convertCommentBodyAsReact(\n body: CommentBody,\n options?: ConvertCommentBodyAsReactOptions<BaseUserMeta>\n): Promise<React.ReactNode> {\n const Components = {\n ...baseComponents,\n ...options?.components,\n };\n const resolvedUsers = await resolveUsersInCommentBody(\n body,\n options?.resolveUsers\n );\n\n const blocks = body.content.map((block, index) => {\n switch (block.type) {\n case \"paragraph\": {\n const children = block.children.map((inline, inlineIndex) => {\n if (isCommentBodyMention(inline)) {\n return inline.id ? (\n <Components.Mention\n key={`lb-comment-body-mention-${inlineIndex}`}\n element={inline}\n user={resolvedUsers.get(inline.id)}\n />\n ) : null;\n }\n\n if (isCommentBodyLink(inline)) {\n const href = toAbsoluteUrl(inline.url) ?? inline.url;\n return (\n <Components.Link\n key={`lb-comment-body-link-${inlineIndex}`}\n element={inline}\n href={href}\n />\n );\n }\n\n if (isCommentBodyText(inline)) {\n return (\n <Components.Text\n key={`lb-comment-body-text-${inlineIndex}`}\n element={inline}\n />\n );\n }\n\n return null;\n });\n\n return (\n <Components.Paragraph key={`lb-comment-body-paragraph-${index}`}>\n {children}\n </Components.Paragraph>\n );\n }\n default:\n console.warn(\n `Unsupported comment body block type: \"${JSON.stringify(block.type)}\"`\n );\n return null;\n }\n });\n\n return (\n <Components.Container key={\"lb-comment-body-container\"}>\n {blocks}\n </Components.Container>\n );\n}\n\nexport type ConvertCommentBodyAsHtmlStyles = {\n /**\n * The default inline CSS styles used to display paragraphs.\n */\n paragraph: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<strong />` elements.\n */\n strong: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<code />` elements.\n */\n code: CSSProperties;\n /**\n * The default inline CSS styles used to display links.\n */\n mention: CSSProperties;\n /**\n * The default inline CSS styles used to display mentions.\n */\n link: CSSProperties;\n};\n\nconst baseStyles: ConvertCommentBodyAsHtmlStyles = {\n paragraph: {\n fontSize: \"14px\",\n },\n strong: {\n fontWeight: 500,\n },\n code: {\n fontFamily:\n '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',\n backgroundColor: \"rgba(0,0,0,0.05)\",\n border: \"solid 1px rgba(0,0,0,0.1)\",\n borderRadius: \"4px\",\n },\n mention: {\n color: \"blue\",\n },\n link: {\n textDecoration: \"underline\",\n },\n};\n\nexport type ConvertCommentBodyAsHtmlOptions<U extends BaseUserMeta = DU> = {\n /**\n * The styles used to customize the html elements in the resulting html safe string.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n /**\n * A function that returns user info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into an html safe string\n * with inline css styles\n */\nexport async function convertCommentBodyAsHtml(\n body: CommentBody,\n options?: ConvertCommentBodyAsHtmlOptions<BaseUserMeta>\n): Promise<string> {\n const styles = { ...baseStyles, ...options?.styles };\n\n const htmlBody = await stringifyCommentBody(body, {\n format: \"html\",\n resolveUsers: options?.resolveUsers,\n elements: {\n // NOTE: using prettier-ignore to preserve template strings\n paragraph: ({ children }) =>\n // prettier-ignore\n children ? html`<p style=\"${toInlineCSSString(styles.paragraph)}\">${htmlSafe(children)}</p>` : children,\n text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children = element.text;\n\n if (!children) {\n return children;\n }\n\n if (element.bold) {\n // prettier-ignore\n children = html`<strong style=\"${toInlineCSSString(styles.strong)}\">${children}</strong>`;\n }\n\n if (element.italic) {\n // prettier-ignore\n children = html`<em>${children}</em>`;\n }\n\n if (element.strikethrough) {\n // prettier-ignore\n children = html`<s>${children}</s>`;\n }\n\n if (element.code) {\n // prettier-ignore\n children = html`<code style=\"${toInlineCSSString(styles.code)}\">${children}</code>`;\n }\n\n return children;\n },\n link: ({ element, href }) => {\n // prettier-ignore\n return html`<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"${toInlineCSSString(styles.link)}\">${element.text ?? element.url}</a>`;\n },\n mention: ({ element, user }) => {\n // prettier-ignore\n return html`<span data-mention style=\"${toInlineCSSString(styles.mention)}\">@${user?.name ?? element.id}</span>`;\n },\n },\n });\n\n return htmlBody;\n}\n","import type { Properties } from \"csstype\";\n\n/**\n * CSS properties object.\n * Type alias for DX purposes.\n *\n */\nexport type CSSProperties = Properties;\n\n/**\n * Vendors\n */\nconst VENDORS_PREFIXES = new RegExp(/^(webkit|moz|ms|o)-/);\n\n/**\n * CSS properties which accept numbers but are not in units of \"px\".\n * Based on: https://github.com/facebook/react/blob/bfe91fbecf183f85fc1c4f909e12a6833a247319/packages/react-dom-bindings/src/shared/isUnitlessNumber.js\n */\nconst UNITLESS_PROPERTIES = [\n \"animationIterationCount\",\n \"aspectRatio\",\n \"borderImageOutset\",\n \"borderImageSlice\",\n \"borderImageWidth\",\n \"boxFlex\",\n \"boxFlexGroup\",\n \"boxOrdinalGroup\",\n \"columnCount\",\n \"columns\",\n \"flex\",\n \"flexGrow\",\n \"flexPositive\",\n \"flexShrink\",\n \"flexNegative\",\n \"flexOrder\",\n \"gridArea\",\n \"gridRow\",\n \"gridRowEnd\",\n \"gridRowSpan\",\n \"gridRowStart\",\n \"gridColumn\",\n \"gridColumnEnd\",\n \"gridColumnSpan\",\n \"gridColumnStart\",\n \"fontWeight\",\n \"lineClamp\",\n \"lineHeight\",\n \"opacity\",\n \"order\",\n \"orphans\",\n \"scale\",\n \"tabSize\",\n \"widows\",\n \"zIndex\",\n \"zoom\",\n \"fillOpacity\",\n \"floodOpacity\",\n \"stopOpacity\",\n \"strokeDasharray\",\n \"strokeDashoffset\",\n \"strokeMiterlimit\",\n \"strokeOpacity\",\n \"strokeWidth\",\n \"MozAnimationIterationCount\",\n \"MozBoxFlex\",\n \"MozBoxFlexGroup\",\n \"MozLineClamp\",\n \"msAnimationIterationCount\",\n \"msFlex\",\n \"msZoom\",\n \"msFlexPositive\",\n \"msGridColumns\",\n \"msGridRows\",\n \"WebkitAnimationIterationCount\",\n \"WebkitBoxFlex\",\n \"WebKitBoxFlexGroup\",\n \"WebkitBoxOrdinalGroup\",\n \"WebkitColumnCount\",\n \"WebkitColumns\",\n \"WebkitFlex\",\n \"WebkitFlexGrow\",\n \"WebkitFlexPositive\",\n \"WebkitFlexShrink\",\n \"WebkitLineClamp\",\n];\n\n/**\n * Convert a `CSSProperties` style object into a inline CSS string.\n */\nexport function toInlineCSSString(styles: CSSProperties): string {\n const entries = Object.entries(styles);\n const inline = entries\n .map(([key, value]): string | null => {\n // Return an empty string if `value` is not acceptable\n if (\n value === null ||\n typeof value === \"boolean\" ||\n value === \"\" ||\n typeof value === \"undefined\"\n ) {\n return \"\";\n }\n\n // Convert key from camelCase to kebab-case\n let property = key.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n\n // Manage vendors prefixes\n if (VENDORS_PREFIXES.test(property)) {\n property = `-${property}`;\n }\n\n // Add `px` if needed for properties which aren't unitless\n if (typeof value === \"number\" && !UNITLESS_PROPERTIES.includes(key)) {\n return `${property}:${value}px;`;\n }\n\n return `${property}:${String(value).trim()};`;\n })\n .filter(Boolean)\n .join(\"\");\n\n return inline;\n}\n","import type { CommentBody, CommentData } from \"@liveblocks/core\";\n\nexport type CommentDataWithBody = Omit<CommentData, \"body\" | \"deletedAt\"> & {\n body: CommentBody;\n deletedAt?: never;\n};\n\nconst isCommentDataWithBody = (\n comment: CommentData\n): comment is CommentDataWithBody => {\n return comment.body !== undefined && comment.deletedAt === undefined;\n};\n\nexport function filterCommentsWithBody(\n comments: CommentData[]\n): CommentDataWithBody[] {\n const commentsWithBody: CommentDataWithBody[] = [];\n for (const comment of comments) {\n if (isCommentDataWithBody(comment)) {\n commentsWithBody.push(comment);\n }\n }\n return commentsWithBody;\n}\n","import type {\n BaseUserMeta,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport { Promise_withResolvers } from \"@liveblocks/core\";\n\nimport { createDevelopmentWarning } from \"./warning\";\n\ntype ResolveUserOptionalPromise<U extends BaseUserMeta> = (\n args: ResolveUsersArgs\n) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n\n/**\n * Batch calls to `resolveUsers` to one and only call.\n * It will avoid any performances issues and invocation timeouts on our customers' webhook handlers.\n *\n * This batch call will stack pending promises referring to `resolveUsers` in a map, resolve all users given in args at once\n * and then resolve pending promises all at once.\n */\nclass BatchUsersResolver<U extends BaseUserMeta> {\n private isResolved: boolean;\n private markAsResolved: () => void;\n private resolvePromise: Promise<void>;\n\n private primeResolveUsersFn: ResolveUserOptionalPromise<U> | undefined;\n private usersById: Map<string, U[\"info\"] | undefined>;\n\n private warnAsAlreadyResolved: () => void;\n\n constructor(resolveUsers: ResolveUserOptionalPromise<U> | undefined) {\n const { promise, resolve } = Promise_withResolvers<void>();\n\n this.isResolved = false;\n this.markAsResolved = resolve;\n this.resolvePromise = promise;\n\n this.primeResolveUsersFn = resolveUsers;\n this.usersById = new Map();\n\n this.warnAsAlreadyResolved = createDevelopmentWarning(\n true,\n \"Batch users resolver promise already resolved. It can only resolve once.\"\n );\n }\n\n resolveUsers = async (\n args: ResolveUsersArgs\n ): Promise<(U[\"info\"] | undefined)[] | undefined> => {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return undefined;\n }\n\n // Note: register all user Ids\n for (const userId of args.userIds) {\n this.usersById.set(userId, undefined);\n }\n\n // Note: waiting until the batch promise is resolved\n await this.resolvePromise;\n\n // Note: once the batch promise is resolved\n // we can return safely resolved users\n return args.userIds.map((userId) => this.usersById.get(userId));\n };\n\n async resolve(): Promise<void> {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return;\n }\n\n // Note: set an array of unique user ids\n const userIds = Array.from(this.usersById.keys());\n const users = await this.primeResolveUsersFn?.({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n this.usersById.set(userId, user);\n }\n\n this.isResolved = true;\n this.markAsResolved();\n }\n}\n\nexport type CreateBatchUsersResolverReturnType<U extends BaseUserMeta> = {\n resolveUsers: (\n args: ResolveUsersArgs\n ) => Promise<(U[\"info\"] | undefined)[] | undefined>;\n resolve: () => Promise<void>;\n};\n\nexport function createBatchUsersResolver<U extends BaseUserMeta = DU>({\n resolveUsers,\n callerName,\n}: {\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n callerName: string;\n}): CreateBatchUsersResolverReturnType<U> {\n const warnIfNoResolveUsers = createDevelopmentWarning(\n () => !resolveUsers,\n `Set \"resolveUsers\" option in \"${callerName}\" to specify users info`\n );\n const batchUsersResolver = new BatchUsersResolver(resolveUsers);\n\n const resolve = async (): Promise<void> => {\n warnIfNoResolveUsers();\n await batchUsersResolver.resolve();\n };\n\n return {\n resolveUsers: batchUsersResolver.resolveUsers,\n resolve,\n } as const;\n}\n","/**\n * @internal\n * Emit a warning only once if a condition is met, in development only.\n */\nexport const createDevelopmentWarning = (\n condition: boolean | (() => boolean),\n ...args: Parameters<typeof console.warn>\n) => {\n let hasWarned = false;\n\n if (process.env.NODE_ENV !== \"production\") {\n return () => {\n if (\n !hasWarned &&\n (typeof condition === \"function\" ? condition() : condition)\n ) {\n console.warn(...args);\n\n hasWarned = true;\n }\n };\n } else {\n return () => {};\n }\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/version.ts","../src/thread-notification.tsx","../src/comment-body.tsx","../src/lib/css-properties.ts","../src/comment-with-body.ts","../src/lib/batch-users-resolver.ts","../src/lib/warning.ts"],"names":[],"mappings":"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","sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n CommentBodyContainerComponentProps,\n CommentBodyLinkComponentProps,\n CommentBodyMentionComponentProps,\n CommentBodyParagraphComponentProps,\n CommentBodyTextComponentProps,\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nexport type {\n CommentEmailAsHtmlData,\n CommentEmailAsReactData,\n PrepareThreadNotificationEmailAsHtmlOptions,\n PrepareThreadNotificationEmailAsReactOptions,\n ResolveRoomInfoArgs,\n ThreadNotificationEmailDataAsHtml,\n ThreadNotificationEmailDataAsReact,\n} from \"./thread-notification\";\nexport {\n prepareThreadNotificationEmailAsHtml,\n prepareThreadNotificationEmailAsReact,\n} from \"./thread-notification\";\nexport type { ResolveUsersArgs } from \"@liveblocks/core\";\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/emails\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n","import type {\n BaseRoomInfo,\n BaseUserMeta,\n CommentBody,\n CommentData,\n DRI,\n DU,\n InboxNotificationData,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n generateCommentUrl,\n getMentionedIdsFromCommentBody,\n} from \"@liveblocks/core\";\nimport type { Liveblocks, ThreadNotificationEvent } from \"@liveblocks/node\";\nimport type React from \"react\";\n\nimport type {\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nimport {\n convertCommentBodyAsHtml,\n convertCommentBodyAsReact,\n} from \"./comment-body\";\nimport type { CommentDataWithBody } from \"./comment-with-body\";\nimport { filterCommentsWithBody } from \"./comment-with-body\";\nimport { createBatchUsersResolver } from \"./lib/batch-users-resolver\";\n\n/** @internal */\nexport const getUnreadComments = ({\n comments,\n inboxNotification,\n userId,\n}: {\n comments: CommentData[];\n inboxNotification: InboxNotificationData;\n userId: string;\n}): CommentDataWithBody[] => {\n const commentsWithBody = filterCommentsWithBody(comments);\n const readAt = inboxNotification.readAt;\n\n return commentsWithBody\n .filter((c) => c.userId !== userId)\n .filter((c) =>\n readAt\n ? c.createdAt > readAt && c.createdAt <= inboxNotification.notifiedAt\n : c.createdAt <= inboxNotification.notifiedAt\n );\n};\n\n/** @internal */\nexport const getLastUnreadCommentWithMention = ({\n comments,\n mentionedUserId,\n}: {\n comments: CommentDataWithBody[];\n mentionedUserId: string;\n}): CommentDataWithBody | null => {\n return (\n Array.from(comments)\n .reverse()\n .filter((c) => c.userId !== mentionedUserId)\n .find((c) => {\n const mentionedUserIds = getMentionedIdsFromCommentBody(c.body);\n return mentionedUserIds.includes(mentionedUserId);\n }) ?? null\n );\n};\n\nexport type ThreadNotificationData =\n | { type: \"unreadMention\"; comment: CommentDataWithBody }\n | { type: \"unreadReplies\"; comments: CommentDataWithBody[] };\n\n/** @internal */\nexport const extractThreadNotificationData = async ({\n client,\n event,\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n}): Promise<ThreadNotificationData | null> => {\n const { threadId, roomId, userId, inboxNotificationId } = event.data;\n const [thread, inboxNotification] = await Promise.all([\n client.getThread({ roomId, threadId }),\n client.getInboxNotification({ inboxNotificationId, userId }),\n ]);\n\n const unreadComments = getUnreadComments({\n comments: thread.comments,\n inboxNotification,\n userId,\n });\n\n if (unreadComments.length <= 0) {\n return null;\n }\n\n const lastUnreadCommentWithMention = getLastUnreadCommentWithMention({\n comments: unreadComments,\n mentionedUserId: userId,\n });\n if (lastUnreadCommentWithMention !== null) {\n return { type: \"unreadMention\", comment: lastUnreadCommentWithMention };\n }\n\n return {\n type: \"unreadReplies\",\n comments: unreadComments,\n };\n};\n\nexport type CommentEmailBaseData = {\n id: string;\n threadId: string;\n roomId: string;\n userId: string;\n createdAt: Date;\n url?: string;\n rawBody: CommentBody;\n};\n\nexport type ResolveRoomInfoArgs = {\n /**\n * The ID of the room to resolve\n */\n roomId: string;\n};\n\ntype PrepareThreadNotificationEmailBaseDataOptions = {\n /**\n * A function that returns room info from room IDs.\n */\n resolveRoomInfo?: (\n args: ResolveRoomInfoArgs\n ) => OptionalPromise<DRI | undefined>;\n};\n\nexport type ThreadNotificationEmailBaseData = (\n | { type: \"unreadMention\"; comment: CommentEmailBaseData }\n | { type: \"unreadReplies\"; comments: CommentEmailBaseData[] }\n) & { roomInfo: DRI };\n\n/** @internal */\nexport const makeCommentEmailBaseData = ({\n roomInfo,\n comment,\n}: {\n roomInfo: BaseRoomInfo | undefined;\n comment: CommentDataWithBody;\n}): CommentEmailBaseData => {\n const url = roomInfo?.url\n ? generateCommentUrl({\n roomUrl: roomInfo?.url,\n commentId: comment.id,\n })\n : undefined;\n\n return {\n id: comment.id,\n userId: comment.userId,\n threadId: comment.threadId,\n roomId: comment.roomId,\n createdAt: comment.createdAt,\n url,\n rawBody: comment.body,\n };\n};\n\n/** @internal */\nexport const prepareThreadNotificationEmailBaseData = async ({\n client,\n event,\n options = {},\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n options?: PrepareThreadNotificationEmailBaseDataOptions;\n}): Promise<ThreadNotificationEmailBaseData | null> => {\n const { roomId } = event.data;\n\n const roomInfo = options.resolveRoomInfo\n ? await options.resolveRoomInfo({ roomId })\n : undefined;\n const resolvedRoomInfo: DRI = {\n ...roomInfo,\n name: roomInfo?.name ?? roomId,\n };\n\n const data = await extractThreadNotificationData({ client, event });\n if (data === null) {\n return null;\n }\n\n switch (data.type) {\n case \"unreadMention\":\n return {\n type: \"unreadMention\",\n comment: makeCommentEmailBaseData({\n roomInfo,\n comment: data.comment,\n }),\n roomInfo: resolvedRoomInfo,\n };\n case \"unreadReplies\": {\n return {\n type: \"unreadReplies\",\n comments: data.comments.map((comment) =>\n makeCommentEmailBaseData({ roomInfo, comment })\n ),\n roomInfo: resolvedRoomInfo,\n };\n }\n }\n};\n\n/** @internal */\nconst resolveAuthorsInfo = async <U extends BaseUserMeta>({\n comments,\n resolveUsers,\n}: {\n comments: CommentEmailBaseData[];\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n}): Promise<Map<string, U[\"info\"]>> => {\n const resolvedAuthors = new Map<string, U[\"info\"]>();\n if (!resolveUsers) {\n return resolvedAuthors;\n }\n\n const userIds = comments.map((c) => c.userId);\n const users = await resolveUsers({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n if (user) {\n resolvedAuthors.set(userId, user);\n }\n }\n\n return resolvedAuthors;\n};\n\nexport type CommentEmailAsHtmlData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n htmlBody: string;\n};\n\nexport type CommentEmailAsReactData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n reactBody: React.ReactNode;\n};\n\ntype ThreadNotificationEmailUnreadRepliesData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadReplies\";\n comments: C[];\n};\n\ntype ThreadNotificationEmailUnreadMentionsData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadMention\";\n comment: C;\n};\n\n// Note: export for testing helpers\nexport type ThreadNotificationEmailData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = (\n | ThreadNotificationEmailUnreadRepliesData<U, C>\n | ThreadNotificationEmailUnreadMentionsData<U, C>\n) & { roomInfo: DRI };\n\nexport type PrepareThreadNotificationEmailAsHtmlOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The styles used to customize the html elements in the resulting html safe string inside a comment body.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n};\n\nexport type ThreadNotificationEmailDataAsHtml = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsHtmlData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as an html safe string.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info\n * and customize comment bodies html elements styles with inline CSS.\n *\n * It returns a `ThreadNotificationEmailDataAsHtml` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsHtml } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsHtml(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * styles,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsHtml(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsHtmlOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsHtml | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsHtml\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodyPromise = convertCommentBodyAsHtml(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyHtml] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsHtml(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyHtml = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml ?? \"\",\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n\nexport type PrepareThreadNotificationEmailAsReactOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The components used to customize the resulting React nodes inside a comment body.\n * Each components has priority over the base components inherited internally defined.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n};\n\nexport type ThreadNotificationEmailDataAsReact = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsReactData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as React nodes.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info and customize comment bodies React components.\n *\n * It returns a `ThreadNotificationEmailDataAsReact` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsReact } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsReact(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * components,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsReact(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsReactOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsReact | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsReact\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodyPromise = convertCommentBodyAsReact(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyReact] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsReact(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyReact = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact ?? null,\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n","import type {\n BaseUserMeta,\n CommentBody,\n CommentBodyLink,\n CommentBodyMention,\n CommentBodyText,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n html,\n htmlSafe,\n isCommentBodyLink,\n isCommentBodyMention,\n isCommentBodyText,\n resolveUsersInCommentBody,\n stringifyCommentBody,\n toAbsoluteUrl,\n} from \"@liveblocks/core\";\nimport React from \"react\";\n\nimport type { CSSProperties } from \"./lib/css-properties\";\nimport { toInlineCSSString } from \"./lib/css-properties\";\n\nexport type CommentBodyContainerComponentProps = {\n /**\n * The blocks of the comment body\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyParagraphComponentProps = {\n /**\n * The text content of the paragraph.\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyTextComponentProps = {\n /**\n * The text element.\n */\n element: CommentBodyText;\n};\n\nexport type CommentBodyLinkComponentProps = {\n /**\n * The link element.\n */\n element: CommentBodyLink;\n\n /**\n * The absolute URL of the link.\n */\n href: string;\n};\n\nexport type CommentBodyMentionComponentProps<U extends BaseUserMeta = DU> = {\n /**\n * The mention element.\n */\n element: CommentBodyMention;\n\n /**\n * The mention's user info, if the `resolvedUsers` option was provided.\n */\n user?: U[\"info\"];\n};\n\nexport type ConvertCommentBodyAsReactComponents<U extends BaseUserMeta = DU> = {\n /**\n *\n * The component used to act as a container to wrap comment body blocks,\n */\n Container: React.ComponentType<CommentBodyContainerComponentProps>;\n /**\n * The component used to display paragraphs.\n */\n Paragraph: React.ComponentType<CommentBodyParagraphComponentProps>;\n\n /**\n * The component used to display text elements.\n */\n Text: React.ComponentType<CommentBodyTextComponentProps>;\n\n /**\n * The component used to display links.\n */\n Link: React.ComponentType<CommentBodyLinkComponentProps>;\n\n /**\n * The component used to display mentions.\n */\n Mention: React.ComponentType<CommentBodyMentionComponentProps<U>>;\n};\n\nconst baseComponents: ConvertCommentBodyAsReactComponents<BaseUserMeta> = {\n Container: ({ children }) => <div>{children}</div>,\n Paragraph: ({ children }) => <p>{children}</p>,\n Text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children: React.ReactNode = element.text;\n\n if (element.bold) {\n children = <strong>{children}</strong>;\n }\n\n if (element.italic) {\n children = <em>{children}</em>;\n }\n\n if (element.strikethrough) {\n children = <s>{children}</s>;\n }\n\n if (element.code) {\n children = <code>{children}</code>;\n }\n\n return <span>{children}</span>;\n },\n Link: ({ element, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {element.text ?? element.url}\n </a>\n ),\n Mention: ({ element, user }) => (\n <span data-mention>@{user?.name ?? element.id}</span>\n ),\n};\n\nexport type ConvertCommentBodyAsReactOptions<U extends BaseUserMeta = DU> = {\n /**\n * The components used to customize the resulting React nodes. Each components has\n * priority over the base components inherited.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n /**\n * A function that returns user info from user IDs.\n * You should return a list of user objects of the same size, in the same order.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into React elements\n */\nexport async function convertCommentBodyAsReact(\n body: CommentBody,\n options?: ConvertCommentBodyAsReactOptions<BaseUserMeta>\n): Promise<React.ReactNode> {\n const Components = {\n ...baseComponents,\n ...options?.components,\n };\n const resolvedUsers = await resolveUsersInCommentBody(\n body,\n options?.resolveUsers\n );\n\n const blocks = body.content.map((block, index) => {\n switch (block.type) {\n case \"paragraph\": {\n const children = block.children.map((inline, inlineIndex) => {\n if (isCommentBodyMention(inline)) {\n return inline.id ? (\n <Components.Mention\n key={`lb-comment-body-mention-${inlineIndex}`}\n element={inline}\n user={resolvedUsers.get(inline.id)}\n />\n ) : null;\n }\n\n if (isCommentBodyLink(inline)) {\n const href = toAbsoluteUrl(inline.url) ?? inline.url;\n return (\n <Components.Link\n key={`lb-comment-body-link-${inlineIndex}`}\n element={inline}\n href={href}\n />\n );\n }\n\n if (isCommentBodyText(inline)) {\n return (\n <Components.Text\n key={`lb-comment-body-text-${inlineIndex}`}\n element={inline}\n />\n );\n }\n\n return null;\n });\n\n return (\n <Components.Paragraph key={`lb-comment-body-paragraph-${index}`}>\n {children}\n </Components.Paragraph>\n );\n }\n default:\n console.warn(\n `Unsupported comment body block type: \"${JSON.stringify(block.type)}\"`\n );\n return null;\n }\n });\n\n return (\n <Components.Container key={\"lb-comment-body-container\"}>\n {blocks}\n </Components.Container>\n );\n}\n\nexport type ConvertCommentBodyAsHtmlStyles = {\n /**\n * The default inline CSS styles used to display paragraphs.\n */\n paragraph: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<strong />` elements.\n */\n strong: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<code />` elements.\n */\n code: CSSProperties;\n /**\n * The default inline CSS styles used to display links.\n */\n mention: CSSProperties;\n /**\n * The default inline CSS styles used to display mentions.\n */\n link: CSSProperties;\n};\n\nconst baseStyles: ConvertCommentBodyAsHtmlStyles = {\n paragraph: {\n fontSize: \"14px\",\n },\n strong: {\n fontWeight: 500,\n },\n code: {\n fontFamily:\n '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',\n backgroundColor: \"rgba(0,0,0,0.05)\",\n border: \"solid 1px rgba(0,0,0,0.1)\",\n borderRadius: \"4px\",\n },\n mention: {\n color: \"blue\",\n },\n link: {\n textDecoration: \"underline\",\n },\n};\n\nexport type ConvertCommentBodyAsHtmlOptions<U extends BaseUserMeta = DU> = {\n /**\n * The styles used to customize the html elements in the resulting html safe string.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n /**\n * A function that returns user info from user IDs.\n * You should return a list of user objects of the same size, in the same order.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into an html safe string\n * with inline css styles\n */\nexport async function convertCommentBodyAsHtml(\n body: CommentBody,\n options?: ConvertCommentBodyAsHtmlOptions<BaseUserMeta>\n): Promise<string> {\n const styles = { ...baseStyles, ...options?.styles };\n\n const htmlBody = await stringifyCommentBody(body, {\n format: \"html\",\n resolveUsers: options?.resolveUsers,\n elements: {\n // NOTE: using prettier-ignore to preserve template strings\n paragraph: ({ children }) =>\n // prettier-ignore\n children ? html`<p style=\"${toInlineCSSString(styles.paragraph)}\">${htmlSafe(children)}</p>` : children,\n text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children = element.text;\n\n if (!children) {\n return children;\n }\n\n if (element.bold) {\n // prettier-ignore\n children = html`<strong style=\"${toInlineCSSString(styles.strong)}\">${children}</strong>`;\n }\n\n if (element.italic) {\n // prettier-ignore\n children = html`<em>${children}</em>`;\n }\n\n if (element.strikethrough) {\n // prettier-ignore\n children = html`<s>${children}</s>`;\n }\n\n if (element.code) {\n // prettier-ignore\n children = html`<code style=\"${toInlineCSSString(styles.code)}\">${children}</code>`;\n }\n\n return children;\n },\n link: ({ element, href }) => {\n // prettier-ignore\n return html`<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"${toInlineCSSString(styles.link)}\">${element.text ?? element.url}</a>`;\n },\n mention: ({ element, user }) => {\n // prettier-ignore\n return html`<span data-mention style=\"${toInlineCSSString(styles.mention)}\">@${user?.name ?? element.id}</span>`;\n },\n },\n });\n\n return htmlBody;\n}\n","import type { Properties } from \"csstype\";\n\n/**\n * CSS properties object.\n * Type alias for DX purposes.\n *\n */\nexport type CSSProperties = Properties;\n\n/**\n * Vendors\n */\nconst VENDORS_PREFIXES = new RegExp(/^(webkit|moz|ms|o)-/);\n\n/**\n * CSS properties which accept numbers but are not in units of \"px\".\n * Based on: https://github.com/facebook/react/blob/bfe91fbecf183f85fc1c4f909e12a6833a247319/packages/react-dom-bindings/src/shared/isUnitlessNumber.js\n */\nconst UNITLESS_PROPERTIES = [\n \"animationIterationCount\",\n \"aspectRatio\",\n \"borderImageOutset\",\n \"borderImageSlice\",\n \"borderImageWidth\",\n \"boxFlex\",\n \"boxFlexGroup\",\n \"boxOrdinalGroup\",\n \"columnCount\",\n \"columns\",\n \"flex\",\n \"flexGrow\",\n \"flexPositive\",\n \"flexShrink\",\n \"flexNegative\",\n \"flexOrder\",\n \"gridArea\",\n \"gridRow\",\n \"gridRowEnd\",\n \"gridRowSpan\",\n \"gridRowStart\",\n \"gridColumn\",\n \"gridColumnEnd\",\n \"gridColumnSpan\",\n \"gridColumnStart\",\n \"fontWeight\",\n \"lineClamp\",\n \"lineHeight\",\n \"opacity\",\n \"order\",\n \"orphans\",\n \"scale\",\n \"tabSize\",\n \"widows\",\n \"zIndex\",\n \"zoom\",\n \"fillOpacity\",\n \"floodOpacity\",\n \"stopOpacity\",\n \"strokeDasharray\",\n \"strokeDashoffset\",\n \"strokeMiterlimit\",\n \"strokeOpacity\",\n \"strokeWidth\",\n \"MozAnimationIterationCount\",\n \"MozBoxFlex\",\n \"MozBoxFlexGroup\",\n \"MozLineClamp\",\n \"msAnimationIterationCount\",\n \"msFlex\",\n \"msZoom\",\n \"msFlexPositive\",\n \"msGridColumns\",\n \"msGridRows\",\n \"WebkitAnimationIterationCount\",\n \"WebkitBoxFlex\",\n \"WebKitBoxFlexGroup\",\n \"WebkitBoxOrdinalGroup\",\n \"WebkitColumnCount\",\n \"WebkitColumns\",\n \"WebkitFlex\",\n \"WebkitFlexGrow\",\n \"WebkitFlexPositive\",\n \"WebkitFlexShrink\",\n \"WebkitLineClamp\",\n];\n\n/**\n * Convert a `CSSProperties` style object into a inline CSS string.\n */\nexport function toInlineCSSString(styles: CSSProperties): string {\n const entries = Object.entries(styles);\n const inline = entries\n .map(([key, value]): string | null => {\n // Return an empty string if `value` is not acceptable\n if (\n value === null ||\n typeof value === \"boolean\" ||\n value === \"\" ||\n typeof value === \"undefined\"\n ) {\n return \"\";\n }\n\n // Convert key from camelCase to kebab-case\n let property = key.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n\n // Manage vendors prefixes\n if (VENDORS_PREFIXES.test(property)) {\n property = `-${property}`;\n }\n\n // Add `px` if needed for properties which aren't unitless\n if (typeof value === \"number\" && !UNITLESS_PROPERTIES.includes(key)) {\n return `${property}:${value}px;`;\n }\n\n return `${property}:${String(value).trim()};`;\n })\n .filter(Boolean)\n .join(\"\");\n\n return inline;\n}\n","import type { CommentBody, CommentData } from \"@liveblocks/core\";\n\nexport type CommentDataWithBody = Omit<CommentData, \"body\" | \"deletedAt\"> & {\n body: CommentBody;\n deletedAt?: never;\n};\n\nconst isCommentDataWithBody = (\n comment: CommentData\n): comment is CommentDataWithBody => {\n return comment.body !== undefined && comment.deletedAt === undefined;\n};\n\nexport function filterCommentsWithBody(\n comments: CommentData[]\n): CommentDataWithBody[] {\n const commentsWithBody: CommentDataWithBody[] = [];\n for (const comment of comments) {\n if (isCommentDataWithBody(comment)) {\n commentsWithBody.push(comment);\n }\n }\n return commentsWithBody;\n}\n","import type {\n BaseUserMeta,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport { Promise_withResolvers } from \"@liveblocks/core\";\n\nimport { createDevelopmentWarning } from \"./warning\";\n\ntype ResolveUserOptionalPromise<U extends BaseUserMeta> = (\n args: ResolveUsersArgs\n) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n\n/**\n * Batch calls to `resolveUsers` to one and only call.\n * It will avoid any performances issues and invocation timeouts on our customers' webhook handlers.\n *\n * This batch call will stack pending promises referring to `resolveUsers` in a map, resolve all users given in args at once\n * and then resolve pending promises all at once.\n */\nclass BatchUsersResolver<U extends BaseUserMeta> {\n private isResolved: boolean;\n private markAsResolved: () => void;\n private resolvePromise: Promise<void>;\n\n private primeResolveUsersFn: ResolveUserOptionalPromise<U> | undefined;\n private usersById: Map<string, U[\"info\"] | undefined>;\n\n private warnAsAlreadyResolved: () => void;\n\n constructor(resolveUsers: ResolveUserOptionalPromise<U> | undefined) {\n const { promise, resolve } = Promise_withResolvers<void>();\n\n this.isResolved = false;\n this.markAsResolved = resolve;\n this.resolvePromise = promise;\n\n this.primeResolveUsersFn = resolveUsers;\n this.usersById = new Map();\n\n this.warnAsAlreadyResolved = createDevelopmentWarning(\n true,\n \"Batch users resolver promise already resolved. It can only resolve once.\"\n );\n }\n\n resolveUsers = async (\n args: ResolveUsersArgs\n ): Promise<(U[\"info\"] | undefined)[] | undefined> => {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return undefined;\n }\n\n // Note: register all user Ids\n for (const userId of args.userIds) {\n this.usersById.set(userId, undefined);\n }\n\n // Note: waiting until the batch promise is resolved\n await this.resolvePromise;\n\n // Note: once the batch promise is resolved\n // we can return safely resolved users\n return args.userIds.map((userId) => this.usersById.get(userId));\n };\n\n async resolve(): Promise<void> {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return;\n }\n\n // Note: set an array of unique user ids\n const userIds = Array.from(this.usersById.keys());\n const users = await this.primeResolveUsersFn?.({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n this.usersById.set(userId, user);\n }\n\n this.isResolved = true;\n this.markAsResolved();\n }\n}\n\nexport type CreateBatchUsersResolverReturnType<U extends BaseUserMeta> = {\n resolveUsers: (\n args: ResolveUsersArgs\n ) => Promise<(U[\"info\"] | undefined)[] | undefined>;\n resolve: () => Promise<void>;\n};\n\nexport function createBatchUsersResolver<U extends BaseUserMeta = DU>({\n resolveUsers,\n callerName,\n}: {\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n callerName: string;\n}): CreateBatchUsersResolverReturnType<U> {\n const warnIfNoResolveUsers = createDevelopmentWarning(\n () => !resolveUsers,\n `Set \"resolveUsers\" option in \"${callerName}\" to specify users info`\n );\n const batchUsersResolver = new BatchUsersResolver(resolveUsers);\n\n const resolve = async (): Promise<void> => {\n warnIfNoResolveUsers();\n await batchUsersResolver.resolve();\n };\n\n return {\n resolveUsers: batchUsersResolver.resolveUsers,\n resolve,\n } as const;\n}\n","/**\n * @internal\n * Emit a warning only once if a condition is met, in development only.\n */\nexport const createDevelopmentWarning = (\n condition: boolean | (() => boolean),\n ...args: Parameters<typeof console.warn>\n) => {\n let hasWarned = false;\n\n if (process.env.NODE_ENV !== \"production\") {\n return () => {\n if (\n !hasWarned &&\n (typeof condition === \"function\" ? condition() : condition)\n ) {\n console.warn(...args);\n\n hasWarned = true;\n }\n };\n } else {\n return () => {};\n }\n};\n"]}
|
package/dist/index.mjs
CHANGED
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/version.ts","../src/thread-notification.tsx","../src/comment-body.tsx","../src/lib/css-properties.ts","../src/comment-with-body.ts","../src/lib/batch-users-resolver.ts","../src/lib/warning.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n CommentBodyContainerComponentProps,\n CommentBodyLinkComponentProps,\n CommentBodyMentionComponentProps,\n CommentBodyParagraphComponentProps,\n CommentBodyTextComponentProps,\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nexport type {\n CommentEmailAsHtmlData,\n CommentEmailAsReactData,\n PrepareThreadNotificationEmailAsHtmlOptions,\n PrepareThreadNotificationEmailAsReactOptions,\n ResolveRoomInfoArgs,\n ThreadNotificationEmailDataAsHtml,\n ThreadNotificationEmailDataAsReact,\n} from \"./thread-notification\";\nexport {\n prepareThreadNotificationEmailAsHtml,\n prepareThreadNotificationEmailAsReact,\n} from \"./thread-notification\";\nexport type { ResolveUsersArgs } from \"@liveblocks/core\";\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/emails\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n","import type {\n BaseRoomInfo,\n BaseUserMeta,\n CommentBody,\n CommentData,\n DRI,\n DU,\n InboxNotificationData,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n generateCommentUrl,\n getMentionedIdsFromCommentBody,\n} from \"@liveblocks/core\";\nimport type { Liveblocks, ThreadNotificationEvent } from \"@liveblocks/node\";\nimport type React from \"react\";\n\nimport type {\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nimport {\n convertCommentBodyAsHtml,\n convertCommentBodyAsReact,\n} from \"./comment-body\";\nimport type { CommentDataWithBody } from \"./comment-with-body\";\nimport { filterCommentsWithBody } from \"./comment-with-body\";\nimport { createBatchUsersResolver } from \"./lib/batch-users-resolver\";\n\n/** @internal */\nexport const getUnreadComments = ({\n comments,\n inboxNotification,\n userId,\n}: {\n comments: CommentData[];\n inboxNotification: InboxNotificationData;\n userId: string;\n}): CommentDataWithBody[] => {\n const commentsWithBody = filterCommentsWithBody(comments);\n const readAt = inboxNotification.readAt;\n\n return commentsWithBody\n .filter((c) => c.userId !== userId)\n .filter((c) =>\n readAt\n ? c.createdAt > readAt && c.createdAt <= inboxNotification.notifiedAt\n : c.createdAt <= inboxNotification.notifiedAt\n );\n};\n\n/** @internal */\nexport const getLastUnreadCommentWithMention = ({\n comments,\n mentionedUserId,\n}: {\n comments: CommentDataWithBody[];\n mentionedUserId: string;\n}): CommentDataWithBody | null => {\n return (\n Array.from(comments)\n .reverse()\n .filter((c) => c.userId !== mentionedUserId)\n .find((c) => {\n const mentionedUserIds = getMentionedIdsFromCommentBody(c.body);\n return mentionedUserIds.includes(mentionedUserId);\n }) ?? null\n );\n};\n\nexport type ThreadNotificationData =\n | { type: \"unreadMention\"; comment: CommentDataWithBody }\n | { type: \"unreadReplies\"; comments: CommentDataWithBody[] };\n\n/** @internal */\nexport const extractThreadNotificationData = async ({\n client,\n event,\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n}): Promise<ThreadNotificationData | null> => {\n const { threadId, roomId, userId, inboxNotificationId } = event.data;\n const [thread, inboxNotification] = await Promise.all([\n client.getThread({ roomId, threadId }),\n client.getInboxNotification({ inboxNotificationId, userId }),\n ]);\n\n const unreadComments = getUnreadComments({\n comments: thread.comments,\n inboxNotification,\n userId,\n });\n\n if (unreadComments.length <= 0) {\n return null;\n }\n\n const lastUnreadCommentWithMention = getLastUnreadCommentWithMention({\n comments: unreadComments,\n mentionedUserId: userId,\n });\n if (lastUnreadCommentWithMention !== null) {\n return { type: \"unreadMention\", comment: lastUnreadCommentWithMention };\n }\n\n return {\n type: \"unreadReplies\",\n comments: unreadComments,\n };\n};\n\nexport type CommentEmailBaseData = {\n id: string;\n threadId: string;\n roomId: string;\n userId: string;\n createdAt: Date;\n url?: string;\n rawBody: CommentBody;\n};\n\nexport type ResolveRoomInfoArgs = {\n /**\n * The ID of the room to resolve\n */\n roomId: string;\n};\n\ntype PrepareThreadNotificationEmailBaseDataOptions = {\n /**\n * A function that returns room info from room IDs.\n */\n resolveRoomInfo?: (\n args: ResolveRoomInfoArgs\n ) => OptionalPromise<DRI | undefined>;\n};\n\nexport type ThreadNotificationEmailBaseData = (\n | { type: \"unreadMention\"; comment: CommentEmailBaseData }\n | { type: \"unreadReplies\"; comments: CommentEmailBaseData[] }\n) & { roomInfo: DRI };\n\n/** @internal */\nexport const makeCommentEmailBaseData = ({\n roomInfo,\n comment,\n}: {\n roomInfo: BaseRoomInfo | undefined;\n comment: CommentDataWithBody;\n}): CommentEmailBaseData => {\n const url = roomInfo?.url\n ? generateCommentUrl({\n roomUrl: roomInfo?.url,\n commentId: comment.id,\n })\n : undefined;\n\n return {\n id: comment.id,\n userId: comment.userId,\n threadId: comment.threadId,\n roomId: comment.roomId,\n createdAt: comment.createdAt,\n url,\n rawBody: comment.body,\n };\n};\n\n/** @internal */\nexport const prepareThreadNotificationEmailBaseData = async ({\n client,\n event,\n options = {},\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n options?: PrepareThreadNotificationEmailBaseDataOptions;\n}): Promise<ThreadNotificationEmailBaseData | null> => {\n const { roomId } = event.data;\n\n const roomInfo = options.resolveRoomInfo\n ? await options.resolveRoomInfo({ roomId })\n : undefined;\n const resolvedRoomInfo: DRI = {\n ...roomInfo,\n name: roomInfo?.name ?? roomId,\n };\n\n const data = await extractThreadNotificationData({ client, event });\n if (data === null) {\n return null;\n }\n\n switch (data.type) {\n case \"unreadMention\":\n return {\n type: \"unreadMention\",\n comment: makeCommentEmailBaseData({\n roomInfo,\n comment: data.comment,\n }),\n roomInfo: resolvedRoomInfo,\n };\n case \"unreadReplies\": {\n return {\n type: \"unreadReplies\",\n comments: data.comments.map((comment) =>\n makeCommentEmailBaseData({ roomInfo, comment })\n ),\n roomInfo: resolvedRoomInfo,\n };\n }\n }\n};\n\n/** @internal */\nconst resolveAuthorsInfo = async <U extends BaseUserMeta>({\n comments,\n resolveUsers,\n}: {\n comments: CommentEmailBaseData[];\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n}): Promise<Map<string, U[\"info\"]>> => {\n const resolvedAuthors = new Map<string, U[\"info\"]>();\n if (!resolveUsers) {\n return resolvedAuthors;\n }\n\n const userIds = comments.map((c) => c.userId);\n const users = await resolveUsers({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n if (user) {\n resolvedAuthors.set(userId, user);\n }\n }\n\n return resolvedAuthors;\n};\n\nexport type CommentEmailAsHtmlData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n htmlBody: string;\n};\n\nexport type CommentEmailAsReactData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n reactBody: React.ReactNode;\n};\n\ntype ThreadNotificationEmailUnreadRepliesData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadReplies\";\n comments: C[];\n};\n\ntype ThreadNotificationEmailUnreadMentionsData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadMention\";\n comment: C;\n};\n\n// Note: export for testing helpers\nexport type ThreadNotificationEmailData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = (\n | ThreadNotificationEmailUnreadRepliesData<U, C>\n | ThreadNotificationEmailUnreadMentionsData<U, C>\n) & { roomInfo: DRI };\n\nexport type PrepareThreadNotificationEmailAsHtmlOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The styles used to customize the html elements in the resulting html safe string inside a comment body.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n};\n\nexport type ThreadNotificationEmailDataAsHtml = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsHtmlData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as an html safe string.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info\n * and customize comment bodies html elements styles with inline CSS.\n *\n * It returns a `ThreadNotificationEmailDataAsHtml` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsHtml } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsHtml(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * styles,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsHtml(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsHtmlOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsHtml | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsHtml\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodyPromise = convertCommentBodyAsHtml(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyHtml] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsHtml(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyHtml = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml ?? \"\",\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n\nexport type PrepareThreadNotificationEmailAsReactOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The components used to customize the resulting React nodes inside a comment body.\n * Each components has priority over the base components inherited internally defined.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n};\n\nexport type ThreadNotificationEmailDataAsReact = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsReactData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as React nodes.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info and customize comment bodies React components.\n *\n * It returns a `ThreadNotificationEmailDataAsReact` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsReact } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsReact(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * components,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsReact(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsReactOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsReact | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsReact\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodyPromise = convertCommentBodyAsReact(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyReact] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsReact(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyReact = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact ?? null,\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n","import type {\n BaseUserMeta,\n CommentBody,\n CommentBodyLink,\n CommentBodyMention,\n CommentBodyText,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n html,\n htmlSafe,\n isCommentBodyLink,\n isCommentBodyMention,\n isCommentBodyText,\n resolveUsersInCommentBody,\n stringifyCommentBody,\n toAbsoluteUrl,\n} from \"@liveblocks/core\";\nimport React from \"react\";\n\nimport type { CSSProperties } from \"./lib/css-properties\";\nimport { toInlineCSSString } from \"./lib/css-properties\";\n\nexport type CommentBodyContainerComponentProps = {\n /**\n * The blocks of the comment body\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyParagraphComponentProps = {\n /**\n * The text content of the paragraph.\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyTextComponentProps = {\n /**\n * The text element.\n */\n element: CommentBodyText;\n};\n\nexport type CommentBodyLinkComponentProps = {\n /**\n * The link element.\n */\n element: CommentBodyLink;\n\n /**\n * The absolute URL of the link.\n */\n href: string;\n};\n\nexport type CommentBodyMentionComponentProps<U extends BaseUserMeta = DU> = {\n /**\n * The mention element.\n */\n element: CommentBodyMention;\n\n /**\n * The mention's user info, if the `resolvedUsers` option was provided.\n */\n user?: U[\"info\"];\n};\n\nexport type ConvertCommentBodyAsReactComponents<U extends BaseUserMeta = DU> = {\n /**\n *\n * The component used to act as a container to wrap comment body blocks,\n */\n Container: React.ComponentType<CommentBodyContainerComponentProps>;\n /**\n * The component used to display paragraphs.\n */\n Paragraph: React.ComponentType<CommentBodyParagraphComponentProps>;\n\n /**\n * The component used to display text elements.\n */\n Text: React.ComponentType<CommentBodyTextComponentProps>;\n\n /**\n * The component used to display links.\n */\n Link: React.ComponentType<CommentBodyLinkComponentProps>;\n\n /**\n * The component used to display mentions.\n */\n Mention: React.ComponentType<CommentBodyMentionComponentProps<U>>;\n};\n\nconst baseComponents: ConvertCommentBodyAsReactComponents<BaseUserMeta> = {\n Container: ({ children }) => <div>{children}</div>,\n Paragraph: ({ children }) => <p>{children}</p>,\n Text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children: React.ReactNode = element.text;\n\n if (element.bold) {\n children = <strong>{children}</strong>;\n }\n\n if (element.italic) {\n children = <em>{children}</em>;\n }\n\n if (element.strikethrough) {\n children = <s>{children}</s>;\n }\n\n if (element.code) {\n children = <code>{children}</code>;\n }\n\n return <span>{children}</span>;\n },\n Link: ({ element, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {element.text ?? element.url}\n </a>\n ),\n Mention: ({ element, user }) => (\n <span data-mention>@{user?.name ?? element.id}</span>\n ),\n};\n\nexport type ConvertCommentBodyAsReactOptions<U extends BaseUserMeta = DU> = {\n /**\n * The components used to customize the resulting React nodes. Each components has\n * priority over the base components inherited.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n /**\n * A function that returns user info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into React elements\n */\nexport async function convertCommentBodyAsReact(\n body: CommentBody,\n options?: ConvertCommentBodyAsReactOptions<BaseUserMeta>\n): Promise<React.ReactNode> {\n const Components = {\n ...baseComponents,\n ...options?.components,\n };\n const resolvedUsers = await resolveUsersInCommentBody(\n body,\n options?.resolveUsers\n );\n\n const blocks = body.content.map((block, index) => {\n switch (block.type) {\n case \"paragraph\": {\n const children = block.children.map((inline, inlineIndex) => {\n if (isCommentBodyMention(inline)) {\n return inline.id ? (\n <Components.Mention\n key={`lb-comment-body-mention-${inlineIndex}`}\n element={inline}\n user={resolvedUsers.get(inline.id)}\n />\n ) : null;\n }\n\n if (isCommentBodyLink(inline)) {\n const href = toAbsoluteUrl(inline.url) ?? inline.url;\n return (\n <Components.Link\n key={`lb-comment-body-link-${inlineIndex}`}\n element={inline}\n href={href}\n />\n );\n }\n\n if (isCommentBodyText(inline)) {\n return (\n <Components.Text\n key={`lb-comment-body-text-${inlineIndex}`}\n element={inline}\n />\n );\n }\n\n return null;\n });\n\n return (\n <Components.Paragraph key={`lb-comment-body-paragraph-${index}`}>\n {children}\n </Components.Paragraph>\n );\n }\n default:\n console.warn(\n `Unsupported comment body block type: \"${JSON.stringify(block.type)}\"`\n );\n return null;\n }\n });\n\n return (\n <Components.Container key={\"lb-comment-body-container\"}>\n {blocks}\n </Components.Container>\n );\n}\n\nexport type ConvertCommentBodyAsHtmlStyles = {\n /**\n * The default inline CSS styles used to display paragraphs.\n */\n paragraph: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<strong />` elements.\n */\n strong: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<code />` elements.\n */\n code: CSSProperties;\n /**\n * The default inline CSS styles used to display links.\n */\n mention: CSSProperties;\n /**\n * The default inline CSS styles used to display mentions.\n */\n link: CSSProperties;\n};\n\nconst baseStyles: ConvertCommentBodyAsHtmlStyles = {\n paragraph: {\n fontSize: \"14px\",\n },\n strong: {\n fontWeight: 500,\n },\n code: {\n fontFamily:\n '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',\n backgroundColor: \"rgba(0,0,0,0.05)\",\n border: \"solid 1px rgba(0,0,0,0.1)\",\n borderRadius: \"4px\",\n },\n mention: {\n color: \"blue\",\n },\n link: {\n textDecoration: \"underline\",\n },\n};\n\nexport type ConvertCommentBodyAsHtmlOptions<U extends BaseUserMeta = DU> = {\n /**\n * The styles used to customize the html elements in the resulting html safe string.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n /**\n * A function that returns user info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into an html safe string\n * with inline css styles\n */\nexport async function convertCommentBodyAsHtml(\n body: CommentBody,\n options?: ConvertCommentBodyAsHtmlOptions<BaseUserMeta>\n): Promise<string> {\n const styles = { ...baseStyles, ...options?.styles };\n\n const htmlBody = await stringifyCommentBody(body, {\n format: \"html\",\n resolveUsers: options?.resolveUsers,\n elements: {\n // NOTE: using prettier-ignore to preserve template strings\n paragraph: ({ children }) =>\n // prettier-ignore\n children ? html`<p style=\"${toInlineCSSString(styles.paragraph)}\">${htmlSafe(children)}</p>` : children,\n text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children = element.text;\n\n if (!children) {\n return children;\n }\n\n if (element.bold) {\n // prettier-ignore\n children = html`<strong style=\"${toInlineCSSString(styles.strong)}\">${children}</strong>`;\n }\n\n if (element.italic) {\n // prettier-ignore\n children = html`<em>${children}</em>`;\n }\n\n if (element.strikethrough) {\n // prettier-ignore\n children = html`<s>${children}</s>`;\n }\n\n if (element.code) {\n // prettier-ignore\n children = html`<code style=\"${toInlineCSSString(styles.code)}\">${children}</code>`;\n }\n\n return children;\n },\n link: ({ element, href }) => {\n // prettier-ignore\n return html`<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"${toInlineCSSString(styles.link)}\">${element.text ?? element.url}</a>`;\n },\n mention: ({ element, user }) => {\n // prettier-ignore\n return html`<span data-mention style=\"${toInlineCSSString(styles.mention)}\">@${user?.name ?? element.id}</span>`;\n },\n },\n });\n\n return htmlBody;\n}\n","import type { Properties } from \"csstype\";\n\n/**\n * CSS properties object.\n * Type alias for DX purposes.\n *\n */\nexport type CSSProperties = Properties;\n\n/**\n * Vendors\n */\nconst VENDORS_PREFIXES = new RegExp(/^(webkit|moz|ms|o)-/);\n\n/**\n * CSS properties which accept numbers but are not in units of \"px\".\n * Based on: https://github.com/facebook/react/blob/bfe91fbecf183f85fc1c4f909e12a6833a247319/packages/react-dom-bindings/src/shared/isUnitlessNumber.js\n */\nconst UNITLESS_PROPERTIES = [\n \"animationIterationCount\",\n \"aspectRatio\",\n \"borderImageOutset\",\n \"borderImageSlice\",\n \"borderImageWidth\",\n \"boxFlex\",\n \"boxFlexGroup\",\n \"boxOrdinalGroup\",\n \"columnCount\",\n \"columns\",\n \"flex\",\n \"flexGrow\",\n \"flexPositive\",\n \"flexShrink\",\n \"flexNegative\",\n \"flexOrder\",\n \"gridArea\",\n \"gridRow\",\n \"gridRowEnd\",\n \"gridRowSpan\",\n \"gridRowStart\",\n \"gridColumn\",\n \"gridColumnEnd\",\n \"gridColumnSpan\",\n \"gridColumnStart\",\n \"fontWeight\",\n \"lineClamp\",\n \"lineHeight\",\n \"opacity\",\n \"order\",\n \"orphans\",\n \"scale\",\n \"tabSize\",\n \"widows\",\n \"zIndex\",\n \"zoom\",\n \"fillOpacity\",\n \"floodOpacity\",\n \"stopOpacity\",\n \"strokeDasharray\",\n \"strokeDashoffset\",\n \"strokeMiterlimit\",\n \"strokeOpacity\",\n \"strokeWidth\",\n \"MozAnimationIterationCount\",\n \"MozBoxFlex\",\n \"MozBoxFlexGroup\",\n \"MozLineClamp\",\n \"msAnimationIterationCount\",\n \"msFlex\",\n \"msZoom\",\n \"msFlexPositive\",\n \"msGridColumns\",\n \"msGridRows\",\n \"WebkitAnimationIterationCount\",\n \"WebkitBoxFlex\",\n \"WebKitBoxFlexGroup\",\n \"WebkitBoxOrdinalGroup\",\n \"WebkitColumnCount\",\n \"WebkitColumns\",\n \"WebkitFlex\",\n \"WebkitFlexGrow\",\n \"WebkitFlexPositive\",\n \"WebkitFlexShrink\",\n \"WebkitLineClamp\",\n];\n\n/**\n * Convert a `CSSProperties` style object into a inline CSS string.\n */\nexport function toInlineCSSString(styles: CSSProperties): string {\n const entries = Object.entries(styles);\n const inline = entries\n .map(([key, value]): string | null => {\n // Return an empty string if `value` is not acceptable\n if (\n value === null ||\n typeof value === \"boolean\" ||\n value === \"\" ||\n typeof value === \"undefined\"\n ) {\n return \"\";\n }\n\n // Convert key from camelCase to kebab-case\n let property = key.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n\n // Manage vendors prefixes\n if (VENDORS_PREFIXES.test(property)) {\n property = `-${property}`;\n }\n\n // Add `px` if needed for properties which aren't unitless\n if (typeof value === \"number\" && !UNITLESS_PROPERTIES.includes(key)) {\n return `${property}:${value}px;`;\n }\n\n return `${property}:${String(value).trim()};`;\n })\n .filter(Boolean)\n .join(\"\");\n\n return inline;\n}\n","import type { CommentBody, CommentData } from \"@liveblocks/core\";\n\nexport type CommentDataWithBody = Omit<CommentData, \"body\" | \"deletedAt\"> & {\n body: CommentBody;\n deletedAt?: never;\n};\n\nconst isCommentDataWithBody = (\n comment: CommentData\n): comment is CommentDataWithBody => {\n return comment.body !== undefined && comment.deletedAt === undefined;\n};\n\nexport function filterCommentsWithBody(\n comments: CommentData[]\n): CommentDataWithBody[] {\n const commentsWithBody: CommentDataWithBody[] = [];\n for (const comment of comments) {\n if (isCommentDataWithBody(comment)) {\n commentsWithBody.push(comment);\n }\n }\n return commentsWithBody;\n}\n","import type {\n BaseUserMeta,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport { Promise_withResolvers } from \"@liveblocks/core\";\n\nimport { createDevelopmentWarning } from \"./warning\";\n\ntype ResolveUserOptionalPromise<U extends BaseUserMeta> = (\n args: ResolveUsersArgs\n) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n\n/**\n * Batch calls to `resolveUsers` to one and only call.\n * It will avoid any performances issues and invocation timeouts on our customers' webhook handlers.\n *\n * This batch call will stack pending promises referring to `resolveUsers` in a map, resolve all users given in args at once\n * and then resolve pending promises all at once.\n */\nclass BatchUsersResolver<U extends BaseUserMeta> {\n private isResolved: boolean;\n private markAsResolved: () => void;\n private resolvePromise: Promise<void>;\n\n private primeResolveUsersFn: ResolveUserOptionalPromise<U> | undefined;\n private usersById: Map<string, U[\"info\"] | undefined>;\n\n private warnAsAlreadyResolved: () => void;\n\n constructor(resolveUsers: ResolveUserOptionalPromise<U> | undefined) {\n const { promise, resolve } = Promise_withResolvers<void>();\n\n this.isResolved = false;\n this.markAsResolved = resolve;\n this.resolvePromise = promise;\n\n this.primeResolveUsersFn = resolveUsers;\n this.usersById = new Map();\n\n this.warnAsAlreadyResolved = createDevelopmentWarning(\n true,\n \"Batch users resolver promise already resolved. It can only resolve once.\"\n );\n }\n\n resolveUsers = async (\n args: ResolveUsersArgs\n ): Promise<(U[\"info\"] | undefined)[] | undefined> => {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return undefined;\n }\n\n // Note: register all user Ids\n for (const userId of args.userIds) {\n this.usersById.set(userId, undefined);\n }\n\n // Note: waiting until the batch promise is resolved\n await this.resolvePromise;\n\n // Note: once the batch promise is resolved\n // we can return safely resolved users\n return args.userIds.map((userId) => this.usersById.get(userId));\n };\n\n async resolve(): Promise<void> {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return;\n }\n\n // Note: set an array of unique user ids\n const userIds = Array.from(this.usersById.keys());\n const users = await this.primeResolveUsersFn?.({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n this.usersById.set(userId, user);\n }\n\n this.isResolved = true;\n this.markAsResolved();\n }\n}\n\nexport type CreateBatchUsersResolverReturnType<U extends BaseUserMeta> = {\n resolveUsers: (\n args: ResolveUsersArgs\n ) => Promise<(U[\"info\"] | undefined)[] | undefined>;\n resolve: () => Promise<void>;\n};\n\nexport function createBatchUsersResolver<U extends BaseUserMeta = DU>({\n resolveUsers,\n callerName,\n}: {\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n callerName: string;\n}): CreateBatchUsersResolverReturnType<U> {\n const warnIfNoResolveUsers = createDevelopmentWarning(\n () => !resolveUsers,\n `Set \"resolveUsers\" option in \"${callerName}\" to specify users info`\n );\n const batchUsersResolver = new BatchUsersResolver(resolveUsers);\n\n const resolve = async (): Promise<void> => {\n warnIfNoResolveUsers();\n await batchUsersResolver.resolve();\n };\n\n return {\n resolveUsers: batchUsersResolver.resolveUsers,\n resolve,\n } as const;\n}\n","/**\n * @internal\n * Emit a warning only once if a condition is met, in development only.\n */\nexport const createDevelopmentWarning = (\n condition: boolean | (() => boolean),\n ...args: Parameters<typeof console.warn>\n) => {\n let hasWarned = false;\n\n if (process.env.NODE_ENV !== \"production\") {\n return () => {\n if (\n !hasWarned &&\n (typeof condition === \"function\" ? condition() : condition)\n ) {\n console.warn(...args);\n\n hasWarned = true;\n }\n };\n } else {\n return () => {};\n }\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/version.ts","../src/thread-notification.tsx","../src/comment-body.tsx","../src/lib/css-properties.ts","../src/comment-with-body.ts","../src/lib/batch-users-resolver.ts","../src/lib/warning.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n CommentBodyContainerComponentProps,\n CommentBodyLinkComponentProps,\n CommentBodyMentionComponentProps,\n CommentBodyParagraphComponentProps,\n CommentBodyTextComponentProps,\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nexport type {\n CommentEmailAsHtmlData,\n CommentEmailAsReactData,\n PrepareThreadNotificationEmailAsHtmlOptions,\n PrepareThreadNotificationEmailAsReactOptions,\n ResolveRoomInfoArgs,\n ThreadNotificationEmailDataAsHtml,\n ThreadNotificationEmailDataAsReact,\n} from \"./thread-notification\";\nexport {\n prepareThreadNotificationEmailAsHtml,\n prepareThreadNotificationEmailAsReact,\n} from \"./thread-notification\";\nexport type { ResolveUsersArgs } from \"@liveblocks/core\";\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/emails\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n","import type {\n BaseRoomInfo,\n BaseUserMeta,\n CommentBody,\n CommentData,\n DRI,\n DU,\n InboxNotificationData,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n generateCommentUrl,\n getMentionedIdsFromCommentBody,\n} from \"@liveblocks/core\";\nimport type { Liveblocks, ThreadNotificationEvent } from \"@liveblocks/node\";\nimport type React from \"react\";\n\nimport type {\n ConvertCommentBodyAsHtmlStyles,\n ConvertCommentBodyAsReactComponents,\n} from \"./comment-body\";\nimport {\n convertCommentBodyAsHtml,\n convertCommentBodyAsReact,\n} from \"./comment-body\";\nimport type { CommentDataWithBody } from \"./comment-with-body\";\nimport { filterCommentsWithBody } from \"./comment-with-body\";\nimport { createBatchUsersResolver } from \"./lib/batch-users-resolver\";\n\n/** @internal */\nexport const getUnreadComments = ({\n comments,\n inboxNotification,\n userId,\n}: {\n comments: CommentData[];\n inboxNotification: InboxNotificationData;\n userId: string;\n}): CommentDataWithBody[] => {\n const commentsWithBody = filterCommentsWithBody(comments);\n const readAt = inboxNotification.readAt;\n\n return commentsWithBody\n .filter((c) => c.userId !== userId)\n .filter((c) =>\n readAt\n ? c.createdAt > readAt && c.createdAt <= inboxNotification.notifiedAt\n : c.createdAt <= inboxNotification.notifiedAt\n );\n};\n\n/** @internal */\nexport const getLastUnreadCommentWithMention = ({\n comments,\n mentionedUserId,\n}: {\n comments: CommentDataWithBody[];\n mentionedUserId: string;\n}): CommentDataWithBody | null => {\n return (\n Array.from(comments)\n .reverse()\n .filter((c) => c.userId !== mentionedUserId)\n .find((c) => {\n const mentionedUserIds = getMentionedIdsFromCommentBody(c.body);\n return mentionedUserIds.includes(mentionedUserId);\n }) ?? null\n );\n};\n\nexport type ThreadNotificationData =\n | { type: \"unreadMention\"; comment: CommentDataWithBody }\n | { type: \"unreadReplies\"; comments: CommentDataWithBody[] };\n\n/** @internal */\nexport const extractThreadNotificationData = async ({\n client,\n event,\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n}): Promise<ThreadNotificationData | null> => {\n const { threadId, roomId, userId, inboxNotificationId } = event.data;\n const [thread, inboxNotification] = await Promise.all([\n client.getThread({ roomId, threadId }),\n client.getInboxNotification({ inboxNotificationId, userId }),\n ]);\n\n const unreadComments = getUnreadComments({\n comments: thread.comments,\n inboxNotification,\n userId,\n });\n\n if (unreadComments.length <= 0) {\n return null;\n }\n\n const lastUnreadCommentWithMention = getLastUnreadCommentWithMention({\n comments: unreadComments,\n mentionedUserId: userId,\n });\n if (lastUnreadCommentWithMention !== null) {\n return { type: \"unreadMention\", comment: lastUnreadCommentWithMention };\n }\n\n return {\n type: \"unreadReplies\",\n comments: unreadComments,\n };\n};\n\nexport type CommentEmailBaseData = {\n id: string;\n threadId: string;\n roomId: string;\n userId: string;\n createdAt: Date;\n url?: string;\n rawBody: CommentBody;\n};\n\nexport type ResolveRoomInfoArgs = {\n /**\n * The ID of the room to resolve\n */\n roomId: string;\n};\n\ntype PrepareThreadNotificationEmailBaseDataOptions = {\n /**\n * A function that returns room info from room IDs.\n */\n resolveRoomInfo?: (\n args: ResolveRoomInfoArgs\n ) => OptionalPromise<DRI | undefined>;\n};\n\nexport type ThreadNotificationEmailBaseData = (\n | { type: \"unreadMention\"; comment: CommentEmailBaseData }\n | { type: \"unreadReplies\"; comments: CommentEmailBaseData[] }\n) & { roomInfo: DRI };\n\n/** @internal */\nexport const makeCommentEmailBaseData = ({\n roomInfo,\n comment,\n}: {\n roomInfo: BaseRoomInfo | undefined;\n comment: CommentDataWithBody;\n}): CommentEmailBaseData => {\n const url = roomInfo?.url\n ? generateCommentUrl({\n roomUrl: roomInfo?.url,\n commentId: comment.id,\n })\n : undefined;\n\n return {\n id: comment.id,\n userId: comment.userId,\n threadId: comment.threadId,\n roomId: comment.roomId,\n createdAt: comment.createdAt,\n url,\n rawBody: comment.body,\n };\n};\n\n/** @internal */\nexport const prepareThreadNotificationEmailBaseData = async ({\n client,\n event,\n options = {},\n}: {\n client: Liveblocks;\n event: ThreadNotificationEvent;\n options?: PrepareThreadNotificationEmailBaseDataOptions;\n}): Promise<ThreadNotificationEmailBaseData | null> => {\n const { roomId } = event.data;\n\n const roomInfo = options.resolveRoomInfo\n ? await options.resolveRoomInfo({ roomId })\n : undefined;\n const resolvedRoomInfo: DRI = {\n ...roomInfo,\n name: roomInfo?.name ?? roomId,\n };\n\n const data = await extractThreadNotificationData({ client, event });\n if (data === null) {\n return null;\n }\n\n switch (data.type) {\n case \"unreadMention\":\n return {\n type: \"unreadMention\",\n comment: makeCommentEmailBaseData({\n roomInfo,\n comment: data.comment,\n }),\n roomInfo: resolvedRoomInfo,\n };\n case \"unreadReplies\": {\n return {\n type: \"unreadReplies\",\n comments: data.comments.map((comment) =>\n makeCommentEmailBaseData({ roomInfo, comment })\n ),\n roomInfo: resolvedRoomInfo,\n };\n }\n }\n};\n\n/** @internal */\nconst resolveAuthorsInfo = async <U extends BaseUserMeta>({\n comments,\n resolveUsers,\n}: {\n comments: CommentEmailBaseData[];\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n}): Promise<Map<string, U[\"info\"]>> => {\n const resolvedAuthors = new Map<string, U[\"info\"]>();\n if (!resolveUsers) {\n return resolvedAuthors;\n }\n\n const userIds = comments.map((c) => c.userId);\n const users = await resolveUsers({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n if (user) {\n resolvedAuthors.set(userId, user);\n }\n }\n\n return resolvedAuthors;\n};\n\nexport type CommentEmailAsHtmlData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n htmlBody: string;\n};\n\nexport type CommentEmailAsReactData<U extends BaseUserMeta = DU> = Omit<\n CommentEmailBaseData,\n \"userId\" | \"rawBody\"\n> & {\n author: U;\n reactBody: React.ReactNode;\n};\n\ntype ThreadNotificationEmailUnreadRepliesData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadReplies\";\n comments: C[];\n};\n\ntype ThreadNotificationEmailUnreadMentionsData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = {\n type: \"unreadMention\";\n comment: C;\n};\n\n// Note: export for testing helpers\nexport type ThreadNotificationEmailData<\n U extends BaseUserMeta,\n C extends CommentEmailAsHtmlData<U> | CommentEmailAsReactData<U>,\n> = (\n | ThreadNotificationEmailUnreadRepliesData<U, C>\n | ThreadNotificationEmailUnreadMentionsData<U, C>\n) & { roomInfo: DRI };\n\nexport type PrepareThreadNotificationEmailAsHtmlOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The styles used to customize the html elements in the resulting html safe string inside a comment body.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n};\n\nexport type ThreadNotificationEmailDataAsHtml = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsHtmlData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as an html safe string.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info\n * and customize comment bodies html elements styles with inline CSS.\n *\n * It returns a `ThreadNotificationEmailDataAsHtml` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsHtml } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsHtml(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * styles,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsHtml(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsHtmlOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsHtml | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsHtml\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodyPromise = convertCommentBodyAsHtml(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyHtml] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsHtml(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n styles: options.styles,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyHtml = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n htmlBody: commentBodyHtml ?? \"\",\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n\nexport type PrepareThreadNotificationEmailAsReactOptions<\n U extends BaseUserMeta = DU,\n> = PrepareThreadNotificationEmailBaseDataOptions & {\n /**\n * A function that returns info from user IDs.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n /**\n * The components used to customize the resulting React nodes inside a comment body.\n * Each components has priority over the base components inherited internally defined.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n};\n\nexport type ThreadNotificationEmailDataAsReact = ThreadNotificationEmailData<\n BaseUserMeta,\n CommentEmailAsReactData\n>;\n\n/**\n * Prepares data from a `ThreadNotificationEvent` and convert comment bodies as React nodes.\n *\n * @param client The `Liveblocks` node client\n * @param event The `ThreadNotificationEvent` received in the webhook handler\n * @param options The optional options to provide to resolve users, resolve room info and customize comment bodies React components.\n *\n * It returns a `ThreadNotificationEmailDataAsReact` or `null` if there are no unread comments (mention or replies).\n *\n * @example\n * import { Liveblocks} from \"@liveblocks/node\"\n * import { prepareThreadNotificationEmailAsReact } from \"@liveblocks/emails\"\n *\n * const liveblocks = new Liveblocks({ secret: \"sk_...\" })\n * const emailData = prepareThreadNotificationEmailAsReact(\n * liveblocks,\n * event,\n * {\n * resolveUsers,\n * resolveRoomInfo,\n * components,\n * }\n * )\n *\n */\nexport async function prepareThreadNotificationEmailAsReact(\n client: Liveblocks,\n event: ThreadNotificationEvent,\n options: PrepareThreadNotificationEmailAsReactOptions<BaseUserMeta> = {}\n): Promise<ThreadNotificationEmailDataAsReact | null> {\n const data = await prepareThreadNotificationEmailBaseData({\n client,\n event,\n options: { resolveRoomInfo: options.resolveRoomInfo },\n });\n\n if (data === null) {\n return null;\n }\n\n const batchUsersResolver = createBatchUsersResolver<BaseUserMeta>({\n resolveUsers: options.resolveUsers,\n callerName: \"prepareThreadNotificationEmailAsReact\",\n });\n\n switch (data.type) {\n case \"unreadMention\": {\n const { comment } = data;\n\n const authorsInfoPromise = resolveAuthorsInfo({\n comments: [comment],\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodyPromise = convertCommentBodyAsReact(comment.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n });\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, commentBodyReact] = await Promise.all([\n authorsInfoPromise,\n commentBodyPromise,\n ]);\n const authorInfo = authorsInfo.get(comment.userId);\n\n return {\n type: \"unreadMention\",\n comment: {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact,\n },\n roomInfo: data.roomInfo,\n };\n }\n case \"unreadReplies\": {\n const { comments } = data;\n const authorsInfoPromise = resolveAuthorsInfo({\n comments,\n resolveUsers: batchUsersResolver.resolveUsers,\n });\n\n const commentBodiesPromises = comments.map((c) =>\n convertCommentBodyAsReact(c.rawBody, {\n resolveUsers: batchUsersResolver.resolveUsers,\n components: options.components,\n })\n );\n\n await batchUsersResolver.resolve();\n\n const [authorsInfo, ...commentBodies] = await Promise.all([\n authorsInfoPromise,\n ...commentBodiesPromises,\n ]);\n\n return {\n type: \"unreadReplies\",\n comments: comments.map((comment, index) => {\n const authorInfo = authorsInfo.get(comment.userId);\n const commentBodyReact = commentBodies[index];\n\n return {\n id: comment.id,\n threadId: comment.threadId,\n roomId: comment.roomId,\n author: authorInfo\n ? { id: comment.userId, info: authorInfo }\n : { id: comment.userId, info: { name: comment.userId } },\n createdAt: comment.createdAt,\n url: comment.url,\n reactBody: commentBodyReact ?? null,\n };\n }),\n roomInfo: data.roomInfo,\n };\n }\n }\n}\n","import type {\n BaseUserMeta,\n CommentBody,\n CommentBodyLink,\n CommentBodyMention,\n CommentBodyText,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport {\n html,\n htmlSafe,\n isCommentBodyLink,\n isCommentBodyMention,\n isCommentBodyText,\n resolveUsersInCommentBody,\n stringifyCommentBody,\n toAbsoluteUrl,\n} from \"@liveblocks/core\";\nimport React from \"react\";\n\nimport type { CSSProperties } from \"./lib/css-properties\";\nimport { toInlineCSSString } from \"./lib/css-properties\";\n\nexport type CommentBodyContainerComponentProps = {\n /**\n * The blocks of the comment body\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyParagraphComponentProps = {\n /**\n * The text content of the paragraph.\n */\n children: React.ReactNode;\n};\n\nexport type CommentBodyTextComponentProps = {\n /**\n * The text element.\n */\n element: CommentBodyText;\n};\n\nexport type CommentBodyLinkComponentProps = {\n /**\n * The link element.\n */\n element: CommentBodyLink;\n\n /**\n * The absolute URL of the link.\n */\n href: string;\n};\n\nexport type CommentBodyMentionComponentProps<U extends BaseUserMeta = DU> = {\n /**\n * The mention element.\n */\n element: CommentBodyMention;\n\n /**\n * The mention's user info, if the `resolvedUsers` option was provided.\n */\n user?: U[\"info\"];\n};\n\nexport type ConvertCommentBodyAsReactComponents<U extends BaseUserMeta = DU> = {\n /**\n *\n * The component used to act as a container to wrap comment body blocks,\n */\n Container: React.ComponentType<CommentBodyContainerComponentProps>;\n /**\n * The component used to display paragraphs.\n */\n Paragraph: React.ComponentType<CommentBodyParagraphComponentProps>;\n\n /**\n * The component used to display text elements.\n */\n Text: React.ComponentType<CommentBodyTextComponentProps>;\n\n /**\n * The component used to display links.\n */\n Link: React.ComponentType<CommentBodyLinkComponentProps>;\n\n /**\n * The component used to display mentions.\n */\n Mention: React.ComponentType<CommentBodyMentionComponentProps<U>>;\n};\n\nconst baseComponents: ConvertCommentBodyAsReactComponents<BaseUserMeta> = {\n Container: ({ children }) => <div>{children}</div>,\n Paragraph: ({ children }) => <p>{children}</p>,\n Text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children: React.ReactNode = element.text;\n\n if (element.bold) {\n children = <strong>{children}</strong>;\n }\n\n if (element.italic) {\n children = <em>{children}</em>;\n }\n\n if (element.strikethrough) {\n children = <s>{children}</s>;\n }\n\n if (element.code) {\n children = <code>{children}</code>;\n }\n\n return <span>{children}</span>;\n },\n Link: ({ element, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {element.text ?? element.url}\n </a>\n ),\n Mention: ({ element, user }) => (\n <span data-mention>@{user?.name ?? element.id}</span>\n ),\n};\n\nexport type ConvertCommentBodyAsReactOptions<U extends BaseUserMeta = DU> = {\n /**\n * The components used to customize the resulting React nodes. Each components has\n * priority over the base components inherited.\n */\n components?: Partial<ConvertCommentBodyAsReactComponents<U>>;\n /**\n * A function that returns user info from user IDs.\n * You should return a list of user objects of the same size, in the same order.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into React elements\n */\nexport async function convertCommentBodyAsReact(\n body: CommentBody,\n options?: ConvertCommentBodyAsReactOptions<BaseUserMeta>\n): Promise<React.ReactNode> {\n const Components = {\n ...baseComponents,\n ...options?.components,\n };\n const resolvedUsers = await resolveUsersInCommentBody(\n body,\n options?.resolveUsers\n );\n\n const blocks = body.content.map((block, index) => {\n switch (block.type) {\n case \"paragraph\": {\n const children = block.children.map((inline, inlineIndex) => {\n if (isCommentBodyMention(inline)) {\n return inline.id ? (\n <Components.Mention\n key={`lb-comment-body-mention-${inlineIndex}`}\n element={inline}\n user={resolvedUsers.get(inline.id)}\n />\n ) : null;\n }\n\n if (isCommentBodyLink(inline)) {\n const href = toAbsoluteUrl(inline.url) ?? inline.url;\n return (\n <Components.Link\n key={`lb-comment-body-link-${inlineIndex}`}\n element={inline}\n href={href}\n />\n );\n }\n\n if (isCommentBodyText(inline)) {\n return (\n <Components.Text\n key={`lb-comment-body-text-${inlineIndex}`}\n element={inline}\n />\n );\n }\n\n return null;\n });\n\n return (\n <Components.Paragraph key={`lb-comment-body-paragraph-${index}`}>\n {children}\n </Components.Paragraph>\n );\n }\n default:\n console.warn(\n `Unsupported comment body block type: \"${JSON.stringify(block.type)}\"`\n );\n return null;\n }\n });\n\n return (\n <Components.Container key={\"lb-comment-body-container\"}>\n {blocks}\n </Components.Container>\n );\n}\n\nexport type ConvertCommentBodyAsHtmlStyles = {\n /**\n * The default inline CSS styles used to display paragraphs.\n */\n paragraph: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<strong />` elements.\n */\n strong: CSSProperties;\n /**\n * The default inline CSS styles used to display text `<code />` elements.\n */\n code: CSSProperties;\n /**\n * The default inline CSS styles used to display links.\n */\n mention: CSSProperties;\n /**\n * The default inline CSS styles used to display mentions.\n */\n link: CSSProperties;\n};\n\nconst baseStyles: ConvertCommentBodyAsHtmlStyles = {\n paragraph: {\n fontSize: \"14px\",\n },\n strong: {\n fontWeight: 500,\n },\n code: {\n fontFamily:\n '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',\n backgroundColor: \"rgba(0,0,0,0.05)\",\n border: \"solid 1px rgba(0,0,0,0.1)\",\n borderRadius: \"4px\",\n },\n mention: {\n color: \"blue\",\n },\n link: {\n textDecoration: \"underline\",\n },\n};\n\nexport type ConvertCommentBodyAsHtmlOptions<U extends BaseUserMeta = DU> = {\n /**\n * The styles used to customize the html elements in the resulting html safe string.\n * Each styles has priority over the base styles inherited.\n */\n styles?: Partial<ConvertCommentBodyAsHtmlStyles>;\n /**\n * A function that returns user info from user IDs.\n * You should return a list of user objects of the same size, in the same order.\n */\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n};\n\n/**\n * Convert a `CommentBody` into an html safe string\n * with inline css styles\n */\nexport async function convertCommentBodyAsHtml(\n body: CommentBody,\n options?: ConvertCommentBodyAsHtmlOptions<BaseUserMeta>\n): Promise<string> {\n const styles = { ...baseStyles, ...options?.styles };\n\n const htmlBody = await stringifyCommentBody(body, {\n format: \"html\",\n resolveUsers: options?.resolveUsers,\n elements: {\n // NOTE: using prettier-ignore to preserve template strings\n paragraph: ({ children }) =>\n // prettier-ignore\n children ? html`<p style=\"${toInlineCSSString(styles.paragraph)}\">${htmlSafe(children)}</p>` : children,\n text: ({ element }) => {\n // Note: construction following the schema 👇\n // <code><s><em><strong>{element.text}</strong></s></em></code>\n let children = element.text;\n\n if (!children) {\n return children;\n }\n\n if (element.bold) {\n // prettier-ignore\n children = html`<strong style=\"${toInlineCSSString(styles.strong)}\">${children}</strong>`;\n }\n\n if (element.italic) {\n // prettier-ignore\n children = html`<em>${children}</em>`;\n }\n\n if (element.strikethrough) {\n // prettier-ignore\n children = html`<s>${children}</s>`;\n }\n\n if (element.code) {\n // prettier-ignore\n children = html`<code style=\"${toInlineCSSString(styles.code)}\">${children}</code>`;\n }\n\n return children;\n },\n link: ({ element, href }) => {\n // prettier-ignore\n return html`<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"${toInlineCSSString(styles.link)}\">${element.text ?? element.url}</a>`;\n },\n mention: ({ element, user }) => {\n // prettier-ignore\n return html`<span data-mention style=\"${toInlineCSSString(styles.mention)}\">@${user?.name ?? element.id}</span>`;\n },\n },\n });\n\n return htmlBody;\n}\n","import type { Properties } from \"csstype\";\n\n/**\n * CSS properties object.\n * Type alias for DX purposes.\n *\n */\nexport type CSSProperties = Properties;\n\n/**\n * Vendors\n */\nconst VENDORS_PREFIXES = new RegExp(/^(webkit|moz|ms|o)-/);\n\n/**\n * CSS properties which accept numbers but are not in units of \"px\".\n * Based on: https://github.com/facebook/react/blob/bfe91fbecf183f85fc1c4f909e12a6833a247319/packages/react-dom-bindings/src/shared/isUnitlessNumber.js\n */\nconst UNITLESS_PROPERTIES = [\n \"animationIterationCount\",\n \"aspectRatio\",\n \"borderImageOutset\",\n \"borderImageSlice\",\n \"borderImageWidth\",\n \"boxFlex\",\n \"boxFlexGroup\",\n \"boxOrdinalGroup\",\n \"columnCount\",\n \"columns\",\n \"flex\",\n \"flexGrow\",\n \"flexPositive\",\n \"flexShrink\",\n \"flexNegative\",\n \"flexOrder\",\n \"gridArea\",\n \"gridRow\",\n \"gridRowEnd\",\n \"gridRowSpan\",\n \"gridRowStart\",\n \"gridColumn\",\n \"gridColumnEnd\",\n \"gridColumnSpan\",\n \"gridColumnStart\",\n \"fontWeight\",\n \"lineClamp\",\n \"lineHeight\",\n \"opacity\",\n \"order\",\n \"orphans\",\n \"scale\",\n \"tabSize\",\n \"widows\",\n \"zIndex\",\n \"zoom\",\n \"fillOpacity\",\n \"floodOpacity\",\n \"stopOpacity\",\n \"strokeDasharray\",\n \"strokeDashoffset\",\n \"strokeMiterlimit\",\n \"strokeOpacity\",\n \"strokeWidth\",\n \"MozAnimationIterationCount\",\n \"MozBoxFlex\",\n \"MozBoxFlexGroup\",\n \"MozLineClamp\",\n \"msAnimationIterationCount\",\n \"msFlex\",\n \"msZoom\",\n \"msFlexPositive\",\n \"msGridColumns\",\n \"msGridRows\",\n \"WebkitAnimationIterationCount\",\n \"WebkitBoxFlex\",\n \"WebKitBoxFlexGroup\",\n \"WebkitBoxOrdinalGroup\",\n \"WebkitColumnCount\",\n \"WebkitColumns\",\n \"WebkitFlex\",\n \"WebkitFlexGrow\",\n \"WebkitFlexPositive\",\n \"WebkitFlexShrink\",\n \"WebkitLineClamp\",\n];\n\n/**\n * Convert a `CSSProperties` style object into a inline CSS string.\n */\nexport function toInlineCSSString(styles: CSSProperties): string {\n const entries = Object.entries(styles);\n const inline = entries\n .map(([key, value]): string | null => {\n // Return an empty string if `value` is not acceptable\n if (\n value === null ||\n typeof value === \"boolean\" ||\n value === \"\" ||\n typeof value === \"undefined\"\n ) {\n return \"\";\n }\n\n // Convert key from camelCase to kebab-case\n let property = key.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n\n // Manage vendors prefixes\n if (VENDORS_PREFIXES.test(property)) {\n property = `-${property}`;\n }\n\n // Add `px` if needed for properties which aren't unitless\n if (typeof value === \"number\" && !UNITLESS_PROPERTIES.includes(key)) {\n return `${property}:${value}px;`;\n }\n\n return `${property}:${String(value).trim()};`;\n })\n .filter(Boolean)\n .join(\"\");\n\n return inline;\n}\n","import type { CommentBody, CommentData } from \"@liveblocks/core\";\n\nexport type CommentDataWithBody = Omit<CommentData, \"body\" | \"deletedAt\"> & {\n body: CommentBody;\n deletedAt?: never;\n};\n\nconst isCommentDataWithBody = (\n comment: CommentData\n): comment is CommentDataWithBody => {\n return comment.body !== undefined && comment.deletedAt === undefined;\n};\n\nexport function filterCommentsWithBody(\n comments: CommentData[]\n): CommentDataWithBody[] {\n const commentsWithBody: CommentDataWithBody[] = [];\n for (const comment of comments) {\n if (isCommentDataWithBody(comment)) {\n commentsWithBody.push(comment);\n }\n }\n return commentsWithBody;\n}\n","import type {\n BaseUserMeta,\n DU,\n OptionalPromise,\n ResolveUsersArgs,\n} from \"@liveblocks/core\";\nimport { Promise_withResolvers } from \"@liveblocks/core\";\n\nimport { createDevelopmentWarning } from \"./warning\";\n\ntype ResolveUserOptionalPromise<U extends BaseUserMeta> = (\n args: ResolveUsersArgs\n) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n\n/**\n * Batch calls to `resolveUsers` to one and only call.\n * It will avoid any performances issues and invocation timeouts on our customers' webhook handlers.\n *\n * This batch call will stack pending promises referring to `resolveUsers` in a map, resolve all users given in args at once\n * and then resolve pending promises all at once.\n */\nclass BatchUsersResolver<U extends BaseUserMeta> {\n private isResolved: boolean;\n private markAsResolved: () => void;\n private resolvePromise: Promise<void>;\n\n private primeResolveUsersFn: ResolveUserOptionalPromise<U> | undefined;\n private usersById: Map<string, U[\"info\"] | undefined>;\n\n private warnAsAlreadyResolved: () => void;\n\n constructor(resolveUsers: ResolveUserOptionalPromise<U> | undefined) {\n const { promise, resolve } = Promise_withResolvers<void>();\n\n this.isResolved = false;\n this.markAsResolved = resolve;\n this.resolvePromise = promise;\n\n this.primeResolveUsersFn = resolveUsers;\n this.usersById = new Map();\n\n this.warnAsAlreadyResolved = createDevelopmentWarning(\n true,\n \"Batch users resolver promise already resolved. It can only resolve once.\"\n );\n }\n\n resolveUsers = async (\n args: ResolveUsersArgs\n ): Promise<(U[\"info\"] | undefined)[] | undefined> => {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return undefined;\n }\n\n // Note: register all user Ids\n for (const userId of args.userIds) {\n this.usersById.set(userId, undefined);\n }\n\n // Note: waiting until the batch promise is resolved\n await this.resolvePromise;\n\n // Note: once the batch promise is resolved\n // we can return safely resolved users\n return args.userIds.map((userId) => this.usersById.get(userId));\n };\n\n async resolve(): Promise<void> {\n if (this.isResolved) {\n this.warnAsAlreadyResolved();\n return;\n }\n\n // Note: set an array of unique user ids\n const userIds = Array.from(this.usersById.keys());\n const users = await this.primeResolveUsersFn?.({ userIds });\n\n for (const [index, userId] of userIds.entries()) {\n const user = users?.[index];\n this.usersById.set(userId, user);\n }\n\n this.isResolved = true;\n this.markAsResolved();\n }\n}\n\nexport type CreateBatchUsersResolverReturnType<U extends BaseUserMeta> = {\n resolveUsers: (\n args: ResolveUsersArgs\n ) => Promise<(U[\"info\"] | undefined)[] | undefined>;\n resolve: () => Promise<void>;\n};\n\nexport function createBatchUsersResolver<U extends BaseUserMeta = DU>({\n resolveUsers,\n callerName,\n}: {\n resolveUsers?: (\n args: ResolveUsersArgs\n ) => OptionalPromise<(U[\"info\"] | undefined)[] | undefined>;\n callerName: string;\n}): CreateBatchUsersResolverReturnType<U> {\n const warnIfNoResolveUsers = createDevelopmentWarning(\n () => !resolveUsers,\n `Set \"resolveUsers\" option in \"${callerName}\" to specify users info`\n );\n const batchUsersResolver = new BatchUsersResolver(resolveUsers);\n\n const resolve = async (): Promise<void> => {\n warnIfNoResolveUsers();\n await batchUsersResolver.resolve();\n };\n\n return {\n resolveUsers: batchUsersResolver.resolveUsers,\n resolve,\n } as const;\n}\n","/**\n * @internal\n * Emit a warning only once if a condition is met, in development only.\n */\nexport const createDevelopmentWarning = (\n condition: boolean | (() => boolean),\n ...args: Parameters<typeof console.warn>\n) => {\n let hasWarned = false;\n\n if (process.env.NODE_ENV !== \"production\") {\n return () => {\n if (\n !hasWarned &&\n (typeof condition === \"function\" ? condition() : condition)\n ) {\n console.warn(...args);\n\n hasWarned = true;\n }\n };\n } else {\n return () => {};\n }\n};\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/emails",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "A set of functions and utilities to make sending emails based on Liveblocks notification events easy. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"test:watch": "jest --silent --verbose --color=always --watch"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@liveblocks/core": "2.
|
|
39
|
-
"@liveblocks/node": "2.
|
|
38
|
+
"@liveblocks/core": "2.13.0",
|
|
39
|
+
"@liveblocks/node": "2.13.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"react": "^16.14.0 || ^17 || ^18 || ^19 || ^19.0.0-rc"
|