1
0

feat: introduce vue-email for templating with tailwind (#4358)

* feat: start on vue-email set up

* feat: email rendering and base template

* refactor: body slot only

* feat: templates

* fix: lint

* fix: build process

* fix: default import issue

* feat: continue making emails

* feat: update address

* feat: new templates

* feat: email temp page viewer

* fix: lint

* fix: reset password heading

* fix: lint

* fix: qa issues
This commit is contained in:
Calum H.
2025-09-16 16:57:34 +01:00
committed by GitHub
parent 902d749293
commit 8149618187
29 changed files with 1729 additions and 1 deletions

View File

@@ -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,

View File

@@ -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",

View File

@@ -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<string, () => Promise<{ default: Component }>>

View File

@@ -0,0 +1,239 @@
<script setup lang="ts">
import {
Body,
Column,
Container,
Head,
Html,
Img,
Link as VLink,
Row,
Section,
Style,
Tailwind,
Text,
} from '@vue-email/components'
defineProps<{
title?: string
manualLinks?: { link: string; label?: string }[]
}>()
interface SocialLink {
href: string
alt: string
src: string
}
const socialLinks = Object.freeze<readonly SocialLink[]>([
{
href: 'https://discord.modrinth.com',
alt: 'Discord',
src: 'https://cdn-raw.modrinth.com/email/discord.png',
},
{
href: 'https://bsky.app/profile/modrinth.com',
alt: 'Bluesky',
src: 'https://cdn-raw.modrinth.com/email/bluesky.png',
},
{
href: 'https://floss.social/@modrinth',
alt: 'Mastodon',
src: 'https://cdn-raw.modrinth.com/email/mastodon.png',
},
{
href: 'https://x.com/modrinth',
alt: 'X (Twitter)',
src: 'https://cdn-raw.modrinth.com/email/x.png',
},
{
href: 'https://www.instagram.com/modrinth/',
alt: 'Instagram',
src: 'https://cdn-raw.modrinth.com/email/instagram.png',
},
{
href: 'https://www.youtube.com/@modrinth',
alt: 'YouTube',
src: 'https://cdn-raw.modrinth.com/email/youtube.png',
},
{
href: 'https://github.com/modrinth',
alt: 'GitHub',
src: 'https://cdn-raw.modrinth.com/email/github.png',
},
])
</script>
<template>
<Html lang="en">
<Head>
<title>{{ title }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://fonts.googleapis.com/css?family=Inter:700,400"
rel="stylesheet"
type="text/css"
/>
<Style>
/* Outlook.com centering + line-height fixes */ .ExternalClass { width:100%; }
.ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td {
line-height:100%; } table { border-collapse:separate; } a, a:link, a:visited {
text-decoration:none; color:#1f68c0; } a:hover { text-decoration:underline; }
h1,h2,h3,h4,h5,h6 { color:#000 !important; margin:0; mso-line-height-rule:exactly; }
</Style>
</Head>
<Body>
<Tailwind
:config="{
theme: {
extend: {
colors: {
bg: { DEFAULT: '#ebebeb', raised: '#ffffff', super: '#e9e9e9' },
divider: { DEFAULT: '#babfc5', dark: '#c8cdd3' },
base: '#2c2e31',
secondary: '#484d54',
contrast: '#1a202c',
accentContrast: '#ffffff',
red: '#cb2245',
orange: '#e08325',
green: '#00af5c',
blue: '#1f68c0',
purple: '#8e32f3',
gray: '#595b61',
brand: {
DEFAULT: '#00af5c',
highlight: 'rgba(0, 175, 92, 0.25)',
shadow: 'rgba(0, 175, 92, 0.7)',
},
highlight: {
red: 'rgba(203, 34, 69, 0.25)',
orange: 'rgba(224, 131, 37, 0.25)',
green: 'rgba(0, 175, 92, 0.25)',
blue: 'rgba(31, 104, 192, 0.25)',
purple: 'rgba(142, 50, 243, 0.25)',
gray: 'rgba(89, 91, 97, 0.25)',
},
tint: {
red: 'rgba(203, 34, 69, 0.1)',
orange: 'rgba(224, 131, 37, 0.1)',
green: 'rgba(0, 175, 92, 0.1)',
blue: 'rgba(31, 104, 192, 0.1)',
purple: 'rgba(142, 50, 243, 0.1)',
},
link: { DEFAULT: '#1f68c0', hover: '#1f68c0', active: '#1f68c0' },
muted: '#777777',
footerText: '#4d4d4d',
},
fontSize: {
base: ['16px', { lineHeight: '24px' }],
'2xl': ['28px', { lineHeight: '32px' }],
xs: ['13px', { lineHeight: '16px' }],
'2xs': ['11px', { lineHeight: '16px' }],
},
fontFamily: {
sans: ['Inter', 'Arial', 'sans-serif'],
},
},
},
}"
>
<Section class="m-0 pb-0 pl-0 pr-0 pt-0 font-sans">
<Section class="bg-bg pb-4 pl-4 pr-4 pt-4">
<Container class="max-w-[600px]">
<Row>
<Column>
<Img
src="https://cdn.modrinth.com/email/f740e2decee8764a4629bff677a284f9.png"
width="29"
alt=""
class="block h-auto"
/>
</Column>
</Row>
</Container>
</Section>
<Section class="bg-white pb-8 pl-8 pr-8 pt-8">
<Container class="max-w-[600px]">
<slot />
</Container>
</Section>
<Section class="mb-4 bg-bg pb-4 pl-4 pr-4 pt-4">
<Container class="max-w-[600px]">
<Row>
<Column class="align-middle">
<VLink href="https://modrinth.com" aria-label="Modrinth">
<Img
src="https://cdn.modrinth.com/email/bd3357dfae4b1d266250372db3a0988f.png"
width="175"
alt="modrinth logo"
class="block h-auto"
/>
</VLink>
<Row class="text-right align-middle">
<Section class="m-0 inline-block pb-0 pl-0 pr-0 pt-0">
<template v-for="(item, index) in socialLinks" :key="item.href">
<VLink
:href="item.href"
:class="['inline-block', index !== socialLinks.length - 1 ? 'mr-4' : '']"
>
<Img width="20" height="20" :alt="item.alt" :src="item.src" />
</VLink>
</template>
</Section>
</Row>
<Text class="mb-0 mt-2 text-xs" :style="{ color: '#4d4d4d' }"> Rinth, Inc. </Text>
<Section class="m-0 pb-0 pl-0 pr-0 pt-0">
<Text class="m-0 text-xs text-secondary">800 N King St</Text>
<Text class="m-0 text-xs text-secondary">Suite 304 #3133</Text>
<Text class="m-0 text-xs text-secondary">Wilmington, DE 19801</Text>
</Section>
</Column>
</Row>
</Container>
</Section>
<!-- <Text
class="text-footerText text-2xs mb-4 mt-0 pb-0 pl-4 pr-4 pt-0 text-center font-sans"
>
This email was sent to you as a registered user of Modrinth. You can customize the
emails you recieve in your
<VLink href="https://modrinth.com/settings/notifications" class="text-green underline"
>notification settings</VLink
>. Some emails are required to keep your account secure and cannot be disabled.
</Text> -->
<hr />
<Section
v-if="manualLinks && manualLinks.length"
class="text-footerText text-2xs mb-4 mt-4 pb-0 pl-4 pr-4 pt-0 font-sans"
>
<small class="text-muted text-2xs"
>If you're having trouble with the links above, copy and paste these URLs into your
web browser:</small
>
<Text class="text-2xs text-muted mt-0">
<span v-for="(item, index) in manualLinks" :key="index" class="block break-words">
<span v-if="item.label">
<b>{{ item.label }}:</b><br />
</span>
{{ item.link }}
</span>
<!-- <span class="block break-words">
<span> <b>Notification settings:</b><br /> </span>
https://modrinth.com/settings/notifications
</span> -->
</Text>
</Section>
</Section>
</Tailwind>
</Body>
</Html>
</template>

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="New sign-in method added"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> New sign-in method added </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
Your {authprovider.name} account has been connected and you can now use it to sign in to your
Modrinth account.
</Text>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Sign-in method removed"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Sign-in method removed</Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
Your <b>{authprovider.name}</b> account has been disconnected and you can no longer use it to
sign in to your Modrinth account.
</Text>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Your email has been changed"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Your email has been changed </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
At your request, we've successfully updated your Modrinth account's email to
{emailchanged.new_email}.
</Text>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,79 @@
<script setup lang="ts">
import { Column, Heading, Img, Link as VLink, Row, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Sign in from new device"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Sign in from new device </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
We noticed that your account was just signed into from a new device or location. If this was
you, you can safely ignore this email.
</Text>
<Section class="bg-bg-super rounded-lg border border-divider pb-4 pl-4 pr-4 pt-4">
<Row>
<Column class="w-full">
<Row class="mb-2 mt-0">
<Column class="w-8">
<Img
width="20"
height="20"
alt="Time icon"
src="https://cdn-raw.modrinth.com/email/earth.png"
/>
</Column>
<Column>
<Text class="m-0 text-sm font-semibold text-secondary">Approximate location</Text>
<Text class="m-0 text-base">{newdevice.location}</Text>
</Column>
</Row>
<Row class="mb-2">
<Column class="w-8">
<Img
width="20"
height="20"
alt="Time icon"
src="https://cdn-raw.modrinth.com/email/monitor-smartphone.png"
/>
</Column>
<Column>
<Text class="m-0 text-sm font-semibold text-secondary">IP Address</Text>
<Text class="m-0 font-mono text-base">{newdevice.ip}</Text>
</Column>
</Row>
<Row>
<Column class="w-8">
<Img
width="20"
height="20"
alt="Time icon"
src="https://cdn-raw.modrinth.com/email/clock.png"
/>
</Column>
<Column>
<Text class="m-0 text-sm font-semibold text-secondary">Time</Text>
<Text class="m-0 text-base">{time.now}</Text>
</Column>
</Row>
</Column>
</Row>
</Section>
<Text class="text-muted text-base">
If this wasn't you, please update your password and review your account security settings. If
you cannot do this, contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="A new personal access token has been created"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold">
A new personal access token has been created
</Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
A new personal access token, <b>{newpat.token_name}</b>, has been added to your account.
</Text>
<Text class="text-muted text-base">
If you did not create this token, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Your password has been changed"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Your password has been changed </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base"> Your password has been changed on your account. </Text>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Your password has been removed"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Your password has been removed </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
At your request, your password has been removed from your account. You must now use a linked
authentication provider (such as your {passremoved.provider} account) to log into your
Modrinth account.</Text
>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { Button, Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Payment failed for {paymentfailed.service}"
:manual-links="[{ link: '{billing.url}', label: 'Billing settings' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold">
Payment failed for {paymentfailed.service}
</Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
Our attempt to collect payment for {paymentfailed.amount} from the payment card on file was
unsuccessful. Please update your billing settings to avoid suspension of your service.
</Text>
<Button
href="{billing.url}"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
Update billing settings
</Button>
<VLink href="{billing.url}">
<Text class="text-muted mt-2 break-words text-xs font-bold">{billing.url}</Text>
</VLink>
</StyledEmail>
</template>

View File

@@ -0,0 +1,43 @@
<script setup lang="ts">
import { Button, Heading, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Revenue available to withdraw!"
:manual-links="[
{ link: 'https://modrinth.com/dashboard/revenue', label: 'Revenue dashboard' },
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold">Revenue available to withdraw!</Heading>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base">
The ${payout.amount} earned during {payout.period} has been processed and is now available to
withdraw from your account.
</Text>
<Section class="mb-4 mt-4">
<Button
href="https://modrinth.com/dashboard/revenue"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
View revenue dashboard
</Button>
</Section>
<Text class="text-base">
If you have any questions about the creator rewards program, please contact support through
the
<VLink href="https://support.modrinth.com" class="text-green underline">Support Portal</VLink>
or by replying to this email.
</Text>
<Text class="text-base">Thank you for being a creator on Modrinth!</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { Button, Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Reset your password"
:manual-links="[{ link: '{resetpassword.url}', label: 'Password reset link' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Reset your password </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
Please visit the link below to reset your password. If you did not request for your password
to be reset, you can safely ignore this email.
</Text>
<Button
href="{resetpassword.url}"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
Reset password
</Button>
<VLink href="{resetpassword.url}">
<Text class="text-muted mt-2 break-words text-xs font-bold">{resetpassword.url}</Text>
</VLink>
</StyledEmail>
</template>

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Two-factor authentication enabled"
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Two-factor authentication enabled </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
You've secured your account with two-factor authentication. Now, when signing in, you will
need to submit the code generated by your authenticator app.
</Text>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,27 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="You've disabled two-factor authentication security on your account."
:manual-links="[{ link: 'https://support.modrinth.com', label: 'Support Portal' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold">
You've disabled two-factor authentication security on your account.
</Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
At your request, we've removed two-factor authentication from your Modrinth account.
</Text>
<Text class="text-muted text-base">
If you did not make this change, please contact us immediately by replying to this email or
<VLink href="https://support.modrinth.com" class="text-green underline"
>through our Support Portal</VLink
>.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { Button, Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Verify your Modrinth email"
:manual-links="[{ link: '{verifyemail.url}', label: 'Verification link' }]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"> Verify your email </Heading>
<Text class="text-muted text-base">Hi {user.name},</Text>
<Text class="text-muted text-base">
Please visit the link below to verify your email. If the button does not work, you can copy
the link and paste it into your browser. This link expires in 24 hours.
</Text>
<Button
href="{verifyemail.url}"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
Verify email
</Button>
<VLink href="{verifyemail.url}">
<Text class="text-muted mt-2 break-words text-xs font-bold">{verifyemail.url}</Text>
</VLink>
</StyledEmail>
</template>

View File

@@ -0,0 +1,58 @@
<script setup lang="ts">
import { Heading, Img, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="New moderation message"
:manual-links="[
{ link: 'https://modrinth.com/legal/rules', label: 'Community Guidelines' },
{
link: 'https://modrinth.com/project/{project.id}/moderation',
label: 'Your project\'s moderation thread',
},
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Section class="mb-4 mt-2">
<Img
src="{project.icon_url}"
alt="project icon"
width="64"
height="64"
class="block h-auto"
/>
</Section>
<Heading as="h1" class="mb-2 text-2xl font-bold"
>New message from moderators on {project.name}</Heading
>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base">
Modrinth's moderation team has left a message on your project,
<VLink
href="https://modrinth.com/project/{project.id}/moderation"
class="text-green underline"
>{project.name}</VLink
>.
</Text>
<Section class="bg-bg-super mb-4 mt-4 rounded-lg border border-divider pb-4 pl-4 pr-4 pt-4">
<Text class="m-0 text-base">
Please
<VLink
href="https://modrinth.com/project/{project.id}/moderation"
class="text-green underline"
>sign in to view the message</VLink
>
and reply if requested. It's important to address feedback from the moderation team
promptly.
</Text>
</Section>
<Text class="text-base">Thank you for publishing on Modrinth!</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,43 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Report of '{report.title}' has been updated"
:manual-links="[
{ link: 'https://modrinth.com/legal/rules', label: 'Community Guidelines' },
{
link: 'https://modrinth.com/dashboard/report/{report.id}',
label: 'View report in dashboard',
},
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"
>Report of '{report.title}' has been updated</Heading
>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base"
>Your report of {report.title} from {report.date} has been updated by our moderation
team.</Text
>
<Text class="text-base">
You can
<VLink href="https://modrinth.com/dashboard/report/{report.id}" class="text-green underline"
>view the full report thread</VLink
>
to see the update. If you have more information to add, please reply in the report thread for
our moderators to review.
</Text>
<Text class="text-base"
>Thank you for helping keep Modrinth safe and welcoming for everyone.</Text
>
</StyledEmail>
</template>

View File

@@ -0,0 +1,51 @@
<script setup lang="ts">
import { Heading, Link as VLink, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Report of {report.title} has been submitted"
:manual-links="[
{ link: 'https://modrinth.com/legal/rules', label: 'Community Guidelines' },
{
link: 'https://modrinth.com/dashboard/report/{newreport.id}',
label: 'View report in dashboard',
},
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Heading as="h1" class="mb-2 text-2xl font-bold"
>Report of {report.title} has been submitted</Heading
>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base">
We've received your report of {report.title} and our moderation team will review it shortly.
</Text>
<Text class="text-base">
Our team takes all reports seriously and will investigate according to our
<VLink href="https://modrinth.com/legal/rules" class="text-green underline"
>Content Rules</VLink
>, <VLink href="https://modrinth.com/legal/terms">Terms of Service</VLink> and
<VLink href="https://modrinth.com/legal/copyright">Copyright Policy</VLink>. You'll receive an
email update once we've completed our review.
</Text>
<Text class="text-base">
If you have any additional information about this report, you can
<VLink
href="https://modrinth.com/dashboard/report/{newreport.id}"
class="text-green underline"
>view it here</VLink
>.
</Text>
<Text class="text-base">
Thank you for helping keep Modrinth safe and welcoming for everyone.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,75 @@
<script setup lang="ts">
import { Button, Heading, Img, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="You've been invited to an organization"
:manual-links="[
{ link: 'https://modrinth.com/organization/{organization.id}', label: 'Organization page' },
{ link: 'https://modrinth.com/dashboard/notifications', label: 'Notification dashboard' },
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Section class="mb-4 mt-2">
<Img
src="{organization.icon_url}"
alt="organization icon"
width="64"
height="64"
class="block h-auto rounded-lg"
/>
</Section>
<Heading as="h1" class="mb-2 text-2xl font-bold"
>You've been invited to an organization</Heading
>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base"
>Modrinth user
<b
><VLink href="https://modrinth.com/user/{inviter.name}" class="text-green underline">
{inviter.name}
</VLink></b
>
has invited you to join the organization
<b
><VLink
href="https://modrinth.com/organization/{organization.id}"
class="text-green underline"
>
{organization.name}
</VLink></b
>
on Modrinth.
</Text>
<Section class="bg-bg-super mb-4 mt-4 rounded-lg border border-divider pb-4 pl-4 pr-4 pt-4">
<Text class="m-0 text-base">
As an organization member you may gain access to manage projects, teams, members, settings,
and other resources depending on the permissions assigned to you.
</Text>
</Section>
<Button
href="https://modrinth.com/dashboard/notifications"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
Review invitation
</Button>
<Text class="text-base">
If you were not expecting this invitation you should reject it. If you believe this was sent
in error or is abusive, please contact support
<VLink href="https://support.modrinth.com" class="text-green underline">
through the Support Portal</VLink
>
or by replying to this email.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,70 @@
<script setup lang="ts">
import { Button, Heading, Img, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="You've been invited to a project"
:manual-links="[
{ link: 'https://modrinth.com/project/{project.id}', label: 'Project page' },
{ link: 'https://modrinth.com/dashboard/notifications', label: 'Notification dashboard' },
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Section class="mb-4 mt-2">
<Img
src="{project.icon_url}"
alt="project icon"
width="64"
height="64"
class="block h-auto rounded-lg"
/>
</Section>
<Heading as="h1" class="mb-2 text-2xl font-bold">You've been invited to a project</Heading>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base">
Modrinth user
<b
><VLink href="https://modrinth.com/user/{inviter.name}" class="text-green underline">
{inviter.name}
</VLink></b
>
has invited you to join the project
<b>
<VLink href="https://modrinth.com/project/{project.id}" class="text-green underline">
{project.name}
</VLink>
</b>
on Modrinth.
</Text>
<Section class="bg-bg-super mb-4 mt-4 rounded-lg border border-divider pb-4 pl-4 pr-4 pt-4">
<Text class="m-0 text-base">
As a project member you may be able to manage versions, edit project details, configure
settings, and collaborate with other maintainers depending on the permissions assigned to
you.
</Text>
</Section>
<Button
href="https://modrinth.com/dashboard/notifications"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
Review invitation
</Button>
<Text class="text-base">
If you were not expecting this invitation you should reject the invitation. If you believe
this was sent in error or is abusive, please contact support
<VLink href="https://support.modrinth.com" class="text-green underline">
through the Support Portal</VLink
>
or by replying to this email.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,56 @@
<script setup lang="ts">
import { Button, Heading, Img, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Your project, {project.name}, has been approved 🎉"
:manual-links="[
{ link: 'https://modrinth.com/project/{project.id}', label: 'Project page' },
{ link: 'https://modrinth.com/legal/rules', label: 'Community Guidelines' },
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Section class="mb-4 mt-2">
<Img
src="{project.icon_url}"
alt="project icon"
width="64"
height="64"
class="block h-auto rounded-lg"
/>
</Section>
<Heading as="h1" class="mb-2 text-2xl font-bold"
>Your project, {project.name}, has been approved 🎉</Heading
>
<Text class="text-base">Congratulations {user.name},</Text>
<Text class="text-base">
Your project
<VLink href="https://modrinth.com/project/{project.id}" class="text-green underline"
>{project.name}</VLink
>
has been <b>approved</b> by the moderation team!
</Text>
<Button
href="https://modrinth.com/project/{project.id}"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
View project
</Button>
<Text class="text-base">
If you have questions or believe something isn't correct, you can reply to this email or reach
out via the
<VLink href="https://support.modrinth.com" class="text-green underline">Support Portal</VLink
>.
</Text>
<Text class="text-base">Thank you for sharing your work with the Modrinth community!</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import { Button, Heading, Img, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Your project, {project.name}, status has been updated"
:manual-links="[
{ link: 'https://modrinth.com/legal/rules', label: 'Community Guidelines' },
{
link: 'https://modrinth.com/project/{project.id}/moderation',
label: 'Your project\'s moderation thread',
},
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Section class="mb-4 mt-2">
<Img
src="{project.icon_url}"
alt="project icon"
width="64"
height="64"
class="block h-auto rounded-lg"
/>
</Section>
<Heading as="h1" class="mb-2 text-2xl font-bold"
>Your project, {project.name}, status has been updated</Heading
>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base">
Your project's status has been changed from <b>{project.oldstatus}</b> to
<b>{project.newstatus}</b> by the moderation team. Please review any messages left in the
<VLink
href="https://modrinth.com/project/{project.id}/moderation"
class="text-green underline"
>moderation thread</VLink
>
which might be relevant to why the status was changed.
</Text>
<Button
href="https://modrinth.com/project/{project.id}"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
View project
</Button>
<Text class="text-base">
If you believe this status was applied in error, you can reply in the moderation thread or
contact support through our
<VLink href="https://support.modrinth.com" class="text-green underline">Support Portal</VLink>
or by replying to this email.
</Text>
<Text class="text-base">Thank you for publishing on Modrinth!</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,60 @@
<script setup lang="ts">
import { Button, Heading, Img, Link as VLink, Section, Text } from '@vue-email/components'
import StyledEmail from '@/emails/shared/StyledEmail.vue'
</script>
<template>
<StyledEmail
title="Project ownership transferred"
:manual-links="[
{ link: 'https://modrinth.com/project/{project.id}', label: 'Project page' },
{ link: 'https://modrinth.com/dashboard/notifications', label: 'Notification dashboard' },
{ link: 'https://support.modrinth.com', label: 'Support Portal' },
]"
>
<Section class="mb-4 mt-2">
<Img
src="{project.icon_url}"
alt="project icon"
width="64"
height="64"
class="block h-auto rounded-lg"
/>
</Section>
<Heading as="h1" class="mb-2 text-2xl font-bold">Project ownership transferred</Heading>
<Text class="text-base">Hi {user.name},</Text>
<Text class="text-base">
The ownership of
<b>
<VLink href="https://modrinth.com/project/{project.id}" class="text-green underline">
{project.name}
</VLink>
</b>
has been successfully transferred to the Modrinth {new_owner.type_capitalized}
<b
><VLink
href="https://modrinth.com/{new_owner.type}/{new_owner.name}"
class="text-green underline"
>{new_owner.name}</VLink
></b
>.
</Text>
<Button
href="https://modrinth.com/project/{project.id}"
target="_blank"
class="text-accentContrast inline-block rounded-[12px] bg-brand pb-3 pl-4 pr-4 pt-3 text-[14px] font-bold"
>
View project
</Button>
<Text class="text-base">
If you did not initiate this transfer, please contact support immediately through the
<VLink href="https://support.modrinth.com" class="text-green underline">Support Portal</VLink>
or by replying to this email.
</Text>
</StyledEmail>
</template>

View File

@@ -0,0 +1,129 @@
<script setup lang="ts">
import { CopyIcon, LibraryIcon, PlayIcon, SearchIcon } from '@modrinth/assets'
import { ButtonStyled, Card } from '@modrinth/ui'
import { computed, onMounted, ref } from 'vue'
import emails from '@/emails'
const allTemplates = Object.keys(emails).sort()
const query = ref('')
const filtered = computed(() =>
allTemplates.filter((t) => t.toLowerCase().includes(query.value.toLowerCase().trim())),
)
function openAll() {
let offset = 0
for (const id of filtered.value) {
openPreview(id, offset)
offset++
}
}
function copy(id: string) {
navigator.clipboard?.writeText(`/email/${id}`).catch(() => {})
}
function openPreview(id: string, offset = 0) {
const width = 600
const height = 850
const left = window.screenX + (window.outerWidth - width) / 2 + ((offset * 28) % 320)
const top = window.screenY + (window.outerHeight - height) / 2 + ((offset * 28) % 320)
window.open(
`/email/${id}`,
`email-${id}`,
`popup=yes,width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes,menubar=no,toolbar=no,location=no,status=no`,
)
}
const counts = computed(() => ({
total: allTemplates.length,
shown: filtered.value.length,
}))
onMounted(() => {
document.getElementById('email-search')?.focus()
})
</script>
<template>
<div class="normal-page no-sidebar">
<h1 class="mb-4 text-3xl font-extrabold text-heading">Email templates</h1>
<div class="normal-page__content">
<Card class="mb-6 flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-3">
<div class="relative">
<SearchIcon
class="pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-secondary"
/>
<input
id="email-search"
v-model="query"
type="text"
placeholder="Search templates..."
class="w-72 rounded-lg border border-divider bg-bg px-7 py-2 text-sm text-primary placeholder-secondary focus:border-green focus:outline-none"
/>
</div>
<ButtonStyled color="brand">
<button :disabled="filtered.length === 0" @click="openAll">
<LibraryIcon class="h-4 w-4" aria-hidden="true" />
Open all ({{ counts.shown }})
</button>
</ButtonStyled>
<span class="text-sm text-secondary">
Showing <span class="font-medium text-contrast">{{ counts.shown }}</span> of
<span class="font-medium text-contrast">{{ counts.total }}</span>
</span>
</div>
<div
v-if="filtered.length === 0"
class="rounded-lg border border-dashed border-divider px-6 py-10 text-center text-sm text-secondary"
>
No templates match your search.
</div>
<ul v-else class="grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<li
v-for="id in filtered"
:key="id"
class="hover:border-green/70 group flex flex-col justify-between rounded-lg border border-divider bg-button-bg p-4 shadow-sm transition hover:shadow"
>
<div class="mb-3">
<div class="font-mono text-sm font-semibold tracking-tight text-contrast">
{{ id }}
</div>
<div class="mt-1 truncate text-xs text-secondary">/email/{{ id }}</div>
</div>
<div class="mt-auto flex gap-2">
<ButtonStyled color="brand" class="flex-1">
<button class="w-full justify-center" @click="openPreview(id)">
<PlayIcon class="h-4 w-4" aria-hidden="true" />
Preview
</button>
</ButtonStyled>
<ButtonStyled>
<button class="justify-center" title="Copy preview URL" @click="copy(id)">
<CopyIcon class="h-4 w-4" aria-hidden="true" />
</button>
</ButtonStyled>
</div>
</li>
</ul>
</Card>
<p class="mt-2 text-xs text-secondary">
All templates come from
<code class="rounded bg-code-bg px-1 py-0.5 text-[11px] text-code-text"
>src/emails/index.ts</code
>. Popouts render via
<code class="rounded bg-code-bg px-1 py-0.5 text-[11px] text-code-text"
>/email/[template]</code
>.
</p>
</div>
</div>
</template>

View File

@@ -1,2 +1,2 @@
User-agent: *
Disallow:
Disallow: /email/

View File

@@ -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',
})
}
})

370
pnpm-lock.yaml generated
View File

@@ -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: {}