mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
feat(core): Switch to MJML for email templates (#10518)
This commit is contained in:
parent
9e1dac0465
commit
dbc10fe9f5
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
|
@ -5,6 +5,7 @@
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"EditorConfig.EditorConfig",
|
"EditorConfig.EditorConfig",
|
||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
|
"mjmlio.vscode-mjml",
|
||||||
"Vue.volar"
|
"Vue.volar"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,19 +49,19 @@ class SmtpConfig {
|
||||||
export class TemplateConfig {
|
export class TemplateConfig {
|
||||||
/** Overrides default HTML template for inviting new people (use full path) */
|
/** Overrides default HTML template for inviting new people (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_INVITE')
|
@Env('N8N_UM_EMAIL_TEMPLATES_INVITE')
|
||||||
invite: string = '';
|
'user-invited': string = '';
|
||||||
|
|
||||||
/** Overrides default HTML template for resetting password (use full path) */
|
/** Overrides default HTML template for resetting password (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_PWRESET')
|
@Env('N8N_UM_EMAIL_TEMPLATES_PWRESET')
|
||||||
passwordReset: string = '';
|
'password-reset-requested': string = '';
|
||||||
|
|
||||||
/** Overrides default HTML template for notifying that a workflow was shared (use full path) */
|
/** Overrides default HTML template for notifying that a workflow was shared (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED')
|
@Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED')
|
||||||
workflowShared: string = '';
|
'workflow-shared': string = '';
|
||||||
|
|
||||||
/** Overrides default HTML template for notifying that credentials were shared (use full path) */
|
/** Overrides default HTML template for notifying that credentials were shared (use full path) */
|
||||||
@Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED')
|
@Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED')
|
||||||
credentialsShared: string = '';
|
'credentials-shared': string = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
|
|
|
@ -89,10 +89,10 @@ describe('GlobalConfig', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
template: {
|
template: {
|
||||||
credentialsShared: '',
|
'credentials-shared': '',
|
||||||
invite: '',
|
'user-invited': '',
|
||||||
passwordReset: '',
|
'password-reset-requested': '',
|
||||||
workflowShared: '',
|
'workflow-shared': '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
"chokidar": "^3.5.2",
|
"chokidar": "^3.5.2",
|
||||||
"concurrently": "^8.2.0",
|
"concurrently": "^8.2.0",
|
||||||
"ioredis-mock": "^8.8.1",
|
"ioredis-mock": "^8.8.1",
|
||||||
|
"mjml": "^4.15.3",
|
||||||
"ts-essentials": "^7.0.3"
|
"ts-essentials": "^7.0.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { writeFileSync } from 'fs';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import shell from 'shelljs';
|
import shell from 'shelljs';
|
||||||
import { rawTimeZones } from '@vvo/tzdb';
|
import { rawTimeZones } from '@vvo/tzdb';
|
||||||
|
import glob from 'fast-glob';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
@ -13,7 +14,7 @@ const SPEC_THEME_FILENAME = 'swagger-theme.css';
|
||||||
|
|
||||||
const publicApiEnabled = process.env.N8N_PUBLIC_API_DISABLED !== 'true';
|
const publicApiEnabled = process.env.N8N_PUBLIC_API_DISABLED !== 'true';
|
||||||
|
|
||||||
copyUserManagementEmailTemplates();
|
generateUserManagementEmailTemplates();
|
||||||
generateTimezoneData();
|
generateTimezoneData();
|
||||||
|
|
||||||
if (publicApiEnabled) {
|
if (publicApiEnabled) {
|
||||||
|
@ -21,13 +22,22 @@ if (publicApiEnabled) {
|
||||||
bundleOpenApiSpecs();
|
bundleOpenApiSpecs();
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyUserManagementEmailTemplates() {
|
function generateUserManagementEmailTemplates() {
|
||||||
const templates = {
|
const sourceDir = path.resolve(ROOT_DIR, 'src', 'user-management', 'email', 'templates');
|
||||||
source: path.resolve(ROOT_DIR, 'src', 'user-management', 'email', 'templates'),
|
const destinationDir = path.resolve(ROOT_DIR, 'dist', 'user-management', 'email', 'templates');
|
||||||
destination: path.resolve(ROOT_DIR, 'dist', 'user-management', 'email'),
|
|
||||||
};
|
|
||||||
|
|
||||||
shell.cp('-r', templates.source, templates.destination);
|
shell.mkdir('-p', destinationDir);
|
||||||
|
|
||||||
|
const templates = glob.sync('*.mjml', { cwd: sourceDir });
|
||||||
|
templates.forEach((template) => {
|
||||||
|
if (template.startsWith('_')) return;
|
||||||
|
const source = path.resolve(sourceDir, template);
|
||||||
|
const destination = path.resolve(destinationDir, template.replace(/\.mjml$/, '.handlebars'));
|
||||||
|
const command = `pnpm mjml --output ${destination} ${source}`;
|
||||||
|
shell.exec(command, { silent: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
shell.cp(path.resolve(sourceDir, 'n8n-logo.png'), destinationDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copySwaggerTheme() {
|
function copySwaggerTheme() {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||||
import { MfaService } from '@/mfa/mfa.service';
|
import { MfaService } from '@/mfa/mfa.service';
|
||||||
import { Logger } from '@/logger';
|
import { Logger } from '@/logger';
|
||||||
import { ExternalHooks } from '@/external-hooks';
|
import { ExternalHooks } from '@/external-hooks';
|
||||||
import { UrlService } from '@/services/url.service';
|
|
||||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||||
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
|
||||||
|
@ -31,7 +30,6 @@ export class PasswordResetController {
|
||||||
private readonly authService: AuthService,
|
private readonly authService: AuthService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly mfaService: MfaService,
|
private readonly mfaService: MfaService,
|
||||||
private readonly urlService: UrlService,
|
|
||||||
private readonly license: License,
|
private readonly license: License,
|
||||||
private readonly passwordUtility: PasswordUtility,
|
private readonly passwordUtility: PasswordUtility,
|
||||||
private readonly userRepository: UserRepository,
|
private readonly userRepository: UserRepository,
|
||||||
|
@ -108,14 +106,12 @@ export class PasswordResetController {
|
||||||
|
|
||||||
const url = this.authService.generatePasswordResetUrl(user);
|
const url = this.authService.generatePasswordResetUrl(user);
|
||||||
|
|
||||||
const { id, firstName, lastName } = user;
|
const { id, firstName } = user;
|
||||||
try {
|
try {
|
||||||
await this.mailer.passwordReset({
|
await this.mailer.passwordReset({
|
||||||
email,
|
email,
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
|
||||||
passwordResetUrl: url,
|
passwordResetUrl: url,
|
||||||
domain: this.urlService.getInstanceBaseUrl(),
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.eventService.emit('email-failed', {
|
this.eventService.emit('email-failed', {
|
||||||
|
|
|
@ -138,7 +138,6 @@ export class UserService {
|
||||||
const result = await this.mailer.invite({
|
const result = await this.mailer.invite({
|
||||||
email,
|
email,
|
||||||
inviteAcceptUrl,
|
inviteAcceptUrl,
|
||||||
domain,
|
|
||||||
});
|
});
|
||||||
if (result.emailSent) {
|
if (result.emailSent) {
|
||||||
invitedUser.user.emailSent = true;
|
invitedUser.user.emailSent = true;
|
||||||
|
@ -168,7 +167,6 @@ export class UserService {
|
||||||
this.logger.error('Failed to send email', {
|
this.logger.error('Failed to send email', {
|
||||||
userId: owner.id,
|
userId: owner.id,
|
||||||
inviteAcceptUrl,
|
inviteAcceptUrl,
|
||||||
domain,
|
|
||||||
email,
|
email,
|
||||||
});
|
});
|
||||||
invitedUser.error = e.message;
|
invitedUser.error = e.message;
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
export type InviteEmailData = {
|
export type InviteEmailData = {
|
||||||
email: string;
|
email: string;
|
||||||
firstName?: string;
|
|
||||||
lastName?: string;
|
|
||||||
inviteAcceptUrl: string;
|
inviteAcceptUrl: string;
|
||||||
domain: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PasswordResetData = {
|
export type PasswordResetData = {
|
||||||
email: string;
|
email: string;
|
||||||
firstName?: string;
|
firstName: string;
|
||||||
lastName?: string;
|
|
||||||
passwordResetUrl: string;
|
passwordResetUrl: string;
|
||||||
domain: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SendEmailResult = {
|
export type SendEmailResult = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { GlobalConfig } from '@n8n/config';
|
import type { GlobalConfig } from '@n8n/config';
|
||||||
import { mock } from 'jest-mock-extended';
|
import { mock } from 'jest-mock-extended';
|
||||||
|
|
||||||
|
import type { UrlService } from '@/services/url.service';
|
||||||
import type { InviteEmailData, PasswordResetData } from '@/user-management/email/Interfaces';
|
import type { InviteEmailData, PasswordResetData } from '@/user-management/email/Interfaces';
|
||||||
import { NodeMailer } from '@/user-management/email/node-mailer';
|
import { NodeMailer } from '@/user-management/email/node-mailer';
|
||||||
import { UserManagementMailer } from '@/user-management/email/user-management-mailer';
|
import { UserManagementMailer } from '@/user-management/email/user-management-mailer';
|
||||||
|
@ -31,7 +32,7 @@ describe('UserManagementMailer', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const userManagementMailer = new UserManagementMailer(config, mock(), mock(), mock());
|
const userManagementMailer = new UserManagementMailer(config, mock(), mock(), mock(), mock());
|
||||||
|
|
||||||
it('should not setup email transport', async () => {
|
it('should not setup email transport', async () => {
|
||||||
expect(userManagementMailer.isEmailSetUp).toBe(false);
|
expect(userManagementMailer.isEmailSetUp).toBe(false);
|
||||||
|
@ -56,7 +57,18 @@ describe('UserManagementMailer', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const userManagementMailer = new UserManagementMailer(config, mock(), mock(), mock());
|
const urlService = mock<UrlService>();
|
||||||
|
const userManagementMailer = new UserManagementMailer(
|
||||||
|
config,
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
urlService,
|
||||||
|
mock(),
|
||||||
|
);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
urlService.getInstanceBaseUrl.mockReturnValue('https://n8n.url');
|
||||||
|
});
|
||||||
|
|
||||||
it('should setup email transport', async () => {
|
it('should setup email transport', async () => {
|
||||||
expect(userManagementMailer.isEmailSetUp).toBe(true);
|
expect(userManagementMailer.isEmailSetUp).toBe(true);
|
||||||
|
@ -67,9 +79,7 @@ describe('UserManagementMailer', () => {
|
||||||
const result = await userManagementMailer.invite(inviteEmailData);
|
const result = await userManagementMailer.invite(inviteEmailData);
|
||||||
expect(result.emailSent).toBe(true);
|
expect(result.emailSent).toBe(true);
|
||||||
expect(nodeMailer.sendMail).toHaveBeenCalledWith({
|
expect(nodeMailer.sendMail).toHaveBeenCalledWith({
|
||||||
body: expect.stringContaining(
|
body: expect.stringContaining(`href="${inviteEmailData.inviteAcceptUrl}"`),
|
||||||
`<a href="${inviteEmailData.inviteAcceptUrl}" target="_blank">`,
|
|
||||||
),
|
|
||||||
emailRecipients: email,
|
emailRecipients: email,
|
||||||
subject: 'You have been invited to n8n',
|
subject: 'You have been invited to n8n',
|
||||||
});
|
});
|
||||||
|
@ -79,7 +89,7 @@ describe('UserManagementMailer', () => {
|
||||||
const result = await userManagementMailer.passwordReset(passwordResetData);
|
const result = await userManagementMailer.passwordReset(passwordResetData);
|
||||||
expect(result.emailSent).toBe(true);
|
expect(result.emailSent).toBe(true);
|
||||||
expect(nodeMailer.sendMail).toHaveBeenCalledWith({
|
expect(nodeMailer.sendMail).toHaveBeenCalledWith({
|
||||||
body: expect.stringContaining(`<a href="${passwordResetData.passwordResetUrl}">`),
|
body: expect.stringContaining(`href="${passwordResetData.passwordResetUrl}"`),
|
||||||
emailRecipients: email,
|
emailRecipients: email,
|
||||||
subject: 'n8n password reset',
|
subject: 'n8n password reset',
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
import path from 'node:path';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import type { Transporter } from 'nodemailer';
|
import type { Transporter } from 'nodemailer';
|
||||||
import { createTransport } from 'nodemailer';
|
import { createTransport } from 'nodemailer';
|
||||||
|
@ -45,12 +46,20 @@ export class NodeMailer {
|
||||||
|
|
||||||
async sendMail(mailData: MailData): Promise<SendEmailResult> {
|
async sendMail(mailData: MailData): Promise<SendEmailResult> {
|
||||||
try {
|
try {
|
||||||
await this.transport?.sendMail({
|
await this.transport.sendMail({
|
||||||
from: this.sender,
|
from: this.sender,
|
||||||
to: mailData.emailRecipients,
|
to: mailData.emailRecipients,
|
||||||
subject: mailData.subject,
|
subject: mailData.subject,
|
||||||
text: mailData.textOnly,
|
text: mailData.textOnly,
|
||||||
html: mailData.body,
|
html: mailData.body,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
cid: 'n8n-logo',
|
||||||
|
filename: 'n8n-logo.png',
|
||||||
|
path: path.resolve(__dirname, 'templates/n8n-logo.png'),
|
||||||
|
contentDisposition: 'inline',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Email sent successfully to the following recipients: ${mailData.emailRecipients.toString()}`,
|
`Email sent successfully to the following recipients: ${mailData.emailRecipients.toString()}`,
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<mj-head>
|
||||||
|
<mj-attributes>
|
||||||
|
<mj-all font-family="Open Sans, sans-serif"></mj-all>
|
||||||
|
<mj-body background-color="#fbfcfe"></mj-body>
|
||||||
|
<mj-text
|
||||||
|
font-weight="400"
|
||||||
|
font-size="16px"
|
||||||
|
color="#444444"
|
||||||
|
line-height="24px"
|
||||||
|
padding="10px 0 0 0"
|
||||||
|
align="center"
|
||||||
|
></mj-text>
|
||||||
|
<mj-button
|
||||||
|
background-color="#ff6f5c"
|
||||||
|
color="#ffffff"
|
||||||
|
font-size="18px"
|
||||||
|
font-weight="600"
|
||||||
|
align="center"
|
||||||
|
padding-top="20px"
|
||||||
|
line-height="24px"
|
||||||
|
border-radius="4px"
|
||||||
|
></mj-button>
|
||||||
|
<mj-section padding="20px 0px"></mj-section>
|
||||||
|
</mj-attributes>
|
||||||
|
</mj-head>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-image src="cid:n8n-logo" height="40px" width="70px" />
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<mjml>
|
||||||
|
<mj-include path="./_common.mjml" />
|
||||||
|
<mj-body>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="24px" color="#ff6f5c">A credential has been shared with you</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section background-color="#FFFFFF" border="1px solid #ddd">
|
||||||
|
<mj-column>
|
||||||
|
<mj-text><b>"{{ credentialsName }}"</b> credential has been shared with you.</mj-text>
|
||||||
|
<mj-text>To access it, please click the button below.</mj-text>
|
||||||
|
<mj-button href="{{credentialsListUrl}}">Open credential</mj-button>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-include path="./_logo.mjml" />
|
||||||
|
</mj-body>
|
||||||
|
</mjml>
|
|
@ -1,4 +0,0 @@
|
||||||
<p>Hi there,</p>
|
|
||||||
<p><b>"{{ credentialsName }}" credential</b> has been shared with you.</p>
|
|
||||||
<p>To view all the credentials you have access to within n8n, click the following link:</p>
|
|
||||||
<p><a href="{{ credentialsListUrl }}" target="_blank">{{ credentialsListUrl }}</a></p>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<h1>Hi there!</h1>
|
|
||||||
<p>Welcome to n8n, {{firstName}} {{lastName}}</p>
|
|
||||||
<p>Your instance is set up!</p>
|
|
||||||
<p>Use your email to login: {{email}} and the chosen password.</p>
|
|
||||||
<p>Have fun automating!</p>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<p>Hi there,</p>
|
|
||||||
<p>You have been invited to join n8n ({{ domain }}).</p>
|
|
||||||
<p>To accept, click the following link:</p>
|
|
||||||
<p><a href="{{ inviteAcceptUrl }}" target="_blank">{{ inviteAcceptUrl }}</a></p>
|
|
BIN
packages/cli/src/user-management/email/templates/n8n-logo.png
Normal file
BIN
packages/cli/src/user-management/email/templates/n8n-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,31 @@
|
||||||
|
<mjml>
|
||||||
|
<mj-include path="./_common.mjml" />
|
||||||
|
<mj-body>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="24px" color="#ff6f5c">Reset your n8n password</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section background-color="#FFFFFF" border="1px solid #ddd">
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="20px">Hi {{firstName}},</mj-text>
|
||||||
|
<mj-text>Somebody asked to reset your password on n8n at <b>{{domain}}</b> .</mj-text>
|
||||||
|
<mj-text> Click the following link to choose a new password. </mj-text>
|
||||||
|
<mj-button href="{{passwordResetUrl}}">Set a new password</mj-button>
|
||||||
|
|
||||||
|
<mj-text font-size="14px">
|
||||||
|
The link is only valid for 20 minutes since this email was sent.
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="12px" color="#777">
|
||||||
|
If you did not request this email, you can safely ignore this. <br />
|
||||||
|
Your password will not be changed.
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-include path="./_logo.mjml" />
|
||||||
|
</mj-body>
|
||||||
|
</mjml>
|
|
@ -1,5 +0,0 @@
|
||||||
<p>Hi {{firstName}},</p>
|
|
||||||
<p>Somebody asked to reset your password on n8n ({{ domain }}).</p>
|
|
||||||
<br />
|
|
||||||
<p>Click the following link to choose a new password. The link is valid for 20 minutes.</p>
|
|
||||||
<a href="{{ passwordResetUrl }}">{{ passwordResetUrl }}</a>
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<mjml>
|
||||||
|
<mj-include path="./_common.mjml" />
|
||||||
|
<mj-body>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="24px" color="#ff6f5c">Welcome to n8n! 🎉</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section background-color="#FFFFFF" border="1px solid #ddd">
|
||||||
|
<mj-column>
|
||||||
|
<mj-text>You have been invited to join n8n at <b>{{domain}}</b> .</mj-text>
|
||||||
|
<mj-text>To accept, please click the button below.</mj-text>
|
||||||
|
<mj-button href="{{inviteAcceptUrl}}">Set up your n8n account</mj-button>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-include path="./_logo.mjml" />
|
||||||
|
</mj-body>
|
||||||
|
</mjml>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<mjml>
|
||||||
|
<mj-include path="./_common.mjml" />
|
||||||
|
<mj-body>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="24px" color="#ff6f5c">A workflow has been shared with you</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section background-color="#FFFFFF" border="1px solid #ddd">
|
||||||
|
<mj-column>
|
||||||
|
<mj-text><b>"{{ workflowName }}"</b> workflow has been shared with you.</mj-text>
|
||||||
|
<mj-text>To access it, please click the button below.</mj-text>
|
||||||
|
<mj-button href="{{workflowUrl}}">Open Workflow</mj-button>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-include path="./_logo.mjml" />
|
||||||
|
</mj-body>
|
||||||
|
</mjml>
|
|
@ -1,4 +0,0 @@
|
||||||
<p>Hi there,</p>
|
|
||||||
<p><b>"{{ workflowName }}" workflow</b> has been shared with you.</p>
|
|
||||||
<p>To access the workflow, click the following link:</p>
|
|
||||||
<p><a href="{{ workflowUrl }}" target="_blank">{{ workflowUrl }}</a></p>
|
|
|
@ -8,6 +8,7 @@ import { GlobalConfig } from '@n8n/config';
|
||||||
import type { User } from '@/databases/entities/User';
|
import type { User } from '@/databases/entities/User';
|
||||||
import type { WorkflowEntity } from '@/databases/entities/workflow-entity';
|
import type { WorkflowEntity } from '@/databases/entities/workflow-entity';
|
||||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||||
|
import { EventService } from '@/events/event.service';
|
||||||
import { Logger } from '@/logger';
|
import { Logger } from '@/logger';
|
||||||
import { UrlService } from '@/services/url.service';
|
import { UrlService } from '@/services/url.service';
|
||||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||||
|
@ -15,10 +16,14 @@ import { toError } from '@/utils';
|
||||||
|
|
||||||
import type { InviteEmailData, PasswordResetData, SendEmailResult } from './Interfaces';
|
import type { InviteEmailData, PasswordResetData, SendEmailResult } from './Interfaces';
|
||||||
import { NodeMailer } from './node-mailer';
|
import { NodeMailer } from './node-mailer';
|
||||||
import { EventService } from '@/events/event.service';
|
import { inTest } from '@/constants';
|
||||||
|
|
||||||
type Template = HandlebarsTemplateDelegate<unknown>;
|
type Template = HandlebarsTemplateDelegate<unknown>;
|
||||||
type TemplateName = 'invite' | 'passwordReset' | 'workflowShared' | 'credentialsShared';
|
type TemplateName =
|
||||||
|
| 'user-invited'
|
||||||
|
| 'password-reset-requested'
|
||||||
|
| 'workflow-shared'
|
||||||
|
| 'credentials-shared';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class UserManagementMailer {
|
export class UserManagementMailer {
|
||||||
|
@ -35,6 +40,7 @@ export class UserManagementMailer {
|
||||||
private readonly logger: Logger,
|
private readonly logger: Logger,
|
||||||
private readonly userRepository: UserRepository,
|
private readonly userRepository: UserRepository,
|
||||||
private readonly urlService: UrlService,
|
private readonly urlService: UrlService,
|
||||||
|
private readonly eventService: EventService,
|
||||||
) {
|
) {
|
||||||
const emailsConfig = globalConfig.userManagement.emails;
|
const emailsConfig = globalConfig.userManagement.emails;
|
||||||
this.isEmailSetUp = emailsConfig.mode === 'smtp' && emailsConfig.smtp.host !== '';
|
this.isEmailSetUp = emailsConfig.mode === 'smtp' && emailsConfig.smtp.host !== '';
|
||||||
|
@ -49,31 +55,23 @@ export class UserManagementMailer {
|
||||||
async invite(inviteEmailData: InviteEmailData): Promise<SendEmailResult> {
|
async invite(inviteEmailData: InviteEmailData): Promise<SendEmailResult> {
|
||||||
if (!this.mailer) return { emailSent: false };
|
if (!this.mailer) return { emailSent: false };
|
||||||
|
|
||||||
const template = await this.getTemplate('invite');
|
const template = await this.getTemplate('user-invited');
|
||||||
const result = await this.mailer.sendMail({
|
return await this.mailer.sendMail({
|
||||||
emailRecipients: inviteEmailData.email,
|
emailRecipients: inviteEmailData.email,
|
||||||
subject: 'You have been invited to n8n',
|
subject: 'You have been invited to n8n',
|
||||||
body: template(inviteEmailData),
|
body: template({ ...this.basePayload, ...inviteEmailData }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// If mailer does not exist it means mail has been disabled.
|
|
||||||
// No error, just say no email was sent.
|
|
||||||
return result ?? { emailSent: false };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async passwordReset(passwordResetData: PasswordResetData): Promise<SendEmailResult> {
|
async passwordReset(passwordResetData: PasswordResetData): Promise<SendEmailResult> {
|
||||||
if (!this.mailer) return { emailSent: false };
|
if (!this.mailer) return { emailSent: false };
|
||||||
|
|
||||||
const template = await this.getTemplate('passwordReset', 'passwordReset.html');
|
const template = await this.getTemplate('password-reset-requested');
|
||||||
const result = await this.mailer.sendMail({
|
return await this.mailer.sendMail({
|
||||||
emailRecipients: passwordResetData.email,
|
emailRecipients: passwordResetData.email,
|
||||||
subject: 'n8n password reset',
|
subject: 'n8n password reset',
|
||||||
body: template(passwordResetData),
|
body: template({ ...this.basePayload, ...passwordResetData }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// If mailer does not exist it means mail has been disabled.
|
|
||||||
// No error, just say no email was sent.
|
|
||||||
return result ?? { emailSent: false };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async notifyWorkflowShared({
|
async notifyWorkflowShared({
|
||||||
|
@ -93,7 +91,7 @@ export class UserManagementMailer {
|
||||||
|
|
||||||
const emailRecipients = recipients.map(({ email }) => email);
|
const emailRecipients = recipients.map(({ email }) => email);
|
||||||
|
|
||||||
const populateTemplate = await this.getTemplate('workflowShared', 'workflowShared.html');
|
const populateTemplate = await this.getTemplate('workflow-shared');
|
||||||
|
|
||||||
const baseUrl = this.urlService.getInstanceBaseUrl();
|
const baseUrl = this.urlService.getInstanceBaseUrl();
|
||||||
|
|
||||||
|
@ -111,7 +109,7 @@ export class UserManagementMailer {
|
||||||
|
|
||||||
this.logger.info('Sent workflow shared email successfully', { sharerId: sharer.id });
|
this.logger.info('Sent workflow shared email successfully', { sharerId: sharer.id });
|
||||||
|
|
||||||
Container.get(EventService).emit('user-transactional-email-sent', {
|
this.eventService.emit('user-transactional-email-sent', {
|
||||||
userId: sharer.id,
|
userId: sharer.id,
|
||||||
messageType: 'Workflow shared',
|
messageType: 'Workflow shared',
|
||||||
publicApi: false,
|
publicApi: false,
|
||||||
|
@ -119,7 +117,7 @@ export class UserManagementMailer {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Container.get(EventService).emit('email-failed', {
|
this.eventService.emit('email-failed', {
|
||||||
user: sharer,
|
user: sharer,
|
||||||
messageType: 'Workflow shared',
|
messageType: 'Workflow shared',
|
||||||
publicApi: false,
|
publicApi: false,
|
||||||
|
@ -148,7 +146,7 @@ export class UserManagementMailer {
|
||||||
|
|
||||||
const emailRecipients = recipients.map(({ email }) => email);
|
const emailRecipients = recipients.map(({ email }) => email);
|
||||||
|
|
||||||
const populateTemplate = await this.getTemplate('credentialsShared', 'credentialsShared.html');
|
const populateTemplate = await this.getTemplate('credentials-shared');
|
||||||
|
|
||||||
const baseUrl = this.urlService.getInstanceBaseUrl();
|
const baseUrl = this.urlService.getInstanceBaseUrl();
|
||||||
|
|
||||||
|
@ -166,7 +164,7 @@ export class UserManagementMailer {
|
||||||
|
|
||||||
this.logger.info('Sent credentials shared email successfully', { sharerId: sharer.id });
|
this.logger.info('Sent credentials shared email successfully', { sharerId: sharer.id });
|
||||||
|
|
||||||
Container.get(EventService).emit('user-transactional-email-sent', {
|
this.eventService.emit('user-transactional-email-sent', {
|
||||||
userId: sharer.id,
|
userId: sharer.id,
|
||||||
messageType: 'Credentials shared',
|
messageType: 'Credentials shared',
|
||||||
publicApi: false,
|
publicApi: false,
|
||||||
|
@ -174,7 +172,7 @@ export class UserManagementMailer {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Container.get(EventService).emit('email-failed', {
|
this.eventService.emit('email-failed', {
|
||||||
user: sharer,
|
user: sharer,
|
||||||
messageType: 'Credentials shared',
|
messageType: 'Credentials shared',
|
||||||
publicApi: false,
|
publicApi: false,
|
||||||
|
@ -186,21 +184,25 @@ export class UserManagementMailer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTemplate(
|
async getTemplate(templateName: TemplateName): Promise<Template> {
|
||||||
templateName: TemplateName,
|
|
||||||
defaultFilename = `${templateName}.html`,
|
|
||||||
): Promise<Template> {
|
|
||||||
let template = this.templatesCache[templateName];
|
let template = this.templatesCache[templateName];
|
||||||
if (!template) {
|
if (!template) {
|
||||||
|
const fileExtension = inTest ? 'mjml' : 'handlebars';
|
||||||
const templateOverride = this.templateOverrides[templateName];
|
const templateOverride = this.templateOverrides[templateName];
|
||||||
const templatePath =
|
const templatePath =
|
||||||
templateOverride && existsSync(templateOverride)
|
templateOverride && existsSync(templateOverride)
|
||||||
? templateOverride
|
? templateOverride
|
||||||
: pathJoin(__dirname, `templates/${defaultFilename}`);
|
: pathJoin(__dirname, `templates/${templateName}.${fileExtension}`);
|
||||||
const markup = await readFile(templatePath, 'utf-8');
|
const markup = await readFile(templatePath, 'utf-8');
|
||||||
template = Handlebars.compile(markup);
|
template = Handlebars.compile(markup);
|
||||||
this.templatesCache[templateName] = template;
|
this.templatesCache[templateName] = template;
|
||||||
}
|
}
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get basePayload() {
|
||||||
|
const baseUrl = this.urlService.getInstanceBaseUrl();
|
||||||
|
const domain = new URL(baseUrl).hostname;
|
||||||
|
return { baseUrl, domain };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
557
pnpm-lock.yaml
557
pnpm-lock.yaml
|
@ -1005,6 +1005,9 @@ importers:
|
||||||
ioredis-mock:
|
ioredis-mock:
|
||||||
specifier: ^8.8.1
|
specifier: ^8.8.1
|
||||||
version: 8.8.1(@types/ioredis-mock@8.2.2)(ioredis@5.3.2)
|
version: 8.8.1(@types/ioredis-mock@8.2.2)(ioredis@5.3.2)
|
||||||
|
mjml:
|
||||||
|
specifier: ^4.15.3
|
||||||
|
version: 4.15.3(encoding@0.1.13)
|
||||||
ts-essentials:
|
ts-essentials:
|
||||||
specifier: ^7.0.3
|
specifier: ^7.0.3
|
||||||
version: 7.0.3(typescript@5.5.2)
|
version: 7.0.3(typescript@5.5.2)
|
||||||
|
@ -6641,6 +6644,9 @@ packages:
|
||||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
camel-case@3.0.0:
|
||||||
|
resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==}
|
||||||
|
|
||||||
camel-case@4.1.2:
|
camel-case@4.1.2:
|
||||||
resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
|
resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
|
||||||
|
|
||||||
|
@ -6771,6 +6777,10 @@ packages:
|
||||||
classnames@2.5.1:
|
classnames@2.5.1:
|
||||||
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
||||||
|
|
||||||
|
clean-css@4.2.4:
|
||||||
|
resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==}
|
||||||
|
engines: {node: '>= 4.0'}
|
||||||
|
|
||||||
clean-regexp@1.0.0:
|
clean-regexp@1.0.0:
|
||||||
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
|
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -7380,6 +7390,9 @@ packages:
|
||||||
detect-node-es@1.1.0:
|
detect-node-es@1.1.0:
|
||||||
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
||||||
|
|
||||||
|
detect-node@2.1.0:
|
||||||
|
resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
|
||||||
|
|
||||||
detect-package-manager@2.0.1:
|
detect-package-manager@2.0.1:
|
||||||
resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==}
|
resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -7450,6 +7463,10 @@ packages:
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
deprecated: Use your platform's native DOMException instead
|
deprecated: Use your platform's native DOMException instead
|
||||||
|
|
||||||
|
domhandler@3.3.0:
|
||||||
|
resolution: {integrity: sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
domhandler@4.3.1:
|
domhandler@4.3.1:
|
||||||
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
|
resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
@ -7471,6 +7488,9 @@ packages:
|
||||||
domutils@3.0.1:
|
domutils@3.0.1:
|
||||||
resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
|
resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
|
||||||
|
|
||||||
|
domutils@3.1.0:
|
||||||
|
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
|
||||||
|
|
||||||
dot-case@3.0.4:
|
dot-case@3.0.4:
|
||||||
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
|
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
|
||||||
|
|
||||||
|
@ -7668,6 +7688,10 @@ packages:
|
||||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
escape-goat@3.0.0:
|
||||||
|
resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
escape-html@1.0.3:
|
escape-html@1.0.3:
|
||||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||||
|
|
||||||
|
@ -8590,16 +8614,27 @@ packages:
|
||||||
html-escaper@2.0.2:
|
html-escaper@2.0.2:
|
||||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||||
|
|
||||||
|
html-minifier@4.0.0:
|
||||||
|
resolution: {integrity: sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
html-to-text@9.0.5:
|
html-to-text@9.0.5:
|
||||||
resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==}
|
resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
htmlparser2@5.0.1:
|
||||||
|
resolution: {integrity: sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==}
|
||||||
|
|
||||||
htmlparser2@6.1.0:
|
htmlparser2@6.1.0:
|
||||||
resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
|
resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
|
||||||
|
|
||||||
htmlparser2@8.0.2:
|
htmlparser2@8.0.2:
|
||||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||||
|
|
||||||
|
htmlparser2@9.1.0:
|
||||||
|
resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
|
||||||
|
|
||||||
http-cache-semantics@4.1.1:
|
http-cache-semantics@4.1.1:
|
||||||
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
||||||
|
|
||||||
|
@ -9390,6 +9425,11 @@ packages:
|
||||||
jszip@3.10.1:
|
jszip@3.10.1:
|
||||||
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||||
|
|
||||||
|
juice@10.0.1:
|
||||||
|
resolution: {integrity: sha512-ZhJT1soxJCkOiO55/mz8yeBKTAJhRzX9WBO+16ZTqNTONnnVlUPyVBIzQ7lDRjaBdTbid+bAnyIon/GM3yp4cA==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
jwa@1.4.1:
|
jwa@1.4.1:
|
||||||
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
||||||
|
|
||||||
|
@ -9830,6 +9870,9 @@ packages:
|
||||||
loupe@2.3.7:
|
loupe@2.3.7:
|
||||||
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
|
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
|
||||||
|
|
||||||
|
lower-case@1.1.4:
|
||||||
|
resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==}
|
||||||
|
|
||||||
lower-case@2.0.2:
|
lower-case@2.0.2:
|
||||||
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
|
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
|
||||||
|
|
||||||
|
@ -9976,6 +10019,9 @@ packages:
|
||||||
memory-pager@1.5.0:
|
memory-pager@1.5.0:
|
||||||
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
||||||
|
|
||||||
|
mensch@0.3.4:
|
||||||
|
resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==}
|
||||||
|
|
||||||
merge-descriptors@1.0.1:
|
merge-descriptors@1.0.1:
|
||||||
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
||||||
|
|
||||||
|
@ -10112,6 +10158,105 @@ packages:
|
||||||
resolution: {integrity: sha512-MGZAq0Q3OuRYgZKvlB69z4gLN4G3PvgC4A2zhkCXCXrLD5wm2cCnwNB59xOBVA+srZ0zEes6u+VylcPIkB4SqA==}
|
resolution: {integrity: sha512-MGZAq0Q3OuRYgZKvlB69z4gLN4G3PvgC4A2zhkCXCXrLD5wm2cCnwNB59xOBVA+srZ0zEes6u+VylcPIkB4SqA==}
|
||||||
engines: {node: 6.* || 8.* || >= 10.*}
|
engines: {node: 6.* || 8.* || >= 10.*}
|
||||||
|
|
||||||
|
mjml-accordion@4.15.3:
|
||||||
|
resolution: {integrity: sha512-LPNVSj1LyUVYT9G1gWwSw3GSuDzDsQCu0tPB2uDsq4VesYNnU6v3iLCQidMiR6azmIt13OEozG700ygAUuA6Ng==}
|
||||||
|
|
||||||
|
mjml-body@4.15.3:
|
||||||
|
resolution: {integrity: sha512-7pfUOVPtmb0wC+oUOn4xBsAw4eT5DyD6xqaxj/kssu6RrFXOXgJaVnDPAI9AzIvXJ/5as9QrqRGYAddehwWpHQ==}
|
||||||
|
|
||||||
|
mjml-button@4.15.3:
|
||||||
|
resolution: {integrity: sha512-79qwn9AgdGjJR1vLnrcm2rq2AsAZkKC5JPwffTMG+Nja6zGYpTDZFZ56ekHWr/r1b5WxkukcPj2PdevUug8c+Q==}
|
||||||
|
|
||||||
|
mjml-carousel@4.15.3:
|
||||||
|
resolution: {integrity: sha512-3ju6I4l7uUhPRrJfN3yK9AMsfHvrYbRkcJ1GRphFHzUj37B2J6qJOQUpzA547Y4aeh69TSb7HFVf1t12ejQxVw==}
|
||||||
|
|
||||||
|
mjml-cli@4.15.3:
|
||||||
|
resolution: {integrity: sha512-+V2TDw3tXUVEptFvLSerz125C2ogYl8klIBRY1m5BHd4JvGVf3yhx8N3PngByCzA6PGcv/eydGQN+wy34SHf0Q==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
mjml-column@4.15.3:
|
||||||
|
resolution: {integrity: sha512-hYdEFdJGHPbZJSEysykrevEbB07yhJGSwfDZEYDSbhQQFjV2tXrEgYcFD5EneMaowjb55e3divSJxU4c5q4Qgw==}
|
||||||
|
|
||||||
|
mjml-core@4.15.3:
|
||||||
|
resolution: {integrity: sha512-Dmwk+2cgSD9L9GmTbEUNd8QxkTZtW9P7FN/ROZW/fGZD6Hq6/4TB0zEspg2Ow9eYjZXO2ofOJ3PaQEEShKV0kQ==}
|
||||||
|
|
||||||
|
mjml-divider@4.15.3:
|
||||||
|
resolution: {integrity: sha512-vh27LQ9FG/01y0b9ntfqm+GT5AjJnDSDY9hilss2ixIUh0FemvfGRfsGVeV5UBVPBKK7Ffhvfqc7Rciob9Spzw==}
|
||||||
|
|
||||||
|
mjml-group@4.15.3:
|
||||||
|
resolution: {integrity: sha512-HSu/rKnGZVKFq3ciT46vi1EOy+9mkB0HewO4+P6dP/Y0UerWkN6S3UK11Cxsj0cAp0vFwkPDCdOeEzRdpFEkzA==}
|
||||||
|
|
||||||
|
mjml-head-attributes@4.15.3:
|
||||||
|
resolution: {integrity: sha512-2ISo0r5ZKwkrvJgDou9xVPxxtXMaETe2AsAA02L89LnbB2KC0N5myNsHV0sEysTw9+CfCmgjAb0GAI5QGpxKkQ==}
|
||||||
|
|
||||||
|
mjml-head-breakpoint@4.15.3:
|
||||||
|
resolution: {integrity: sha512-Eo56FA5C2v6ucmWQL/JBJ2z641pLOom4k0wP6CMZI2utfyiJ+e2Uuinj1KTrgDcEvW4EtU9HrfAqLK9UosLZlg==}
|
||||||
|
|
||||||
|
mjml-head-font@4.15.3:
|
||||||
|
resolution: {integrity: sha512-CzV2aDPpiNIIgGPHNcBhgyedKY4SX3BJoTwOobSwZVIlEA6TAWB4Z9WwFUmQqZOgo1AkkiTHPZQvGcEhFFXH6g==}
|
||||||
|
|
||||||
|
mjml-head-html-attributes@4.15.3:
|
||||||
|
resolution: {integrity: sha512-MDNDPMBOgXUZYdxhosyrA2kudiGO8aogT0/cODyi2Ed9o/1S7W+je11JUYskQbncqhWKGxNyaP4VWa+6+vUC/g==}
|
||||||
|
|
||||||
|
mjml-head-preview@4.15.3:
|
||||||
|
resolution: {integrity: sha512-J2PxCefUVeFwsAExhrKo4lwxDevc5aKj888HBl/wN4EuWOoOg06iOGCxz4Omd8dqyFsrqvbBuPqRzQ+VycGmaA==}
|
||||||
|
|
||||||
|
mjml-head-style@4.15.3:
|
||||||
|
resolution: {integrity: sha512-9J+JuH+mKrQU65CaJ4KZegACUgNIlYmWQYx3VOBR/tyz+8kDYX7xBhKJCjQ1I4wj2Tvga3bykd89Oc2kFZ5WOw==}
|
||||||
|
|
||||||
|
mjml-head-title@4.15.3:
|
||||||
|
resolution: {integrity: sha512-IM59xRtsxID4DubQ0iLmoCGXguEe+9BFG4z6y2xQDrscIa4QY3KlfqgKGT69ojW+AVbXXJPEVqrAi4/eCsLItQ==}
|
||||||
|
|
||||||
|
mjml-head@4.15.3:
|
||||||
|
resolution: {integrity: sha512-o3mRuuP/MB5fZycjD3KH/uXsnaPl7Oo8GtdbJTKtH1+O/3pz8GzGMkscTKa97l03DAG2EhGrzzLcU2A6eshwFw==}
|
||||||
|
|
||||||
|
mjml-hero@4.15.3:
|
||||||
|
resolution: {integrity: sha512-9cLAPuc69yiuzNrMZIN58j+HMK1UWPaq2i3/Fg2ZpimfcGFKRcPGCbEVh0v+Pb6/J0+kf8yIO0leH20opu3AyQ==}
|
||||||
|
|
||||||
|
mjml-image@4.15.3:
|
||||||
|
resolution: {integrity: sha512-g1OhSdofIytE9qaOGdTPmRIp7JsCtgO0zbsn1Fk6wQh2gEL55Z40j/VoghslWAWTgT2OHFdBKnMvWtN6U5+d2Q==}
|
||||||
|
|
||||||
|
mjml-migrate@4.15.3:
|
||||||
|
resolution: {integrity: sha512-sr/+35RdxZroNQVegjpfRHJ5hda9XCgaS4mK2FGO+Mb1IUevKfeEPII3F/cHDpNwFeYH3kAgyqQ22ClhGLWNBA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
mjml-navbar@4.15.3:
|
||||||
|
resolution: {integrity: sha512-VsKH/Jdlf8Yu3y7GpzQV5n7JMdpqvZvTSpF6UQXL0PWOm7k6+LX+sCZimOfpHJ+wCaaybpxokjWZ71mxOoCWoA==}
|
||||||
|
|
||||||
|
mjml-parser-xml@4.15.3:
|
||||||
|
resolution: {integrity: sha512-Tz0UX8/JVYICLjT+U8J1f/TFxIYVYjzZHeh4/Oyta0pLpRLeZlxEd71f3u3kdnulCKMP4i37pFRDmyLXAlEuLw==}
|
||||||
|
|
||||||
|
mjml-preset-core@4.15.3:
|
||||||
|
resolution: {integrity: sha512-1zZS8P4O0KweWUqNS655+oNnVMPQ1Rq1GaZq5S9JfwT1Vh/m516lSmiTW9oko6gGHytt5s6Yj6oOeu5Zm8FoLw==}
|
||||||
|
|
||||||
|
mjml-raw@4.15.3:
|
||||||
|
resolution: {integrity: sha512-IGyHheOYyRchBLiAEgw3UM11kFNmBSMupu2BDdejC6ZiDhEAdG+tyERlsCwDPYtXanvFpGWULIu3XlsUPc+RZw==}
|
||||||
|
|
||||||
|
mjml-section@4.15.3:
|
||||||
|
resolution: {integrity: sha512-JfVPRXH++Hd933gmQfG8JXXCBCR6fIzC3DwiYycvanL/aW1cEQ2EnebUfQkt5QzlYjOkJEH+JpccAsq3ln6FZQ==}
|
||||||
|
|
||||||
|
mjml-social@4.15.3:
|
||||||
|
resolution: {integrity: sha512-7sD5FXrESOxpT9Z4Oh36bS6u/geuUrMP1aCg2sjyAwbPcF1aWa2k9OcatQfpRf6pJEhUZ18y6/WBBXmMVmSzXg==}
|
||||||
|
|
||||||
|
mjml-spacer@4.15.3:
|
||||||
|
resolution: {integrity: sha512-3B7Qj+17EgDdAtZ3NAdMyOwLTX1jfmJuY7gjyhS2HtcZAmppW+cxqHUBwCKfvSRgTQiccmEvtNxaQK+tfyrZqA==}
|
||||||
|
|
||||||
|
mjml-table@4.15.3:
|
||||||
|
resolution: {integrity: sha512-FLx7DcRKTdKdcOCbMyBaeudeHaHpwPveRrBm6WyQe3LXx6FfdmOh59i71/16LFQMgBOD3N4/UJkzxLzlTJzMqQ==}
|
||||||
|
|
||||||
|
mjml-text@4.15.3:
|
||||||
|
resolution: {integrity: sha512-+C0hxCmw9kg0XzT6vhE5mFkK6y225nC8UEQcN94K0fBCjPKkM+HqZMwGX205fzdGRi+Bxa55b/VhrIVwdv+8vw==}
|
||||||
|
|
||||||
|
mjml-validator@4.15.3:
|
||||||
|
resolution: {integrity: sha512-Xb72KdqRwjv/qM2rJpV22syyP2N3cRQ9VVDrN6u2FSzLq02buFNxmSPJ7CKhat3PrUNdVHU75KZwOf/tz4UEhA==}
|
||||||
|
|
||||||
|
mjml-wrapper@4.15.3:
|
||||||
|
resolution: {integrity: sha512-ditsCijeHJrmBmObtJmQ18ddLxv5oPyMTdPU8Di8APOnD2zPk7Z4UAuJSl7HXB45oFiivr3MJf4koFzMUSZ6Gg==}
|
||||||
|
|
||||||
|
mjml@4.15.3:
|
||||||
|
resolution: {integrity: sha512-bW2WpJxm6HS+S3Yu6tq1DUPFoTxU9sPviUSmnL7Ua+oVO3WA5ILFWqvujUlz+oeuM+HCwEyMiP5xvKNPENVjYA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
mkdirp-classic@0.5.3:
|
mkdirp-classic@0.5.3:
|
||||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||||
|
|
||||||
|
@ -10312,6 +10457,9 @@ packages:
|
||||||
neo-async@2.6.2:
|
neo-async@2.6.2:
|
||||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||||
|
|
||||||
|
no-case@2.3.2:
|
||||||
|
resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
|
||||||
|
|
||||||
no-case@3.0.4:
|
no-case@3.0.4:
|
||||||
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
||||||
|
|
||||||
|
@ -10690,6 +10838,9 @@ packages:
|
||||||
pako@1.0.11:
|
pako@1.0.11:
|
||||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||||
|
|
||||||
|
param-case@2.1.1:
|
||||||
|
resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==}
|
||||||
|
|
||||||
param-case@3.0.4:
|
param-case@3.0.4:
|
||||||
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
|
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
|
||||||
|
|
||||||
|
@ -11483,6 +11634,10 @@ packages:
|
||||||
reinterval@1.1.0:
|
reinterval@1.1.0:
|
||||||
resolution: {integrity: sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==}
|
resolution: {integrity: sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==}
|
||||||
|
|
||||||
|
relateurl@0.2.7:
|
||||||
|
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
remove-trailing-slash@0.1.1:
|
remove-trailing-slash@0.1.1:
|
||||||
resolution: {integrity: sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==}
|
resolution: {integrity: sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==}
|
||||||
|
|
||||||
|
@ -11831,6 +11986,9 @@ packages:
|
||||||
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
|
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
slick@1.12.2:
|
||||||
|
resolution: {integrity: sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==}
|
||||||
|
|
||||||
slugify@1.4.7:
|
slugify@1.4.7:
|
||||||
resolution: {integrity: sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==}
|
resolution: {integrity: sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
|
@ -12761,6 +12919,9 @@ packages:
|
||||||
upper-case-first@2.0.2:
|
upper-case-first@2.0.2:
|
||||||
resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
|
resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
|
||||||
|
|
||||||
|
upper-case@1.1.3:
|
||||||
|
resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==}
|
||||||
|
|
||||||
upper-case@2.0.2:
|
upper-case@2.0.2:
|
||||||
resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
|
resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
|
||||||
|
|
||||||
|
@ -12844,6 +13005,10 @@ packages:
|
||||||
resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==}
|
resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==}
|
||||||
engines: {node: '>=10.12.0'}
|
engines: {node: '>=10.12.0'}
|
||||||
|
|
||||||
|
valid-data-url@3.0.1:
|
||||||
|
resolution: {integrity: sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
validate-npm-package-license@3.0.4:
|
validate-npm-package-license@3.0.4:
|
||||||
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
|
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
|
||||||
|
|
||||||
|
@ -13080,6 +13245,10 @@ packages:
|
||||||
wcwidth@1.0.1:
|
wcwidth@1.0.1:
|
||||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||||
|
|
||||||
|
web-resource-inliner@6.0.1:
|
||||||
|
resolution: {integrity: sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
web-streams-polyfill@3.2.1:
|
web-streams-polyfill@3.2.1:
|
||||||
resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
|
resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
@ -20131,6 +20300,11 @@ snapshots:
|
||||||
|
|
||||||
callsites@3.1.0: {}
|
callsites@3.1.0: {}
|
||||||
|
|
||||||
|
camel-case@3.0.0:
|
||||||
|
dependencies:
|
||||||
|
no-case: 2.3.2
|
||||||
|
upper-case: 1.1.3
|
||||||
|
|
||||||
camel-case@4.1.2:
|
camel-case@4.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
pascal-case: 3.1.2
|
pascal-case: 3.1.2
|
||||||
|
@ -20287,6 +20461,10 @@ snapshots:
|
||||||
|
|
||||||
classnames@2.5.1: {}
|
classnames@2.5.1: {}
|
||||||
|
|
||||||
|
clean-css@4.2.4:
|
||||||
|
dependencies:
|
||||||
|
source-map: 0.6.1
|
||||||
|
|
||||||
clean-regexp@1.0.0:
|
clean-regexp@1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
escape-string-regexp: 1.0.5
|
escape-string-regexp: 1.0.5
|
||||||
|
@ -20947,6 +21125,8 @@ snapshots:
|
||||||
|
|
||||||
detect-node-es@1.1.0: {}
|
detect-node-es@1.1.0: {}
|
||||||
|
|
||||||
|
detect-node@2.1.0: {}
|
||||||
|
|
||||||
detect-package-manager@2.0.1:
|
detect-package-manager@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
execa: 5.1.1
|
execa: 5.1.1
|
||||||
|
@ -21017,6 +21197,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
webidl-conversions: 7.0.0
|
webidl-conversions: 7.0.0
|
||||||
|
|
||||||
|
domhandler@3.3.0:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
domhandler@4.3.1:
|
domhandler@4.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
|
@ -21041,6 +21225,12 @@ snapshots:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
domhandler: 5.0.3
|
domhandler: 5.0.3
|
||||||
|
|
||||||
|
domutils@3.1.0:
|
||||||
|
dependencies:
|
||||||
|
dom-serializer: 2.0.0
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
|
||||||
dot-case@3.0.4:
|
dot-case@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
no-case: 3.0.4
|
no-case: 3.0.4
|
||||||
|
@ -21369,6 +21559,8 @@ snapshots:
|
||||||
|
|
||||||
escalade@3.1.1: {}
|
escalade@3.1.1: {}
|
||||||
|
|
||||||
|
escape-goat@3.0.0: {}
|
||||||
|
|
||||||
escape-html@1.0.3: {}
|
escape-html@1.0.3: {}
|
||||||
|
|
||||||
escape-string-regexp@1.0.5: {}
|
escape-string-regexp@1.0.5: {}
|
||||||
|
@ -22537,6 +22729,16 @@ snapshots:
|
||||||
|
|
||||||
html-escaper@2.0.2: {}
|
html-escaper@2.0.2: {}
|
||||||
|
|
||||||
|
html-minifier@4.0.0:
|
||||||
|
dependencies:
|
||||||
|
camel-case: 3.0.0
|
||||||
|
clean-css: 4.2.4
|
||||||
|
commander: 2.20.3
|
||||||
|
he: 1.2.0
|
||||||
|
param-case: 2.1.1
|
||||||
|
relateurl: 0.2.7
|
||||||
|
uglify-js: 3.17.4
|
||||||
|
|
||||||
html-to-text@9.0.5:
|
html-to-text@9.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@selderee/plugin-htmlparser2': 0.11.0
|
'@selderee/plugin-htmlparser2': 0.11.0
|
||||||
|
@ -22545,6 +22747,13 @@ snapshots:
|
||||||
htmlparser2: 8.0.2
|
htmlparser2: 8.0.2
|
||||||
selderee: 0.11.0
|
selderee: 0.11.0
|
||||||
|
|
||||||
|
htmlparser2@5.0.1:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 3.3.0
|
||||||
|
domutils: 2.8.0
|
||||||
|
entities: 2.2.0
|
||||||
|
|
||||||
htmlparser2@6.1.0:
|
htmlparser2@6.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
|
@ -22559,6 +22768,13 @@ snapshots:
|
||||||
domutils: 3.0.1
|
domutils: 3.0.1
|
||||||
entities: 4.5.0
|
entities: 4.5.0
|
||||||
|
|
||||||
|
htmlparser2@9.1.0:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
domutils: 3.1.0
|
||||||
|
entities: 4.5.0
|
||||||
|
|
||||||
http-cache-semantics@4.1.1:
|
http-cache-semantics@4.1.1:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
@ -23621,6 +23837,16 @@ snapshots:
|
||||||
readable-stream: 2.3.7
|
readable-stream: 2.3.7
|
||||||
setimmediate: 1.0.5
|
setimmediate: 1.0.5
|
||||||
|
|
||||||
|
juice@10.0.1(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
cheerio: 1.0.0-rc.12
|
||||||
|
commander: 6.2.1
|
||||||
|
mensch: 0.3.4
|
||||||
|
slick: 1.12.2
|
||||||
|
web-resource-inliner: 6.0.1(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
jwa@1.4.1:
|
jwa@1.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer-equal-constant-time: 1.0.1
|
buffer-equal-constant-time: 1.0.1
|
||||||
|
@ -23983,6 +24209,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
get-func-name: 2.0.2
|
get-func-name: 2.0.2
|
||||||
|
|
||||||
|
lower-case@1.1.4: {}
|
||||||
|
|
||||||
lower-case@2.0.2:
|
lower-case@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
|
@ -24153,6 +24381,8 @@ snapshots:
|
||||||
|
|
||||||
memory-pager@1.5.0: {}
|
memory-pager@1.5.0: {}
|
||||||
|
|
||||||
|
mensch@0.3.4: {}
|
||||||
|
|
||||||
merge-descriptors@1.0.1: {}
|
merge-descriptors@1.0.1: {}
|
||||||
|
|
||||||
merge-stream@2.0.0: {}
|
merge-stream@2.0.0: {}
|
||||||
|
@ -24275,6 +24505,303 @@ snapshots:
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
pretender: 3.4.7
|
pretender: 3.4.7
|
||||||
|
|
||||||
|
mjml-accordion@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-body@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-button@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-carousel@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-cli@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
chokidar: 3.5.2
|
||||||
|
glob: 10.3.10
|
||||||
|
html-minifier: 4.0.0
|
||||||
|
js-beautify: 1.14.9
|
||||||
|
lodash: 4.17.21
|
||||||
|
minimatch: 9.0.5
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-migrate: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-parser-xml: 4.15.3
|
||||||
|
mjml-validator: 4.15.3
|
||||||
|
yargs: 17.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-column@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-core@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
cheerio: 1.0.0-rc.12
|
||||||
|
detect-node: 2.1.0
|
||||||
|
html-minifier: 4.0.0
|
||||||
|
js-beautify: 1.14.9
|
||||||
|
juice: 10.0.1(encoding@0.1.13)
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-migrate: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-parser-xml: 4.15.3
|
||||||
|
mjml-validator: 4.15.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-divider@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-group@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-attributes@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-breakpoint@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-font@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-html-attributes@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-preview@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-style@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head-title@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-head@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-hero@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-image@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-migrate@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
js-beautify: 1.14.9
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-parser-xml: 4.15.3
|
||||||
|
yargs: 17.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-navbar@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-parser-xml@4.15.3:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
detect-node: 2.1.0
|
||||||
|
htmlparser2: 9.1.0
|
||||||
|
lodash: 4.17.21
|
||||||
|
|
||||||
|
mjml-preset-core@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
mjml-accordion: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-body: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-button: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-carousel: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-column: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-divider: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-group: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-attributes: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-breakpoint: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-font: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-html-attributes: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-preview: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-style: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-head-title: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-hero: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-image: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-navbar: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-raw: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-section: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-social: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-spacer: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-table: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-text: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-wrapper: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-raw@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-section@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-social@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-spacer@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-table@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-text@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml-validator@4.15.3:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
|
||||||
|
mjml-wrapper@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
lodash: 4.17.21
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-section: 4.15.3(encoding@0.1.13)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
|
mjml@4.15.3(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
mjml-cli: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-core: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-migrate: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-preset-core: 4.15.3(encoding@0.1.13)
|
||||||
|
mjml-validator: 4.15.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
mkdirp-classic@0.5.3: {}
|
mkdirp-classic@0.5.3: {}
|
||||||
|
|
||||||
mkdirp@0.5.6:
|
mkdirp@0.5.6:
|
||||||
|
@ -24484,6 +25011,10 @@ snapshots:
|
||||||
|
|
||||||
neo-async@2.6.2: {}
|
neo-async@2.6.2: {}
|
||||||
|
|
||||||
|
no-case@2.3.2:
|
||||||
|
dependencies:
|
||||||
|
lower-case: 1.1.4
|
||||||
|
|
||||||
no-case@3.0.4:
|
no-case@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
lower-case: 2.0.2
|
lower-case: 2.0.2
|
||||||
|
@ -24923,6 +25454,10 @@ snapshots:
|
||||||
|
|
||||||
pako@1.0.11: {}
|
pako@1.0.11: {}
|
||||||
|
|
||||||
|
param-case@2.1.1:
|
||||||
|
dependencies:
|
||||||
|
no-case: 2.3.2
|
||||||
|
|
||||||
param-case@3.0.4:
|
param-case@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
dot-case: 3.0.4
|
dot-case: 3.0.4
|
||||||
|
@ -25819,6 +26354,8 @@ snapshots:
|
||||||
|
|
||||||
reinterval@1.1.0: {}
|
reinterval@1.1.0: {}
|
||||||
|
|
||||||
|
relateurl@0.2.7: {}
|
||||||
|
|
||||||
remove-trailing-slash@0.1.1: {}
|
remove-trailing-slash@0.1.1: {}
|
||||||
|
|
||||||
replace-in-file@6.3.5:
|
replace-in-file@6.3.5:
|
||||||
|
@ -26246,6 +26783,8 @@ snapshots:
|
||||||
astral-regex: 2.0.0
|
astral-regex: 2.0.0
|
||||||
is-fullwidth-code-point: 3.0.0
|
is-fullwidth-code-point: 3.0.0
|
||||||
|
|
||||||
|
slick@1.12.2: {}
|
||||||
|
|
||||||
slugify@1.4.7: {}
|
slugify@1.4.7: {}
|
||||||
|
|
||||||
smart-buffer@4.2.0:
|
smart-buffer@4.2.0:
|
||||||
|
@ -27159,8 +27698,7 @@ snapshots:
|
||||||
|
|
||||||
ufo@1.5.4: {}
|
ufo@1.5.4: {}
|
||||||
|
|
||||||
uglify-js@3.17.4:
|
uglify-js@3.17.4: {}
|
||||||
optional: true
|
|
||||||
|
|
||||||
uid-safe@2.1.5:
|
uid-safe@2.1.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -27302,6 +27840,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
|
|
||||||
|
upper-case@1.1.3: {}
|
||||||
|
|
||||||
upper-case@2.0.2:
|
upper-case@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
|
@ -27375,6 +27915,8 @@ snapshots:
|
||||||
'@types/istanbul-lib-coverage': 2.0.4
|
'@types/istanbul-lib-coverage': 2.0.4
|
||||||
convert-source-map: 1.9.0
|
convert-source-map: 1.9.0
|
||||||
|
|
||||||
|
valid-data-url@3.0.1: {}
|
||||||
|
|
||||||
validate-npm-package-license@3.0.4:
|
validate-npm-package-license@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
spdx-correct: 3.1.1
|
spdx-correct: 3.1.1
|
||||||
|
@ -27633,6 +28175,17 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
defaults: 1.0.4
|
defaults: 1.0.4
|
||||||
|
|
||||||
|
web-resource-inliner@6.0.1(encoding@0.1.13):
|
||||||
|
dependencies:
|
||||||
|
ansi-colors: 4.1.3
|
||||||
|
escape-goat: 3.0.0
|
||||||
|
htmlparser2: 5.0.1
|
||||||
|
mime: 2.6.0
|
||||||
|
node-fetch: 2.7.0(encoding@0.1.13)
|
||||||
|
valid-data-url: 3.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
web-streams-polyfill@3.2.1: {}
|
web-streams-polyfill@3.2.1: {}
|
||||||
|
|
||||||
web-streams-polyfill@4.0.0-beta.3: {}
|
web-streams-polyfill@4.0.0-beta.3: {}
|
||||||
|
|
Loading…
Reference in a new issue