diff --git a/apps/frontend/nuxt.config.ts b/apps/frontend/nuxt.config.ts index ab532a20..e2d9bfe1 100644 --- a/apps/frontend/nuxt.config.ts +++ b/apps/frontend/nuxt.config.ts @@ -1,6 +1,7 @@ import { pathToFileURL } from 'node:url' import { match as matchLocale } from '@formatjs/intl-localematcher' +import serverSidedVue from '@vitejs/plugin-vue' import { consola } from 'consola' import { promises as fs } from 'fs' import { globIterate } from 'glob' @@ -111,6 +112,17 @@ export default defineNuxtConfig({ ], }, hooks: { + async 'nitro:config'(nitroConfig) { + const emailTemplates = Object.keys( + await import('./src/emails/index.ts').then((m) => m.default), + ) + + nitroConfig.prerender = nitroConfig.prerender || {} + nitroConfig.prerender.routes = nitroConfig.prerender.routes || [] + for (const template of emailTemplates) { + nitroConfig.prerender.routes.push(`/email/${template}`) + } + }, async 'build:before'() { // 30 minutes const TTL = 30 * 60 * 1000 @@ -435,6 +447,10 @@ export default defineNuxtConfig({ }, nitro: { moduleSideEffects: ['@vintl/compact-number/locale-data'], + rollupConfig: { + // @ts-expect-error it's not infinite. + plugins: [serverSidedVue()], + }, }, devtools: { enabled: true, @@ -453,6 +469,13 @@ export default defineNuxtConfig({ 'Critical-CH': 'Sec-CH-Prefers-Color-Scheme', }, }, + '/email/**': { + prerender: true, + headers: { + 'Content-Type': 'text/html', + 'Cache-Control': 'public, max-age=3600', + }, + }, }, compatibilityDate: '2024-07-03', telemetry: false, diff --git a/apps/frontend/package.json b/apps/frontend/package.json index a4c0fe7f..e4fe68a1 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -45,6 +45,9 @@ "@pinia/nuxt": "^0.5.1", "@types/three": "^0.172.0", "@vintl/vintl": "^4.4.1", + "@vitejs/plugin-vue": "^5.0.4", + "@vue-email/components": "^0.0.21", + "@vue-email/render": "^0.0.9", "@vueuse/core": "^11.1.0", "ace-builds": "^1.36.2", "ansi-to-html": "^0.7.2", diff --git a/apps/frontend/src/emails/index.ts b/apps/frontend/src/emails/index.ts new file mode 100644 index 00000000..d3ad463c --- /dev/null +++ b/apps/frontend/src/emails/index.ts @@ -0,0 +1,34 @@ +import type { Component } from 'vue' + +export default { + // Account + 'auth-method-added': () => import('./templates/account/AuthenticationMethodAdded.vue'), + 'auth-method-removed': () => import('./templates/account/AuthenticationMethodRemoved.vue'), + 'email-changed': () => import('./templates/account/EmailChanged.vue'), + 'password-changed': () => import('./templates/account/PasswordChanged.vue'), + 'password-removed': () => import('./templates/account/PasswordRemoved.vue'), + 'payment-failed': () => import('./templates/account/PaymentFailed.vue'), + 'reset-password': () => import('./templates/account/ResetPassword.vue'), + 'two-factor-added': () => import('./templates/account/TwoFactorAdded.vue'), + 'two-factor-removed': () => import('./templates/account/TwoFactorRemoved.vue'), + 'verify-email': () => import('./templates/account/VerifyEmail.vue'), + 'login-new-device': () => import('./templates/account/LoginNewDevice.vue'), + 'payout-available': () => import('./templates/account/PayoutAvailable.vue'), + 'personal-access-token-created': () => import('./templates/account/PATCreated.vue'), + + // Moderation + 'report-submitted': () => import('./templates/moderation/ReportSubmitted.vue'), + 'report-status-updated': () => import('./templates/moderation/ReportStatusUpdated.vue'), + 'moderation-thread-message-received': () => + import('./templates/moderation/ModerationThreadMessageReceived.vue'), + + // Project + 'project-status-updated-neutral': () => + import('./templates/project/ProjectStatusUpdatedNeutral.vue'), + 'project-status-approved': () => import('./templates/project/ProjectStatusApproved.vue'), + 'project-invited': () => import('./templates/project/ProjectInvited.vue'), + 'project-transferred': () => import('./templates/project/ProjectTransferred.vue'), + + // Organization + 'organization-invited': () => import('./templates/organization/OrganizationInvited.vue'), +} as Record Promise<{ default: Component }>> diff --git a/apps/frontend/src/emails/shared/StyledEmail.vue b/apps/frontend/src/emails/shared/StyledEmail.vue new file mode 100644 index 00000000..17ea1063 --- /dev/null +++ b/apps/frontend/src/emails/shared/StyledEmail.vue @@ -0,0 +1,239 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/AuthenticationMethodAdded.vue b/apps/frontend/src/emails/templates/account/AuthenticationMethodAdded.vue new file mode 100644 index 00000000..a2f33741 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/AuthenticationMethodAdded.vue @@ -0,0 +1,26 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/AuthenticationMethodRemoved.vue b/apps/frontend/src/emails/templates/account/AuthenticationMethodRemoved.vue new file mode 100644 index 00000000..591ef28f --- /dev/null +++ b/apps/frontend/src/emails/templates/account/AuthenticationMethodRemoved.vue @@ -0,0 +1,26 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/EmailChanged.vue b/apps/frontend/src/emails/templates/account/EmailChanged.vue new file mode 100644 index 00000000..76fd3a49 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/EmailChanged.vue @@ -0,0 +1,26 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/LoginNewDevice.vue b/apps/frontend/src/emails/templates/account/LoginNewDevice.vue new file mode 100644 index 00000000..96a6dd4f --- /dev/null +++ b/apps/frontend/src/emails/templates/account/LoginNewDevice.vue @@ -0,0 +1,79 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/PATCreated.vue b/apps/frontend/src/emails/templates/account/PATCreated.vue new file mode 100644 index 00000000..c9556426 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/PATCreated.vue @@ -0,0 +1,27 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/PasswordChanged.vue b/apps/frontend/src/emails/templates/account/PasswordChanged.vue new file mode 100644 index 00000000..dc62cd65 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/PasswordChanged.vue @@ -0,0 +1,23 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/PasswordRemoved.vue b/apps/frontend/src/emails/templates/account/PasswordRemoved.vue new file mode 100644 index 00000000..59b7c1fc --- /dev/null +++ b/apps/frontend/src/emails/templates/account/PasswordRemoved.vue @@ -0,0 +1,27 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/PaymentFailed.vue b/apps/frontend/src/emails/templates/account/PaymentFailed.vue new file mode 100644 index 00000000..1560cb2e --- /dev/null +++ b/apps/frontend/src/emails/templates/account/PaymentFailed.vue @@ -0,0 +1,33 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/PayoutAvailable.vue b/apps/frontend/src/emails/templates/account/PayoutAvailable.vue new file mode 100644 index 00000000..1a2b79cc --- /dev/null +++ b/apps/frontend/src/emails/templates/account/PayoutAvailable.vue @@ -0,0 +1,43 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/ResetPassword.vue b/apps/frontend/src/emails/templates/account/ResetPassword.vue new file mode 100644 index 00000000..42258984 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/ResetPassword.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/TwoFactorAdded.vue b/apps/frontend/src/emails/templates/account/TwoFactorAdded.vue new file mode 100644 index 00000000..1a65d9ee --- /dev/null +++ b/apps/frontend/src/emails/templates/account/TwoFactorAdded.vue @@ -0,0 +1,26 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/TwoFactorRemoved.vue b/apps/frontend/src/emails/templates/account/TwoFactorRemoved.vue new file mode 100644 index 00000000..3b43cc10 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/TwoFactorRemoved.vue @@ -0,0 +1,27 @@ + + + diff --git a/apps/frontend/src/emails/templates/account/VerifyEmail.vue b/apps/frontend/src/emails/templates/account/VerifyEmail.vue new file mode 100644 index 00000000..30697ee0 --- /dev/null +++ b/apps/frontend/src/emails/templates/account/VerifyEmail.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/frontend/src/emails/templates/moderation/ModerationThreadMessageReceived.vue b/apps/frontend/src/emails/templates/moderation/ModerationThreadMessageReceived.vue new file mode 100644 index 00000000..d7383f02 --- /dev/null +++ b/apps/frontend/src/emails/templates/moderation/ModerationThreadMessageReceived.vue @@ -0,0 +1,58 @@ + + + diff --git a/apps/frontend/src/emails/templates/moderation/ReportStatusUpdated.vue b/apps/frontend/src/emails/templates/moderation/ReportStatusUpdated.vue new file mode 100644 index 00000000..4821441c --- /dev/null +++ b/apps/frontend/src/emails/templates/moderation/ReportStatusUpdated.vue @@ -0,0 +1,43 @@ + + + diff --git a/apps/frontend/src/emails/templates/moderation/ReportSubmitted.vue b/apps/frontend/src/emails/templates/moderation/ReportSubmitted.vue new file mode 100644 index 00000000..7e7cdf5c --- /dev/null +++ b/apps/frontend/src/emails/templates/moderation/ReportSubmitted.vue @@ -0,0 +1,51 @@ + + + diff --git a/apps/frontend/src/emails/templates/organization/OrganizationInvited.vue b/apps/frontend/src/emails/templates/organization/OrganizationInvited.vue new file mode 100644 index 00000000..e284de9f --- /dev/null +++ b/apps/frontend/src/emails/templates/organization/OrganizationInvited.vue @@ -0,0 +1,75 @@ + + + diff --git a/apps/frontend/src/emails/templates/project/ProjectInvited.vue b/apps/frontend/src/emails/templates/project/ProjectInvited.vue new file mode 100644 index 00000000..cc901710 --- /dev/null +++ b/apps/frontend/src/emails/templates/project/ProjectInvited.vue @@ -0,0 +1,70 @@ + + + diff --git a/apps/frontend/src/emails/templates/project/ProjectStatusApproved.vue b/apps/frontend/src/emails/templates/project/ProjectStatusApproved.vue new file mode 100644 index 00000000..cb840f72 --- /dev/null +++ b/apps/frontend/src/emails/templates/project/ProjectStatusApproved.vue @@ -0,0 +1,56 @@ + + + diff --git a/apps/frontend/src/emails/templates/project/ProjectStatusUpdatedNeutral.vue b/apps/frontend/src/emails/templates/project/ProjectStatusUpdatedNeutral.vue new file mode 100644 index 00000000..f26b8d98 --- /dev/null +++ b/apps/frontend/src/emails/templates/project/ProjectStatusUpdatedNeutral.vue @@ -0,0 +1,62 @@ + + + diff --git a/apps/frontend/src/emails/templates/project/ProjectTransferred.vue b/apps/frontend/src/emails/templates/project/ProjectTransferred.vue new file mode 100644 index 00000000..f63b7922 --- /dev/null +++ b/apps/frontend/src/emails/templates/project/ProjectTransferred.vue @@ -0,0 +1,60 @@ + + + diff --git a/apps/frontend/src/pages/admin/emails.vue b/apps/frontend/src/pages/admin/emails.vue new file mode 100644 index 00000000..c7b86399 --- /dev/null +++ b/apps/frontend/src/pages/admin/emails.vue @@ -0,0 +1,129 @@ + + + diff --git a/apps/frontend/src/public/robots.txt b/apps/frontend/src/public/robots.txt index eb053628..9c46f4a3 100644 --- a/apps/frontend/src/public/robots.txt +++ b/apps/frontend/src/public/robots.txt @@ -1,2 +1,2 @@ User-agent: * -Disallow: +Disallow: /email/ diff --git a/apps/frontend/src/server/routes/email/[template].ts b/apps/frontend/src/server/routes/email/[template].ts new file mode 100644 index 00000000..dce301d0 --- /dev/null +++ b/apps/frontend/src/server/routes/email/[template].ts @@ -0,0 +1,28 @@ +import { render } from '@vue-email/render' +import type { Component } from 'vue' + +import emails from '~/emails' + +export default defineEventHandler(async (event) => { + const template = event.context.params?.template as string + try { + const component = (await emails[template]()).default as Component | undefined + + if (!component) { + throw createError({ + statusCode: 404, + message: 'Email template not found', + }) + } + + const html = await render(component, {}) + + return html + } catch (error) { + console.error(`Error rendering email template ${template}:`, error) + throw createError({ + statusCode: 500, + message: 'Failed to render email template', + }) + } +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f49ee444..09465eff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -242,6 +242,15 @@ importers: '@vintl/vintl': specifier: ^4.4.1 version: 4.4.1(typescript@5.5.4)(vue@3.5.13(typescript@5.5.4)) + '@vitejs/plugin-vue': + specifier: ^5.0.4 + version: 5.2.1(vite@5.4.11(@types/node@20.14.11)(sass@1.77.6)(terser@5.43.1))(vue@3.5.13(typescript@5.5.4)) + '@vue-email/components': + specifier: ^0.0.21 + version: 0.0.21(typescript@5.5.4)(vue@3.5.13(typescript@5.5.4)) + '@vue-email/render': + specifier: ^0.0.9 + version: 0.0.9(typescript@5.5.4) '@vueuse/core': specifier: ^11.1.0 version: 11.1.0(vue@3.5.13(typescript@5.5.4)) @@ -2039,6 +2048,9 @@ packages: peerDependencies: vue: ^3.3.4 + '@one-ini/wasm@0.1.1': + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} @@ -2472,6 +2484,9 @@ packages: cpu: [x64] os: [win32] + '@selderee/plugin-htmlparser2@0.11.0': + resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + '@sentry-internal/browser-utils@8.27.0': resolution: {integrity: sha512-YTIwQ1GM1NTRXgN4DvpFSQ2x4pjlqQ0FQAyHW5x2ZYv4z7VmqG4Xkid1P/srQUipECk6nxkebfD4WR19nLsvnQ==} engines: {node: '>=14.18'} @@ -3046,6 +3061,116 @@ packages: '@vscode/l10n@0.0.18': resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + '@vue-email/body@0.0.3': + resolution: {integrity: sha512-JxZb1upJTnt6tLKszqHfrCWTpioWuG7eZXneUmCBr0YVt6gI781dSAgUQASTBprENnO+M2sNsarszoo7jGZNOQ==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/button@0.0.3': + resolution: {integrity: sha512-Su1iKBpfzF03SqLhxxIGDm2ZgpnXh+yD8kvLQ9+V0COepXOSdVQD5Ovif14uKGweafXSMkyQSi5lqmnVIace3A==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/code-block@0.0.3': + resolution: {integrity: sha512-NuOAY3dhWCwnywQ9lguLWqh+2BDKr1UM7AkV/ejDJwfX/GLZnlN9EEJRYOVhFnGwXOcJnS27NmvjZHaRweZfWA==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/code-inline@0.0.3': + resolution: {integrity: sha512-FN9WPQBwWWumpPIAN/++oly9/hpUfioVokb7nfM/U0hEOS3mGsVjYPZNiX/oGOAHrAF83qOqgIFcd9ipVMtefg==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/column@0.0.3': + resolution: {integrity: sha512-L1tYu3ZqoqcSNa5GK8wEKQKuvUBlsWeSA3RqKlkLrc+dR+uitcyCcbYsoE/N2tgvzZ1poykE/S6VIcrqH/zL9A==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/components@0.0.21': + resolution: {integrity: sha512-xtL9vdWgBpq2B4OqbOvW9s9+5fF8bZamNHCBNYkFMzGg7Ne+SWk/vZI0LhCeMqWUkodnCvCoW/i7IYGjw5veHw==} + engines: {node: '>=18.0.0'} + peerDependencies: + vue: ^3.4.29 + + '@vue-email/container@0.0.3': + resolution: {integrity: sha512-L+9VZ3RbCgyPaV54QCQsOAe9lAvq549JULEmH3QRDgHsIaFE3Yaddc1zMJKdbwH7ugiaRPRFrM2paR57IS6sWw==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/font@0.0.3': + resolution: {integrity: sha512-X9vwUTKjPeFuh06BkYbFVM3rdZggLo7hJ3SHgJ09qBF7e0J7zZx5KLjkeYzKTWfHlM1fx9XtNdpQ35UKyIpwUg==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/head@0.0.3': + resolution: {integrity: sha512-RobskTPhRQ18aHFcwOe1eorGDd3BCotXJy2YfZF9VRHvw1MtV5M/AQ0eqUUgnNuNrxFGobZtxZJMu4+EE2ToUQ==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/heading@0.0.3': + resolution: {integrity: sha512-cUxlLDuRHEdLn+CZWehsUuJjWNnDVC1LAK1iKtZl++J9xGE1l4lrxaBFdhIZctH2yoZZLGm8OHvUJiYrke9YIg==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/hr@0.0.3': + resolution: {integrity: sha512-DNSi4CrsgRJRstTIB8ILcCqg0rWIIMKZ1fmSVgHoEBfgiV9I4m/6wKv2Rzg1AxkYldy5w1YhwVx0NfBTCHlL7A==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/html@0.0.3': + resolution: {integrity: sha512-kjUBwwWcgNoJ6jEmZW7gkdSXZzy6rcJ0jV4507TZlF6PRsu4FaCpeI6WHnDexdXIfCeAIwZqeAQOJHASHJd2mw==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/img@0.0.3': + resolution: {integrity: sha512-lFDavbzdbOXo2VK8Fq/YPFB/2ZolOaToC/oFR9fQlw2hA9n1TTiEZZK5D7en62FSD9gPG1P7eQ81tOt6/Tc6+A==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/link@0.0.3': + resolution: {integrity: sha512-AvX5wxXACrxqyLaooIDQBsz/8Q6FDSVGDg0Lo1opUZKEW80s68zI+FUhI3kuByVEogzIhfdpq9rc1yGmkUUh8A==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/markdown@0.0.7': + resolution: {integrity: sha512-AxMpxo0A20lFiED7l1nJy6Y+fDYHknYW6u1HZ7F2QbDUihtinwAWU9pBFDX9SSHg9Ihkf3KeitvGf4YHiYlXRA==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/preview@0.0.3': + resolution: {integrity: sha512-e9qLDsP5+f5KZQhiVGjI/d/x5NfLfYusjI9C4bewwXM6bYJo1i5WRRzX6SM7sygKEk0ZbKqnzPqbnSWtABuzDw==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/render@0.0.9': + resolution: {integrity: sha512-FShvnLSoys3y+30uIO4ZuBSsXKGaj/VOB+CfNxhgxLmFsLbwKwUZQgJVAmXviuuSC5xpWQCOEPQ8P7oEEYa0WA==} + engines: {node: '>=18.0.0'} + + '@vue-email/row@0.0.3': + resolution: {integrity: sha512-/wnkRMFJl5WTehD3/ryn7taJs42Vk7K1xUH37Q5R5T8tu1lBnAhwWcDvUeqaH/7+N4weELEBjQdKa9F6fqYlcA==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/section@0.0.3': + resolution: {integrity: sha512-DPvDBmf3jPZGw8ZoIgs/lS3yt8H0BXMLniR0aTa6FhBPWJsXXaaQHDPY6h7jfeCgppgAoDRLZqiMnZXfqSTUWw==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/style@0.0.3': + resolution: {integrity: sha512-1t1I1EFJ77N4AC0qb1WYUfSOsFXTUUR2gxnbg88dsXHiaMiBlyokqy50wnn4/FrubUqbOFmseCz+4nSZzGg5bA==} + peerDependencies: + vue: ^3.4.27 + + '@vue-email/tailwind@0.2.0': + resolution: {integrity: sha512-/DNEMhvEuZa9OptICLelwh4Rh4Lh54GtoTkQgCAV0/4qvAgbAmjUMr0f7GsincdxoPrFwpTofaKAxMFm6ZO0xA==} + peerDependencies: + vue: ^3.4.29 + + '@vue-email/text@0.0.3': + resolution: {integrity: sha512-xn6MYicnXyFeV72nNTDZylOL7ut60clYUR2bqMDKkW6+XD6qWp6LGAx4b8sE0kADgu7MTq23zbU9kA/cebhk8w==} + peerDependencies: + vue: ^3.4.27 + '@vue-macros/common@1.15.0': resolution: {integrity: sha512-yg5VqW7+HRfJGimdKvFYzx8zorHUYo0hzPwuraoC1DWa7HHazbTMoVsHDvk3JHa1SGfSL87fRnzmlvgjEHhszA==} engines: {node: '>=16.14.0'} @@ -3226,6 +3351,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -3733,6 +3862,9 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} @@ -4097,6 +4229,11 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -4897,12 +5034,19 @@ packages: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} + html-to-text@9.0.5: + resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} + engines: {node: '>=14'} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} html-whitespace-sensitive-tag-names@3.0.0: resolution: {integrity: sha512-KlClZ3/Qy5UgvpvVvDomGhnQhNWH5INE8GwvSIQ9CWt1K0zbbXrl7eN5bWaafOZgtmO3jMPwUqmrmEwinhPq1w==} + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} @@ -5174,6 +5318,15 @@ packages: resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} hasBin: true + js-beautify@1.15.4: + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} + hasBin: true + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} @@ -5287,6 +5440,9 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} + leac@0.6.0: + resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -5413,6 +5569,11 @@ packages: markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + marked@7.0.4: + resolution: {integrity: sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==} + engines: {node: '>= 16'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -5663,6 +5824,10 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} + minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -5813,6 +5978,11 @@ packages: engines: {node: '>=6'} hasBin: true + nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -6026,6 +6196,9 @@ packages: parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + parseley@0.12.1: + resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -6073,6 +6246,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + peberminta@0.9.0: + resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} @@ -6484,6 +6660,9 @@ packages: property-information@7.0.0: resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protocols@2.0.1: resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} @@ -6799,6 +6978,9 @@ packages: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} engines: {node: '>=4'} + selderee@0.11.0: + resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -9834,6 +10016,8 @@ snapshots: - vti - vue-tsc + '@one-ini/wasm@0.1.1': {} + '@oslojs/encoding@1.1.0': {} '@pagefind/darwin-arm64@1.3.0': @@ -10189,6 +10373,11 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.34.9': optional: true + '@selderee/plugin-htmlparser2@0.11.0': + dependencies: + domhandler: 5.0.3 + selderee: 0.11.0 + '@sentry-internal/browser-utils@8.27.0': dependencies: '@sentry/core': 8.27.0 @@ -10973,6 +11162,123 @@ snapshots: '@vscode/l10n@0.0.18': {} + '@vue-email/body@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/button@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/code-block@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + shiki: 1.29.2 + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/code-inline@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/column@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/components@0.0.21(typescript@5.5.4)(vue@3.5.13(typescript@5.5.4))': + dependencies: + '@vue-email/body': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/button': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/code-block': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/code-inline': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/column': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/container': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/font': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/head': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/heading': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/hr': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/html': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/img': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/link': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/markdown': 0.0.7(vue@3.5.13(typescript@5.5.4)) + '@vue-email/preview': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/render': 0.0.9(typescript@5.5.4) + '@vue-email/row': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/section': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/style': 0.0.3(vue@3.5.13(typescript@5.5.4)) + '@vue-email/tailwind': 0.2.0(vue@3.5.13(typescript@5.5.4)) + '@vue-email/text': 0.0.3(vue@3.5.13(typescript@5.5.4)) + vue: 3.5.13(typescript@5.5.4) + transitivePeerDependencies: + - typescript + + '@vue-email/container@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/font@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/head@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/heading@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/hr@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/html@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/img@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/link@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/markdown@0.0.7(vue@3.5.13(typescript@5.5.4))': + dependencies: + marked: 7.0.4 + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/preview@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/render@0.0.9(typescript@5.5.4)': + dependencies: + html-to-text: 9.0.5 + js-beautify: 1.15.4 + vue: 3.5.13(typescript@5.5.4) + transitivePeerDependencies: + - typescript + + '@vue-email/row@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/section@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/style@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/tailwind@0.2.0(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + + '@vue-email/text@0.0.3(vue@3.5.13(typescript@5.5.4))': + dependencies: + vue: 3.5.13(typescript@5.5.4) + '@vue-macros/common@1.15.0(rollup@4.28.1)(vue@3.5.13(typescript@5.5.4))': dependencies: '@babel/types': 7.26.3 @@ -11289,6 +11595,8 @@ snapshots: abbrev@1.1.1: {} + abbrev@2.0.0: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -11890,6 +12198,11 @@ snapshots: confbox@0.2.2: optional: true + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + consola@3.2.3: {} consola@3.4.2: {} @@ -12185,6 +12498,13 @@ snapshots: eastasianwidth@0.2.0: {} + editorconfig@1.0.4: + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.7.2 + ee-first@1.1.1: {} electron-to-chromium@1.5.182: @@ -13391,10 +13711,25 @@ snapshots: html-tags@3.3.1: {} + html-to-text@9.0.5: + dependencies: + '@selderee/plugin-htmlparser2': 0.11.0 + deepmerge: 4.3.1 + dom-serializer: 2.0.0 + htmlparser2: 8.0.2 + selderee: 0.11.0 + html-void-elements@3.0.0: {} html-whitespace-sensitive-tag-names@3.0.0: {} + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + http-cache-semantics@4.1.1: {} http-errors@2.0.0: @@ -13633,6 +13968,16 @@ snapshots: jiti@2.5.1: optional: true + js-beautify@1.15.4: + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.4.2 + js-cookie: 3.0.5 + nopt: 7.2.1 + + js-cookie@3.0.5: {} + js-levenshtein@1.1.6: {} js-tokens@4.0.0: {} @@ -13727,6 +14072,8 @@ snapshots: dependencies: readable-stream: 2.3.8(patch_hash=h52dazg37p4h3yox67pw36akse) + leac@0.6.0: {} + leven@3.1.0: {} levn@0.4.1: @@ -13877,6 +14224,8 @@ snapshots: markdown-table@3.0.3: {} + marked@7.0.4: {} + math-intrinsics@1.1.0: {} mdast-util-definitions@6.0.0: @@ -14406,6 +14755,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@9.0.1: + dependencies: + brace-expansion: 2.0.1 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -14608,6 +14961,10 @@ snapshots: dependencies: abbrev: 1.1.1 + nopt@7.2.1: + dependencies: + abbrev: 2.0.0 + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -14968,6 +15325,11 @@ snapshots: dependencies: entities: 4.5.0 + parseley@0.12.1: + dependencies: + leac: 0.6.0 + peberminta: 0.9.0 + parseurl@1.3.3: {} pascal-case@3.1.2: @@ -15001,6 +15363,8 @@ snapshots: pathe@2.0.3: optional: true + peberminta@0.9.0: {} + perfect-debounce@1.0.0: {} picocolors@1.1.1: {} @@ -15325,6 +15689,8 @@ snapshots: property-information@7.0.0: {} + proto-list@1.2.4: {} + protocols@2.0.1: {} pump@3.0.2: @@ -15794,6 +16160,10 @@ snapshots: extend-shallow: 2.0.1 kind-of: 6.0.3 + selderee@0.11.0: + dependencies: + parseley: 0.12.1 + semver@5.7.2: {} semver@6.3.1: {}