Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
649 changes: 71 additions & 578 deletions README.md

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions src/actions/contact/responder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { Buffer } from 'node:buffer'
import { ActionsFunctionError } from '@actions/utils/errors'
import acknowledgementTemplateContent from '@actions/contact/email/acknowledgement.mjml?raw'
import messageTemplateContent from '@actions/contact/email/message.mjml?raw'
import { compileEmailTemplate, createEmailTemplate } from '@actions/utils/email/templateCompiler'
import {
compileEmailTemplate,
createImportedEmailTemplate,
} from '@actions/utils/email/templateCompiler'
import { escapeHtml, formatFileSize } from './utils'
import type { ContactFormData, ContactTimeline, FileAttachment } from '@actions/contact/@types'

Expand Down Expand Up @@ -61,13 +64,13 @@ const readInputBoolean = (input: Record<string, unknown>, key: string): boolean
return false
}

const contactMessageTemplate = createEmailTemplate(
new URL('./email/message.mjml', import.meta.url),
const contactMessageTemplate = createImportedEmailTemplate(
'src/actions/contact/email/message.mjml',
messageTemplateContent
)

const contactAcknowledgementTemplate = createEmailTemplate(
new URL('./email/acknowledgement.mjml', import.meta.url),
const contactAcknowledgementTemplate = createImportedEmailTemplate(
'src/actions/contact/email/acknowledgement.mjml',
acknowledgementTemplateContent
)

Expand Down
9 changes: 6 additions & 3 deletions src/actions/gdpr/entities/email.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Resend } from 'resend'
import verificationTemplateContent from '@actions/gdpr/email/verification.mjml?raw'
import { dsarVerificationEmailText } from '@actions/gdpr/email/dsarText'
import { compileEmailTemplate, createEmailTemplate } from '@actions/utils/email/templateCompiler'
import {
compileEmailTemplate,
createImportedEmailTemplate,
} from '@actions/utils/email/templateCompiler'
import { getResendApiKey, isProd } from '@actions/utils/environment/environmentActions'
import { gdprReplyTo, gdprSender } from '@actions/utils/email/resendSenders'
import { getSiteUrl } from '@actions/utils/environment/siteUrlActions'
import { ActionsFunctionError } from '@actions/utils/errors/ActionsFunctionError'

const verificationTemplate = createEmailTemplate(
new URL('../email/verification.mjml', import.meta.url),
const verificationTemplate = createImportedEmailTemplate(
'src/actions/gdpr/email/verification.mjml',
verificationTemplateContent
)

Expand Down
6 changes: 3 additions & 3 deletions src/actions/newsletter/email/confirmationHtml.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import confirmationTemplateContent from './confirmation.mjml?raw'
import { compileEmailTemplate, createEmailTemplate } from '@actions/utils/email/templateCompiler'
import { compileEmailTemplate, createImportedEmailTemplate } from '@actions/utils/email/templateCompiler'

const confirmationTemplate = createEmailTemplate(
new URL('./confirmation.mjml', import.meta.url),
const confirmationTemplate = createImportedEmailTemplate(
'src/actions/newsletter/email/confirmation.mjml',
confirmationTemplateContent
)

Expand Down
6 changes: 3 additions & 3 deletions src/actions/newsletter/email/welcomeHtml.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import welcomeTemplateContent from './welcome.mjml?raw'
import { compileEmailTemplate, createEmailTemplate } from '@actions/utils/email/templateCompiler'
import { compileEmailTemplate, createImportedEmailTemplate } from '@actions/utils/email/templateCompiler'

const welcomeTemplate = createEmailTemplate(
new URL('./welcome.mjml', import.meta.url),
const welcomeTemplate = createImportedEmailTemplate(
'src/actions/newsletter/email/welcome.mjml',
welcomeTemplateContent
)

Expand Down
23 changes: 22 additions & 1 deletion src/actions/utils/email/__tests__/templateCompiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import contactMessageTemplateContent from '../../../contact/email/message.mjml?r
import exampleTemplateContent from '../__fixtures__/example.mjml?raw'
import invalidTemplateContent from '../__fixtures__/invalid.mjml?raw'
import withCommonDataTemplateContent from '../__fixtures__/with-common-data.mjml?raw'
import { compileEmailTemplate, createEmailTemplate } from '../templateCompiler'
import {
compileEmailTemplate,
createEmailTemplate,
createImportedEmailTemplate,
} from '../templateCompiler'

const exampleTemplate = createEmailTemplate(
new URL('../__fixtures__/example.mjml', import.meta.url),
Expand All @@ -28,6 +32,11 @@ const withCommonDataTemplate = createEmailTemplate(
withCommonDataTemplateContent
)

const importedExampleTemplate = createImportedEmailTemplate(
'src/actions/utils/email/__fixtures__/example.mjml',
exampleTemplateContent
)

describe('compileEmailTemplate', () => {
it('compiles the moved contact message template from its imported source', async () => {
const result = await compileEmailTemplate(contactMessageTemplate, {
Expand Down Expand Up @@ -90,6 +99,18 @@ describe('compileEmailTemplate', () => {
expect(result.text).toContain('Contact Webstack Builders at support@webstackbuilders.com.')
})

it('compiles imported template content from a stable source path', async () => {
const result = await compileEmailTemplate(importedExampleTemplate, {
htmlMessage: '<strong>Urgent</strong> message body',
items: ['Coffee Beans'],
name: 'Alex',
})

expect(result.html).toContain('Hello, Alex!')
expect(result.html).toContain('Coffee Beans')
expect(result.text).toContain('Urgent message body')
})

it('throws ActionsFunctionError when MJML compilation reports errors', async () => {
await expect(compileEmailTemplate(invalidTemplate)).rejects.toMatchObject({
appCode: 'EMAIL_TEMPLATE_COMPILE_FAILED',
Expand Down
5 changes: 4 additions & 1 deletion src/actions/utils/email/templateCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,10 @@ const createPlainText = (html: string): string =>
/**
* Creates a bundle-safe template descriptor from imported MJML source.
*/
export const createImportedEmailTemplate = createEmailTemplate
export const createImportedEmailTemplate = (
sourcePath: string,
content: string
): EmailTemplateSource => createEmailTemplate(sourcePath, content)

/**
* Renders imported MJML source with Nunjucks data and returns HTML plus plain text.
Expand Down
Loading