diff --git a/package.json b/package.json index e1c6a4e059..201c00ad24 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "@octokit/graphql": "^7.0.2", "@ptc-org/nestjs-query-core": "^4.2.0", "@ptc-org/nestjs-query-typeorm": "4.2.1-alpha.2", + "@react-email/components": "0.0.12", + "@react-email/render": "0.0.10", "@sentry/node": "^7.66.0", "@sentry/profiling-node": "^1.2.6", "@sentry/react": "^7.88.0", diff --git a/packages/twenty-server/src/emails/common-style.ts b/packages/twenty-server/src/emails/common-style.ts new file mode 100644 index 0000000000..6a80ebeddb --- /dev/null +++ b/packages/twenty-server/src/emails/common-style.ts @@ -0,0 +1,48 @@ +const grayScale = { + gray100: '#000000', + gray90: '#141414', + gray85: '#171717', + gray80: '#1b1b1b', + gray75: '#1d1d1d', + gray70: '#222222', + gray65: '#292929', + gray60: '#333333', + gray55: '#4c4c4c', + gray50: '#666666', + gray45: '#818181', + gray40: '#999999', + gray35: '#b3b3b3', + gray30: '#cccccc', + gray25: '#d6d6d6', + gray20: '#ebebeb', + gray15: '#f1f1f1', + gray10: '#fcfcfc', + gray0: '#ffffff', +}; + +export const emailTheme = { + font: { + colors: { + highlighted: grayScale.gray60, + primary: grayScale.gray50, + inverted: grayScale.gray0, + }, + weight: { + regular: 400, + bold: 600, + }, + size: { + md: '13px', + lg: '16px', + }, + }, + background: { + colors: { highlight: grayScale.gray15 }, + radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${grayScale.gray60} 100%)`, + radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${grayScale.gray60} 100%)`, + transparent: { + medium: 'rgba(0, 0, 0, 0.08)', + light: 'rgba(0, 0, 0, 0.04)', + }, + }, +}; diff --git a/packages/twenty-server/src/emails/components/BaseEmail.tsx b/packages/twenty-server/src/emails/components/BaseEmail.tsx new file mode 100644 index 0000000000..6717f0e579 --- /dev/null +++ b/packages/twenty-server/src/emails/components/BaseEmail.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { Container, Html } from '@react-email/components'; + +import { BaseHead } from 'src/emails/components/BaseHead'; +import { Logo } from 'src/emails/components/Logo'; + +export const BaseEmail = ({ children }) => { + return ( + + + + + {children} + + + ); +}; diff --git a/packages/twenty-server/src/emails/components/BaseHead.tsx b/packages/twenty-server/src/emails/components/BaseHead.tsx new file mode 100644 index 0000000000..6d3c92be13 --- /dev/null +++ b/packages/twenty-server/src/emails/components/BaseHead.tsx @@ -0,0 +1,22 @@ +import { Font, Head } from '@react-email/components'; +import * as React from 'react'; + +import { emailTheme } from 'src/emails/common-style'; + +export const BaseHead = () => { + return ( + + Twenty email + + + ); +}; diff --git a/packages/twenty-server/src/emails/components/CallToAction.tsx b/packages/twenty-server/src/emails/components/CallToAction.tsx new file mode 100644 index 0000000000..7748999236 --- /dev/null +++ b/packages/twenty-server/src/emails/components/CallToAction.tsx @@ -0,0 +1,23 @@ +import { Button } from '@react-email/button'; +import * as React from 'react'; + +import { emailTheme } from 'src/emails/common-style'; +const callToActionStyle = { + display: 'flex', + padding: '8px 32px', + borderRadius: '8px', + border: `1px solid ${emailTheme.background.transparent.light}`, + background: emailTheme.background.radialGradient, + boxShadow: `0px 2px 4px 0px ${emailTheme.background.transparent.light}, 0px 0px 4px 0px ${emailTheme.background.transparent.medium}`, + color: emailTheme.font.colors.inverted, + fontSize: emailTheme.font.size.md, + fontWeight: emailTheme.font.weight.bold, +}; + +export const CallToAction = ({ value, href }) => { + return ( + + ); +}; diff --git a/packages/twenty-server/src/emails/components/HighlightedText.tsx b/packages/twenty-server/src/emails/components/HighlightedText.tsx new file mode 100644 index 0000000000..75010e017c --- /dev/null +++ b/packages/twenty-server/src/emails/components/HighlightedText.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { Row } from '@react-email/row'; +import { Text } from '@react-email/text'; +import { Column } from '@react-email/components'; + +import { emailTheme } from 'src/emails/common-style'; + +const rowStyle = { + display: 'flex', +}; + +const highlightedStyle = { + borderRadius: '4px', + background: emailTheme.background.colors.highlight, + padding: '4px 8px', + margin: 0, + fontSize: emailTheme.font.size.lg, + fontWeight: emailTheme.font.weight.bold, + color: emailTheme.font.colors.highlighted, +}; + +export const HighlightedText = ({ value }) => { + return ( + + + {value} + + + ); +}; diff --git a/packages/twenty-server/src/emails/components/Logo.tsx b/packages/twenty-server/src/emails/components/Logo.tsx new file mode 100644 index 0000000000..7b0638426c --- /dev/null +++ b/packages/twenty-server/src/emails/components/Logo.tsx @@ -0,0 +1,17 @@ +import { Img } from '@react-email/components'; + +const logoStyle = { + marginBottom: '40px', +}; + +export const Logo = () => { + return ( + Twenty logo + ); +}; diff --git a/packages/twenty-server/src/emails/components/MainText.tsx b/packages/twenty-server/src/emails/components/MainText.tsx new file mode 100644 index 0000000000..8412c2bd94 --- /dev/null +++ b/packages/twenty-server/src/emails/components/MainText.tsx @@ -0,0 +1,14 @@ +import { Text } from '@react-email/text'; +import * as React from 'react'; + +import { emailTheme } from 'src/emails/common-style'; + +const mainTextStyle = { + fontSize: emailTheme.font.size.md, + fontWeight: emailTheme.font.weight.regular, + color: emailTheme.font.colors.primary, +}; + +export const MainText = ({ children }) => { + return {children}; +}; diff --git a/packages/twenty-server/src/emails/components/Title.tsx b/packages/twenty-server/src/emails/components/Title.tsx new file mode 100644 index 0000000000..1b5aed29a0 --- /dev/null +++ b/packages/twenty-server/src/emails/components/Title.tsx @@ -0,0 +1,6 @@ +import { Heading } from '@react-email/components'; +import * as React from 'react'; + +export const Title = ({ value }) => { + return {value}; +}; diff --git a/packages/twenty-server/src/integrations/email/email-sender.job.ts b/packages/twenty-server/src/integrations/email/email-sender.job.ts new file mode 100644 index 0000000000..d6ad62c37b --- /dev/null +++ b/packages/twenty-server/src/integrations/email/email-sender.job.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; + +import { SendMailOptions } from 'nodemailer'; + +import { MessageQueueJob } from 'src/integrations/message-queue/interfaces/message-queue-job.interface'; + +import { EmailSenderService } from 'src/integrations/email/email-sender.service'; + +@Injectable() +export class EmailSenderJob implements MessageQueueJob { + constructor(private readonly emailSenderService: EmailSenderService) {} + + async handle(data: SendMailOptions): Promise { + process.stdout.write(`Sending email to ${data.to} ...`); + await this.emailSenderService.send(data); + console.log(' done!'); + } +} diff --git a/packages/twenty-server/src/integrations/email/email-sender.service.ts b/packages/twenty-server/src/integrations/email/email-sender.service.ts new file mode 100644 index 0000000000..58b6c4a9c1 --- /dev/null +++ b/packages/twenty-server/src/integrations/email/email-sender.service.ts @@ -0,0 +1,16 @@ +import { Inject, Injectable } from '@nestjs/common'; + +import { SendMailOptions } from 'nodemailer'; + +import { EmailDriver } from 'src/integrations/email/drivers/interfaces/email-driver.interface'; + +import { EMAIL_DRIVER } from 'src/integrations/email/email.constants'; + +@Injectable() +export class EmailSenderService implements EmailDriver { + constructor(@Inject(EMAIL_DRIVER) private driver: EmailDriver) {} + + async send(sendMailOptions: SendMailOptions): Promise { + await this.driver.send(sendMailOptions); + } +} diff --git a/packages/twenty-server/src/integrations/email/email.module.ts b/packages/twenty-server/src/integrations/email/email.module.ts index 2e4c8d9a18..d18fa71fdb 100644 --- a/packages/twenty-server/src/integrations/email/email.module.ts +++ b/packages/twenty-server/src/integrations/email/email.module.ts @@ -6,6 +6,7 @@ import { EMAIL_DRIVER } from 'src/integrations/email/email.constants'; import { LoggerDriver } from 'src/integrations/email/drivers/logger.driver'; import { SmtpDriver } from 'src/integrations/email/drivers/smtp.driver'; import { EmailService } from 'src/integrations/email/email.service'; +import { EmailSenderService } from 'src/integrations/email/email-sender.service'; @Global() export class EmailModule { @@ -22,8 +23,8 @@ export class EmailModule { return { module: EmailModule, - providers: [EmailService, provider], - exports: [EmailService], + providers: [EmailSenderService, EmailService, provider], + exports: [EmailSenderService, EmailService], }; } } diff --git a/packages/twenty-server/src/integrations/email/email.service.ts b/packages/twenty-server/src/integrations/email/email.service.ts index 1c94c33b11..8963ce74d9 100644 --- a/packages/twenty-server/src/integrations/email/email.service.ts +++ b/packages/twenty-server/src/integrations/email/email.service.ts @@ -2,15 +2,22 @@ import { Inject, Injectable } from '@nestjs/common'; import { SendMailOptions } from 'nodemailer'; -import { EmailDriver } from 'src/integrations/email/drivers/interfaces/email-driver.interface'; - -import { EMAIL_DRIVER } from 'src/integrations/email/email.constants'; +import { MessageQueue } from 'src/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/integrations/message-queue/services/message-queue.service'; +import { EmailSenderJob } from 'src/integrations/email/email-sender.job'; @Injectable() -export class EmailService implements EmailDriver { - constructor(@Inject(EMAIL_DRIVER) private driver: EmailDriver) {} +export class EmailService { + constructor( + @Inject(MessageQueue.emailQueue) + private readonly messageQueueService: MessageQueueService, + ) {} async send(sendMailOptions: SendMailOptions): Promise { - await this.driver.send(sendMailOptions); + await this.messageQueueService.add( + EmailSenderJob.name, + sendMailOptions, + { retryLimit: 3 }, + ); } } diff --git a/packages/twenty-server/src/integrations/integrations.module.ts b/packages/twenty-server/src/integrations/integrations.module.ts index 51ac6f0895..7c63cfe568 100644 --- a/packages/twenty-server/src/integrations/integrations.module.ts +++ b/packages/twenty-server/src/integrations/integrations.module.ts @@ -6,8 +6,8 @@ import { exceptionHandlerModuleFactory } from 'src/integrations/exception-handle import { fileStorageModuleFactory } from 'src/integrations/file-storage/file-storage.module-factory'; import { loggerModuleFactory } from 'src/integrations/logger/logger.module-factory'; import { messageQueueModuleFactory } from 'src/integrations/message-queue/message-queue.module-factory'; -import { emailModuleFactory } from 'src/integrations/email/email.module-factory'; import { EmailModule } from 'src/integrations/email/email.module'; +import { emailModuleFactory } from 'src/integrations/email/email.module-factory'; import { EnvironmentModule } from './environment/environment.module'; import { EnvironmentService } from './environment/environment.service'; diff --git a/packages/twenty-server/src/integrations/message-queue/jobs.module.ts b/packages/twenty-server/src/integrations/message-queue/jobs.module.ts index 345c4a418a..1104718464 100644 --- a/packages/twenty-server/src/integrations/message-queue/jobs.module.ts +++ b/packages/twenty-server/src/integrations/message-queue/jobs.module.ts @@ -10,6 +10,7 @@ import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metada import { DataSourceModule } from 'src/metadata/data-source/data-source.module'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { FetchWorkspaceMessagesModule } from 'src/workspace/messaging/services/fetch-workspace-messages.module'; +import { EmailSenderJob } from 'src/integrations/email/email-sender.job'; @Module({ imports: [ @@ -33,6 +34,10 @@ import { FetchWorkspaceMessagesModule } from 'src/workspace/messaging/services/f provide: CallWebhookJob.name, useClass: CallWebhookJob, }, + { + provide: EmailSenderJob.name, + useClass: EmailSenderJob, + }, ], }) export class JobsModule { diff --git a/packages/twenty-server/src/integrations/message-queue/message-queue.constants.ts b/packages/twenty-server/src/integrations/message-queue/message-queue.constants.ts index 925407e981..228311c507 100644 --- a/packages/twenty-server/src/integrations/message-queue/message-queue.constants.ts +++ b/packages/twenty-server/src/integrations/message-queue/message-queue.constants.ts @@ -5,4 +5,5 @@ export enum MessageQueue { messagingQueue = 'messaging-queue', webhookQueue = 'webhook-queue', cronQueue = 'cron-queue', + emailQueue = 'email-queue', } diff --git a/packages/twenty-server/src/queue-worker.module.ts b/packages/twenty-server/src/queue-worker.module.ts index fbf96e5909..06fa839ebd 100644 --- a/packages/twenty-server/src/queue-worker.module.ts +++ b/packages/twenty-server/src/queue-worker.module.ts @@ -7,6 +7,7 @@ import { loggerModuleFactory } from 'src/integrations/logger/logger.module-facto import { JobsModule } from 'src/integrations/message-queue/jobs.module'; import { MessageQueueModule } from 'src/integrations/message-queue/message-queue.module'; import { messageQueueModuleFactory } from 'src/integrations/message-queue/message-queue.module-factory'; +import { IntegrationsModule } from 'src/integrations/integrations.module'; @Module({ imports: [ @@ -20,6 +21,7 @@ import { messageQueueModuleFactory } from 'src/integrations/message-queue/messag inject: [EnvironmentService], }), JobsModule, + IntegrationsModule, ], }) export class QueueWorkerModule {} diff --git a/packages/twenty-server/tsconfig.json b/packages/twenty-server/tsconfig.json index f5993c2161..6acfb191b4 100644 --- a/packages/twenty-server/tsconfig.json +++ b/packages/twenty-server/tsconfig.json @@ -22,6 +22,7 @@ "forceConsistentCasingInFileNames": false, "noFallthroughCasesInSwitch": false, "resolveJsonModule": true, - "types": ["jest", "node"] + "types": ["jest", "node"], + "jsx": "react-jsx" } } diff --git a/yarn.lock b/yarn.lock index b353f28c2c..ceb4e26668 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8416,6 +8416,13 @@ __metadata: languageName: node linkType: hard +"@one-ini/wasm@npm:0.1.1": + version: 0.1.1 + resolution: "@one-ini/wasm@npm:0.1.1" + checksum: 54700e055037f1a63bfcc86d24822203b25759598c2c3e295d1435130a449108aebc119c9c2e467744767dbe0b6ab47a182c61aa1071ba7368f5e20ab197ba65 + languageName: node + linkType: hard + "@open-draft/deferred-promise@npm:^2.1.0, @open-draft/deferred-promise@npm:^2.2.0": version: 2.2.0 resolution: "@open-draft/deferred-promise@npm:2.2.0" @@ -9795,6 +9802,205 @@ __metadata: languageName: node linkType: hard +"@react-email/body@npm:0.0.4": + version: 0.0.4 + resolution: "@react-email/body@npm:0.0.4" + peerDependencies: + react: 18.2.0 + checksum: 756a184bc1284e8ce1828cd3abc0ea3aa24262e6c677b4e4de48fd6c298717fbc0164e7af7ac4c72262bc3138222ab7fc30c63b0520178315fece2bd78d12f98 + languageName: node + linkType: hard + +"@react-email/button@npm:0.0.11": + version: 0.0.11 + resolution: "@react-email/button@npm:0.0.11" + peerDependencies: + react: 18.2.0 + checksum: 91de881f33adec7f5ff311dc8259771fff638cbb736a851a6d4a7e634378555177eb112bc38abb18af7e4bc8ccc899f5bce5b20d409e377d289904d37a20c0ce + languageName: node + linkType: hard + +"@react-email/column@npm:0.0.8": + version: 0.0.8 + resolution: "@react-email/column@npm:0.0.8" + peerDependencies: + react: 18.2.0 + checksum: 5a937dbe7a69c1db8078f84cf70b66224be187dafa78e683103ccbbdb5d3ad2267f7b92c4fbd73922e8c8dda2a4372f37c1a7efac38501cb356d20c028a87574 + languageName: node + linkType: hard + +"@react-email/components@npm:0.0.12": + version: 0.0.12 + resolution: "@react-email/components@npm:0.0.12" + dependencies: + "@react-email/body": "npm:0.0.4" + "@react-email/button": "npm:0.0.11" + "@react-email/column": "npm:0.0.8" + "@react-email/container": "npm:0.0.10" + "@react-email/font": "npm:0.0.4" + "@react-email/head": "npm:0.0.6" + "@react-email/heading": "npm:0.0.9" + "@react-email/hr": "npm:0.0.6" + "@react-email/html": "npm:0.0.6" + "@react-email/img": "npm:0.0.6" + "@react-email/link": "npm:0.0.6" + "@react-email/preview": "npm:0.0.7" + "@react-email/render": "npm:0.0.9" + "@react-email/row": "npm:0.0.6" + "@react-email/section": "npm:0.0.10" + "@react-email/tailwind": "npm:0.0.13" + "@react-email/text": "npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: 1cc01198e5eeb42aac79b11e1a0ceaddd75d3164425899d6fc676ddbcd84cb869cebb0c6feb1f4383ba92d150c32e94d1fe5eec2ee74711b9309569e3d9bc6ac + languageName: node + linkType: hard + +"@react-email/container@npm:0.0.10": + version: 0.0.10 + resolution: "@react-email/container@npm:0.0.10" + peerDependencies: + react: 18.2.0 + checksum: d074fad448f6033d232b890b9d1a9914d0f92908ba494feaa627828718f4fa6e639636f239eb8eeb8b597c220da9019e90cb72ee2b0328c2ec908fd73e48fc13 + languageName: node + linkType: hard + +"@react-email/font@npm:0.0.4": + version: 0.0.4 + resolution: "@react-email/font@npm:0.0.4" + peerDependencies: + react: 18.2.0 + checksum: 066a0016fa78267c83665d5e3846421f7d787361b11f4e712bd32353d0de947a72a42036fdfd35b75eff479ca77deba0f5c220bee43ace8594f7c6345c30a0bc + languageName: node + linkType: hard + +"@react-email/head@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/head@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: aa2362c965c6f1fa2bcd41be04c1ce8695864153768b4ba4f4b102dd1e1adb28ba067c54f71ded592799aacfa348813cae0f442797b3448bb87feb4588443546 + languageName: node + linkType: hard + +"@react-email/heading@npm:0.0.9": + version: 0.0.9 + resolution: "@react-email/heading@npm:0.0.9" + dependencies: + "@radix-ui/react-slot": "npm:1.0.2" + react: "npm:18.2.0" + checksum: d082d2a4d3db312cbaa0d62419cc1b29c6b6c3ee1467a220c97c9cb009be1af5f6409370b9caac054d8aee8d326fb6e894a72073ff429f05ed097ba471e12a43 + languageName: node + linkType: hard + +"@react-email/hr@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/hr@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: b965c176192a06b39d2c696a8b747cdf4060ba7229a7d45eaf1d5729c59920fefe90f43fbc5f8d203a8e5d77645ee62745d06ec5ec5c9b030815f0642a8ac4ab + languageName: node + linkType: hard + +"@react-email/html@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/html@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: 9046476ccb20e405a64e33ca3a80f1ed7645bacec0601001fd36efd95497a5999daebf0ad141f0c08387190582e23ff2b2f7fc536461ec9b27d0b397a311fe4f + languageName: node + linkType: hard + +"@react-email/img@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/img@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: 046f0b60bdf9c7c04a2033b39967de96e31ffedae8922f9f187ce39f6040deee33f02e5695f56c26cf1691cce7de937bcbd303c3804b9a824d0aabc71427a462 + languageName: node + linkType: hard + +"@react-email/link@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/link@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: 3e5eb2e222abe99bdcec6127a20d4ac8ed584189527a2bced119b09d08625b74f0ffa8a1de009974b4cd47249ade4081e108ca4fd65daa0ca811a7c6058cf838 + languageName: node + linkType: hard + +"@react-email/preview@npm:0.0.7": + version: 0.0.7 + resolution: "@react-email/preview@npm:0.0.7" + peerDependencies: + react: 18.2.0 + checksum: 9125597760e69d36b9caf1a94595913f52364642351728a5ff91b7d97fce26fad74bae5f1c9baade8831f4154d4c88c773adcbc1f9f1d602b4113c50bf21eb30 + languageName: node + linkType: hard + +"@react-email/render@npm:0.0.10": + version: 0.0.10 + resolution: "@react-email/render@npm:0.0.10" + dependencies: + html-to-text: "npm:9.0.5" + pretty: "npm:2.0.0" + react: "npm:18.2.0" + react-dom: "npm:18.2.0" + checksum: ea0db578ef58734160ac512d04de5b09f558d192fbb74c0b9bdb3006e91d0d73ee7d77007f4740bef0d587f8b231f8dba5ef01e16e18d2deb37859ddd2e7d09a + languageName: node + linkType: hard + +"@react-email/render@npm:0.0.9": + version: 0.0.9 + resolution: "@react-email/render@npm:0.0.9" + dependencies: + html-to-text: "npm:9.0.5" + pretty: "npm:2.0.0" + react: "npm:18.2.0" + react-dom: "npm:18.2.0" + checksum: 128b3a7c65e77a14600e48fb24183e182de82b4ddc8ff11bb239c421fa68bd6eb8b063822b5abe9f8599e34ece315cdb961b4133c59285cebcc517d2ec0ae8da + languageName: node + linkType: hard + +"@react-email/row@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/row@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: ca1d92094a5ccc35c93560538311c38989162e9f0235a71897296bc43f2c0ba31d53df9c7db1688f7be0d77ccc03a0094cc227c4d095787f3b3ea0c3d262e520 + languageName: node + linkType: hard + +"@react-email/section@npm:0.0.10": + version: 0.0.10 + resolution: "@react-email/section@npm:0.0.10" + peerDependencies: + react: 18.2.0 + checksum: d1af5dc3ff9a5bd2675a82f976df79ab5acded5ca305536df36ad84440b3828b021f8026d721e34fe92853bc3dfe8b9aa4603c25bf2f901b22049748ed6a7fbc + languageName: node + linkType: hard + +"@react-email/tailwind@npm:0.0.13": + version: 0.0.13 + resolution: "@react-email/tailwind@npm:0.0.13" + dependencies: + react: "npm:18.2.0" + react-dom: "npm:18.2.0" + peerDependencies: + react: 18.2.0 + checksum: 5980a8593b699e9a0e0a8178120d206e74ccb525ba5fedb02e7048f8efff7ca41f82308584624a9701dc021d2ccfd8fa224f11a191d78e567a77f8d35bd47bb4 + languageName: node + linkType: hard + +"@react-email/text@npm:0.0.6": + version: 0.0.6 + resolution: "@react-email/text@npm:0.0.6" + peerDependencies: + react: 18.2.0 + checksum: 1e960838bfe81bf33b42db1aa1d84446fc36911b4d9e9a79570d9a43fe9cc29d9271f7e1b25448383d8fe950a73130f8bed5c65cd8dbc786a2e6fe02e0c16202 + languageName: node + linkType: hard + "@react-hook/debounce@npm:^3.0.0": version: 3.0.0 resolution: "@react-hook/debounce@npm:3.0.0" @@ -19889,7 +20095,18 @@ __metadata: languageName: node linkType: hard -"config-chain@npm:^1.1.11": +"condense-newlines@npm:^0.2.1": + version: 0.2.1 + resolution: "condense-newlines@npm:0.2.1" + dependencies: + extend-shallow: "npm:^2.0.1" + is-whitespace: "npm:^0.3.0" + kind-of: "npm:^3.0.2" + checksum: 19485db92a5d4658b50ab250626ece0cebe57f73af126b348604309894ed9a2b05f88f1802a090fd1897156eda0af69d8f14446bc62f978e0d048b5135e91694 + languageName: node + linkType: hard + +"config-chain@npm:^1.1.11, config-chain@npm:^1.1.13": version: 1.1.13 resolution: "config-chain@npm:1.1.13" dependencies: @@ -21842,6 +22059,20 @@ __metadata: languageName: node linkType: hard +"editorconfig@npm:^1.0.3": + version: 1.0.4 + resolution: "editorconfig@npm:1.0.4" + dependencies: + "@one-ini/wasm": "npm:0.1.1" + commander: "npm:^10.0.0" + minimatch: "npm:9.0.1" + semver: "npm:^7.5.3" + bin: + editorconfig: bin/editorconfig + checksum: ed6985959d7b34a56e1c09bef118758c81c969489b768d152c93689fce8403b0452462e934f665febaba3478eebc0fd41c0a36100783eaadf6d926c4abc87a3d + languageName: node + linkType: hard + "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -24670,7 +24901,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.0.0, glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.0.0, glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.3, glob@npm:^10.3.7": version: 10.3.10 resolution: "glob@npm:10.3.10" dependencies: @@ -27074,7 +27305,7 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^1.1.0": +"is-buffer@npm:^1.1.0, is-buffer@npm:^1.1.5": version: 1.1.6 resolution: "is-buffer@npm:1.1.6" checksum: ae18aa0b6e113d6c490ad1db5e8df9bdb57758382b313f5a22c9c61084875c6396d50bbf49315f5b1926d142d74dfb8d31b40d993a383e0a158b15fea7a82234 @@ -27635,6 +27866,13 @@ __metadata: languageName: node linkType: hard +"is-whitespace@npm:^0.3.0": + version: 0.3.0 + resolution: "is-whitespace@npm:0.3.0" + checksum: 2f4ef13e0195170bbb587437133ef81ed9d6aec1c5e88f4c2b9055a18a1e70f75d9a9376f0cdae64f3c519e05e5f734d6b8f9682e5cb50384843480bade785ae + languageName: node + linkType: hard + "is-windows@npm:^0.2.0": version: 0.2.0 resolution: "is-windows@npm:0.2.0" @@ -28608,6 +28846,22 @@ __metadata: languageName: node linkType: hard +"js-beautify@npm:^1.6.12": + version: 1.14.11 + resolution: "js-beautify@npm:1.14.11" + dependencies: + config-chain: "npm:^1.1.13" + editorconfig: "npm:^1.0.3" + glob: "npm:^10.3.3" + nopt: "npm:^7.2.0" + bin: + css-beautify: js/bin/css-beautify.js + html-beautify: js/bin/html-beautify.js + js-beautify: js/bin/js-beautify.js + checksum: 23267f8e68a4cf190274906fbec98c4fa44025e1b7e1fa701480867c9ab6b2b90a1bb2b358cd487c34d735a1039c16bcb51f82d390bcc6384172cc540aa11c9b + languageName: node + linkType: hard + "js-cookie@npm:^2.2.1": version: 2.2.1 resolution: "js-cookie@npm:2.2.1" @@ -29167,6 +29421,15 @@ __metadata: languageName: node linkType: hard +"kind-of@npm:^3.0.2": + version: 3.2.2 + resolution: "kind-of@npm:3.2.2" + dependencies: + is-buffer: "npm:^1.1.5" + checksum: 7e34bc29d4b02c997f92f080de34ebb92033a96736bbb0bb2410e033a7e5ae6571f1fa37b2d7710018f95361473b816c604234197f4f203f9cf149d8ef1574d9 + languageName: node + linkType: hard + "kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -32285,6 +32548,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:9.0.1": + version: 9.0.1 + resolution: "minimatch@npm:9.0.1" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: aa043eb8822210b39888a5d0d28df0017b365af5add9bd522f180d2a6962de1cbbf1bdeacdb1b17f410dc3336bc8d76fb1d3e814cdc65d00c2f68e01f0010096 + languageName: node + linkType: hard + "minimatch@npm:9.0.3, minimatch@npm:^9.0.0, minimatch@npm:^9.0.1": version: 9.0.3 resolution: "minimatch@npm:9.0.3" @@ -33222,7 +33494,7 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^7.0.0": +"nopt@npm:^7.0.0, nopt@npm:^7.2.0": version: 7.2.0 resolution: "nopt@npm:7.2.0" dependencies: @@ -35916,6 +36188,17 @@ __metadata: languageName: node linkType: hard +"pretty@npm:2.0.0": + version: 2.0.0 + resolution: "pretty@npm:2.0.0" + dependencies: + condense-newlines: "npm:^0.2.1" + extend-shallow: "npm:^2.0.1" + js-beautify: "npm:^1.6.12" + checksum: 2fcd72f331d0afae3893ba88a5c05f6fdd62b059cb309028aa3309fc8a90410d81dfe66ae95677bc6d6d4a68f3cc1a247c13e5872bd35686f99acb33acc51164 + languageName: node + linkType: hard + "prettyjson@npm:^1.2.1": version: 1.2.5 resolution: "prettyjson@npm:1.2.5" @@ -36728,7 +37011,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.2.0": +"react-dom@npm:18.2.0, react-dom@npm:^18.2.0": version: 18.2.0 resolution: "react-dom@npm:18.2.0" dependencies: @@ -37263,7 +37546,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^18, react@npm:^18.2.0": +"react@npm:18.2.0, react@npm:^18, react@npm:^18.2.0": version: 18.2.0 resolution: "react@npm:18.2.0" dependencies: @@ -41529,6 +41812,8 @@ __metadata: "@octokit/graphql": "npm:^7.0.2" "@ptc-org/nestjs-query-core": "npm:^4.2.0" "@ptc-org/nestjs-query-typeorm": "npm:4.2.1-alpha.2" + "@react-email/components": "npm:0.0.12" + "@react-email/render": "npm:0.0.10" "@sentry/node": "npm:^7.66.0" "@sentry/profiling-node": "npm:^1.2.6" "@sentry/react": "npm:^7.88.0"