@syncello/auth 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/index.cjs +210 -276
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -1
- package/dist/index.d.ts +55 -1
- package/dist/index.js +209 -276
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -997,36 +997,140 @@ function escapeHtml(text) {
|
|
|
997
997
|
}
|
|
998
998
|
|
|
999
999
|
// src/core/email-template.ts
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1000
|
+
var FONT = "'Montserrat',Arial,sans-serif";
|
|
1001
|
+
var PAGE = "#f4f5f7";
|
|
1002
|
+
var BODY_TEXT = "#404040";
|
|
1003
|
+
var MUTED = "#737373";
|
|
1004
|
+
var RULE = "#e5e7eb";
|
|
1005
|
+
var TABLE = 'width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;"';
|
|
1006
|
+
function logoDimensions(width, height) {
|
|
1007
|
+
if (width === void 0 && height === void 0) return null;
|
|
1008
|
+
if (width === void 0 || height === void 0) {
|
|
1009
|
+
throw new Error("logoWidth and logoHeight must be given together");
|
|
1010
|
+
}
|
|
1011
|
+
return { width: pixels("logoWidth", width), height: pixels("logoHeight", height) };
|
|
1012
|
+
}
|
|
1013
|
+
function pixels(name, value) {
|
|
1014
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
|
|
1015
|
+
throw new Error(`${name} must be a positive integer`);
|
|
1016
|
+
}
|
|
1017
|
+
return escapeHtml(String(value));
|
|
1018
|
+
}
|
|
1019
|
+
function brandColours(branding) {
|
|
1020
|
+
return {
|
|
1021
|
+
buttonBgColor: escapeHtml(branding.buttonBgColor ?? "#00fe9a"),
|
|
1022
|
+
buttonTextColor: escapeHtml(branding.buttonTextColor ?? "#000004"),
|
|
1023
|
+
buttonFontWeight: escapeHtml(String(branding.buttonFontWeight ?? 500)),
|
|
1024
|
+
buttonRadius: escapeHtml(branding.buttonRadius ?? "6px"),
|
|
1025
|
+
footerColor: escapeHtml(branding.footerColor ?? "#1e1b4b"),
|
|
1026
|
+
headingColor: escapeHtml(branding.headingColor ?? "#1e1b4b")
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
function logoUrlFor(logoUrl, appUrl) {
|
|
1030
|
+
if (logoUrl) return escapeHtml(sanitizeEmailUrl(logoUrl, appUrl));
|
|
1031
|
+
const base = appUrl ? sanitizeEmailUrl(appUrl, appUrl) : "";
|
|
1032
|
+
return escapeHtml(`${base.replace(/\/$/, "")}/email-header-image.png`);
|
|
1033
|
+
}
|
|
1034
|
+
function marketingUrlFor(marketingUrl) {
|
|
1035
|
+
return marketingUrl ? escapeHtml(sanitizeEmailUrl(marketingUrl, marketingUrl).replace(/\/$/, "")) : "";
|
|
1036
|
+
}
|
|
1037
|
+
var cardRow = (padding, content) => `
|
|
1038
|
+
<table ${TABLE}>
|
|
1039
|
+
<tr>
|
|
1040
|
+
<td class="pad" style="${padding}">
|
|
1041
|
+
${content}
|
|
1042
|
+
</td>
|
|
1043
|
+
</tr>
|
|
1044
|
+
</table>`;
|
|
1045
|
+
function logoBlock({ logoUrl, logoSize, appName }) {
|
|
1046
|
+
const img = logoSize ? `<img src="${logoUrl}" width="${logoSize.width}" height="${logoSize.height}" style="width: ${logoSize.width}px; max-width: 100%; height: auto; display: block; border: 0;" alt="${appName}" title="${appName}">` : `<div class="fullWidth" style="max-width: 50%;">
|
|
1047
|
+
<img src="${logoUrl}" style="display: block; height: auto; border: 0; width: 100%;" alt="${appName}" title="${appName}" height="auto">
|
|
1048
|
+
</div>`;
|
|
1049
|
+
return `
|
|
1050
|
+
<!-- Header Image -->
|
|
1051
|
+
<table class="image_block" ${TABLE}>
|
|
1052
|
+
<tr>
|
|
1053
|
+
<td class="pad" style="padding-top:40px;padding-left:40px;padding-right:40px;padding-bottom:8px;">
|
|
1054
|
+
<div class="alignment" align="center">
|
|
1055
|
+
${img}
|
|
1056
|
+
</div>
|
|
1057
|
+
</td>
|
|
1058
|
+
</tr>
|
|
1059
|
+
</table>`;
|
|
1060
|
+
}
|
|
1061
|
+
function buttonBlock({ label, url }, brand) {
|
|
1062
|
+
const font = `font-family: ${FONT}; font-size: 16px; font-weight: ${brand.buttonFontWeight};`;
|
|
1063
|
+
return `
|
|
1064
|
+
<!-- Button -->${cardRow(
|
|
1065
|
+
"padding-top:8px;padding-bottom:32px;padding-left:40px;padding-right:40px;text-align:center;",
|
|
1066
|
+
`<div class="alignment" align="center">
|
|
1067
|
+
<!--[if mso]>
|
|
1068
|
+
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${url}" style="height:48px;width:auto;v-text-anchor:middle;" arcsize="12%" fillcolor="${brand.buttonBgColor}">
|
|
1069
|
+
<v:stroke dashstyle="Solid" weight="0px" color="${brand.buttonBgColor}"/>
|
|
1070
|
+
<w:anchorlock/>
|
|
1071
|
+
<v:textbox inset="0px,0px,0px,0px">
|
|
1072
|
+
<center dir="false" style="color:${brand.buttonTextColor};${font}">
|
|
1073
|
+
<![endif]-->
|
|
1074
|
+
<a href="${url}" style="background-color: ${brand.buttonBgColor}; border: 0px solid transparent; border-radius: ${brand.buttonRadius}; color: ${brand.buttonTextColor}; display: inline-block; ${font} line-height: 24px; mso-border-alt: none; padding: 12px 28px; text-align: center; text-decoration: none; word-break: keep-all;">${label}</a>
|
|
1075
|
+
<!--[if mso]>
|
|
1076
|
+
</center>
|
|
1077
|
+
</v:textbox>
|
|
1078
|
+
</v:roundrect>
|
|
1079
|
+
<![endif]-->
|
|
1080
|
+
</div>`
|
|
1081
|
+
)}
|
|
1082
|
+
|
|
1083
|
+
<!-- Copy Link -->${cardRow(
|
|
1084
|
+
"padding-bottom:24px;padding-left:40px;padding-right:40px;",
|
|
1085
|
+
`<div style="border-top: 1px solid ${RULE}; padding-top: 16px; color:${MUTED};font-family:${FONT};font-size:12px;line-height:1.5;text-align:left;mso-line-height-alt:18px;">
|
|
1086
|
+
<p style="margin: 0 0 4px 0; word-break: break-word;">Or copy and paste this link into your browser:</p>
|
|
1087
|
+
<a href="${url}" style="color:${MUTED};text-decoration:underline;word-break:break-all;">${url}</a>
|
|
1088
|
+
</div>`
|
|
1089
|
+
)}`;
|
|
1090
|
+
}
|
|
1091
|
+
function renderLayout(parts) {
|
|
1092
|
+
const { brand } = parts;
|
|
1093
|
+
const welcome = parts.welcome ? `
|
|
1094
|
+
<!-- Welcome Message -->${cardRow(
|
|
1095
|
+
"padding-top:24px;padding-left:40px;padding-right:40px;",
|
|
1096
|
+
`<div style="color:${brand.headingColor};font-family:${FONT};font-size:20px;font-weight:600;line-height:1.4;text-align:left;mso-line-height-alt:28px;">
|
|
1097
|
+
<p style="margin: 0; word-break: break-word;">${parts.welcome}</p>
|
|
1098
|
+
</div>`
|
|
1099
|
+
)}` : "";
|
|
1100
|
+
const heading = parts.heading ? `
|
|
1101
|
+
<!-- Heading -->${cardRow(
|
|
1102
|
+
"padding-top:24px;padding-left:40px;padding-right:40px;",
|
|
1103
|
+
`<div style="color:${brand.headingColor};font-family:${FONT};font-size:24px;font-weight:700;line-height:1.3;text-align:left;mso-line-height-alt:31px;">
|
|
1104
|
+
<p style="margin: 0; word-break: break-word;">${parts.heading}</p>
|
|
1105
|
+
</div>`
|
|
1106
|
+
)}` : "";
|
|
1107
|
+
const notice = parts.notice ? `
|
|
1108
|
+
<!-- Notice -->${cardRow(
|
|
1109
|
+
"padding-bottom:24px;padding-left:40px;padding-right:40px;",
|
|
1110
|
+
`<table ${TABLE.replace('style="', `style="background-color: ${PAGE}; border-left: 3px solid ${brand.headingColor}; border-radius: 4px; `)}>
|
|
1111
|
+
<tr>
|
|
1112
|
+
<td style="padding: 14px 16px; color: ${BODY_TEXT}; font-family: ${FONT}; font-size: 13px; line-height: 1.5; text-align: left;">
|
|
1113
|
+
${parts.notice}
|
|
1114
|
+
</td>
|
|
1115
|
+
</tr>
|
|
1116
|
+
</table>`
|
|
1117
|
+
)}` : "";
|
|
1118
|
+
const footerNote = parts.footerNote ? `
|
|
1119
|
+
<!-- Footer Note -->${cardRow(
|
|
1120
|
+
"padding-bottom:32px;padding-left:40px;padding-right:40px;",
|
|
1121
|
+
`<div style="color:${MUTED};font-family:${FONT};font-size:13px;line-height:1.5;text-align:left;mso-line-height-alt:20px;">
|
|
1122
|
+
<p style="margin: 0; word-break: break-word;">${parts.footerNote}</p>
|
|
1123
|
+
</div>`
|
|
1124
|
+
)}` : "";
|
|
1125
|
+
const links = parts.marketingUrl ? `
|
|
1126
|
+
<p style="margin: 0 0 12px 0; word-break: break-word;">
|
|
1127
|
+
<a href="${parts.marketingUrl}/privacy" style="color: #ffffff; text-decoration: underline;">Privacy Policy</a> | <a href="${parts.marketingUrl}/contact" style="color: #ffffff; text-decoration: underline;">Get in Touch</a>
|
|
1128
|
+
</p>` : "";
|
|
1025
1129
|
return `
|
|
1026
1130
|
<!DOCTYPE html>
|
|
1027
1131
|
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" lang="en">
|
|
1028
1132
|
<head>
|
|
1029
|
-
<title>${
|
|
1133
|
+
<title>${parts.title}</title>
|
|
1030
1134
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
1031
1135
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1032
1136
|
<!--[if mso]>
|
|
@@ -1041,7 +1145,7 @@ function generateEmailTemplate(options) {
|
|
|
1041
1145
|
</xml>
|
|
1042
1146
|
<![endif]-->
|
|
1043
1147
|
<!--[if !mso]><!-->
|
|
1044
|
-
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@
|
|
1148
|
+
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet" type="text/css">
|
|
1045
1149
|
<!--<![endif]-->
|
|
1046
1150
|
<style>
|
|
1047
1151
|
* {
|
|
@@ -1062,13 +1166,6 @@ function generateEmailTemplate(options) {
|
|
|
1062
1166
|
p {
|
|
1063
1167
|
line-height: inherit;
|
|
1064
1168
|
}
|
|
1065
|
-
.desktop_hide,
|
|
1066
|
-
.desktop_hide table {
|
|
1067
|
-
mso-hide: all;
|
|
1068
|
-
display: none;
|
|
1069
|
-
max-height: 0px;
|
|
1070
|
-
overflow: hidden;
|
|
1071
|
-
}
|
|
1072
1169
|
.image_block img+div {
|
|
1073
1170
|
display: none;
|
|
1074
1171
|
}
|
|
@@ -1077,41 +1174,16 @@ function generateEmailTemplate(options) {
|
|
|
1077
1174
|
line-height: 0;
|
|
1078
1175
|
}
|
|
1079
1176
|
@media (max-width:660px) {
|
|
1080
|
-
.
|
|
1081
|
-
|
|
1082
|
-
}
|
|
1083
|
-
.icons-inner {
|
|
1084
|
-
text-align: center;
|
|
1085
|
-
}
|
|
1086
|
-
.icons-inner td {
|
|
1087
|
-
margin: 0 auto;
|
|
1088
|
-
}
|
|
1089
|
-
.mobile_hide {
|
|
1090
|
-
display: none;
|
|
1177
|
+
.page {
|
|
1178
|
+
padding: 16px 8px !important;
|
|
1091
1179
|
}
|
|
1092
1180
|
.row-content {
|
|
1093
1181
|
width: 100% !important;
|
|
1094
1182
|
max-width: 100% !important;
|
|
1095
1183
|
}
|
|
1096
|
-
.stack .column {
|
|
1097
|
-
width: 100%;
|
|
1098
|
-
display: block;
|
|
1099
|
-
}
|
|
1100
|
-
.mobile_hide {
|
|
1101
|
-
min-height: 0;
|
|
1102
|
-
max-height: 0;
|
|
1103
|
-
max-width: 0;
|
|
1104
|
-
overflow: hidden;
|
|
1105
|
-
font-size: 0px;
|
|
1106
|
-
}
|
|
1107
|
-
.desktop_hide,
|
|
1108
|
-
.desktop_hide table {
|
|
1109
|
-
display: table !important;
|
|
1110
|
-
max-height: none !important;
|
|
1111
|
-
}
|
|
1112
1184
|
.pad {
|
|
1113
|
-
padding-left:
|
|
1114
|
-
padding-right:
|
|
1185
|
+
padding-left: 24px !important;
|
|
1186
|
+
padding-right: 24px !important;
|
|
1115
1187
|
}
|
|
1116
1188
|
}
|
|
1117
1189
|
</style>
|
|
@@ -1123,235 +1195,46 @@ function generateEmailTemplate(options) {
|
|
|
1123
1195
|
</style>
|
|
1124
1196
|
<![endif]-->
|
|
1125
1197
|
</head>
|
|
1126
|
-
<body class="body" style="background-color:
|
|
1127
|
-
<table class="nl-container"
|
|
1198
|
+
<body class="body" style="background-color: ${PAGE}; margin: 0; padding: 0; -webkit-text-size-adjust: none; text-size-adjust: none;">
|
|
1199
|
+
<table class="nl-container" ${TABLE.replace('style="', `style="background-color: ${PAGE}; `)}>
|
|
1128
1200
|
<tbody>
|
|
1129
1201
|
<tr>
|
|
1130
|
-
<td>
|
|
1131
|
-
<!--
|
|
1132
|
-
<table class="row
|
|
1202
|
+
<td class="page" style="padding: 32px 16px;">
|
|
1203
|
+
<!-- Card -->
|
|
1204
|
+
<table class="row-content" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #ffffff; border: 1px solid ${RULE}; border-radius: 12px; max-width: 640px; width: 100%; margin: 0 auto;">
|
|
1133
1205
|
<tbody>
|
|
1134
1206
|
<tr>
|
|
1135
|
-
<td>
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
<span style="word-break: break-word;"> </span>
|
|
1150
|
-
</td>
|
|
1151
|
-
</tr>
|
|
1152
|
-
</table>
|
|
1153
|
-
</div>
|
|
1154
|
-
</td>
|
|
1155
|
-
</tr>
|
|
1156
|
-
</table>
|
|
1207
|
+
<td width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; text-align: left; vertical-align: top;">
|
|
1208
|
+
${logoBlock(parts)}
|
|
1209
|
+
${welcome}
|
|
1210
|
+
${heading}
|
|
1211
|
+
|
|
1212
|
+
<!-- Body Text -->${cardRow(
|
|
1213
|
+
"padding-top:16px;padding-bottom:24px;padding-left:40px;padding-right:40px;",
|
|
1214
|
+
`<div style="color:${BODY_TEXT};font-family:${FONT};font-size:15px;line-height:1.6;text-align:left;mso-line-height-alt:24px;">
|
|
1215
|
+
${parts.body}
|
|
1216
|
+
</div>`
|
|
1217
|
+
)}
|
|
1218
|
+
${parts.button ? buttonBlock(parts.button, brand) : ""}
|
|
1219
|
+
${notice}
|
|
1220
|
+
${footerNote}
|
|
1157
1221
|
|
|
1158
|
-
<!-- Header Image -->
|
|
1159
|
-
<table class="image_block block-2" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
|
|
1160
|
-
<tr>
|
|
1161
|
-
<td class="pad" style="padding-left:40px;padding-right:40px;width:100%;">
|
|
1162
|
-
<div class="alignment" align="center">
|
|
1163
|
-
<div class="fullWidth" style="max-width: 50%;">
|
|
1164
|
-
<img src="${safeLogoUrl}" style="display: block; height: auto; border: 0; width: 100%;" alt="${safeAppName}" title="${safeAppName}" height="auto">
|
|
1165
|
-
</div>
|
|
1166
|
-
</div>
|
|
1167
|
-
</td>
|
|
1168
|
-
</tr>
|
|
1169
|
-
</table>
|
|
1170
|
-
|
|
1171
|
-
${welcomeMessage ? `
|
|
1172
|
-
<!-- Welcome Message -->
|
|
1173
|
-
<table class="paragraph_block" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1174
|
-
<tr>
|
|
1175
|
-
<td class="pad" style="padding-top:30px;padding-left:40px;padding-right:40px;">
|
|
1176
|
-
<div style="color:${headingColor};font-family:'Montserrat',Arial,sans-serif;font-size:22px;font-weight:600;line-height:1.4;text-align:center;mso-line-height-alt:31px;">
|
|
1177
|
-
<p style="margin: 0; word-break: break-word;">${welcomeMessage}</p>
|
|
1178
|
-
</div>
|
|
1179
|
-
</td>
|
|
1180
|
-
</tr>
|
|
1181
|
-
</table>
|
|
1182
|
-
` : ""}
|
|
1183
|
-
|
|
1184
|
-
${heading ? `
|
|
1185
|
-
<!-- Heading -->
|
|
1186
|
-
<table class="paragraph_block block-4" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1187
|
-
<tr>
|
|
1188
|
-
<td class="pad" style="padding-bottom:10px;padding-left:40px;padding-right:40px;padding-top:10px;">
|
|
1189
|
-
<div style="color:${headingColor};font-family:'Montserrat',Arial,sans-serif;font-size:30px;font-weight:700;line-height:1.2;text-align:center;mso-line-height-alt:36px;">
|
|
1190
|
-
<p style="margin: 0; word-break: break-word;">${heading}</p>
|
|
1191
|
-
</div>
|
|
1192
|
-
</td>
|
|
1193
|
-
</tr>
|
|
1194
|
-
</table>
|
|
1195
|
-
` : ""}
|
|
1196
|
-
|
|
1197
|
-
<!-- Body Text -->
|
|
1198
|
-
<table class="paragraph_block block-5" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1199
|
-
<tr>
|
|
1200
|
-
<td class="pad" style="padding-bottom:30px;padding-left:40px;padding-right:40px;padding-top:30px;">
|
|
1201
|
-
<div style="color:#404040;font-family:'Montserrat',Arial,sans-serif;font-size:15px;line-height:1.6;text-align:left;mso-line-height-alt:24px;">
|
|
1202
|
-
<p style="margin: 0; word-break: break-word;">${body}</p>
|
|
1203
|
-
</div>
|
|
1204
|
-
</td>
|
|
1205
|
-
</tr>
|
|
1206
|
-
</table>
|
|
1207
|
-
|
|
1208
|
-
${safeButtonUrl ? `
|
|
1209
|
-
<!-- Button -->
|
|
1210
|
-
<table class="button_block block-6" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
|
|
1211
|
-
<tr>
|
|
1212
|
-
<td class="pad" style="padding-left:10px;padding-right:10px;padding-bottom:10px;text-align:center;">
|
|
1213
|
-
<div class="alignment" align="center">
|
|
1214
|
-
<!--[if mso]>
|
|
1215
|
-
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${safeButtonUrl}" style="height:52px;width:auto;v-text-anchor:middle;" arcsize="12%" fillcolor="${buttonBgColor}">
|
|
1216
|
-
<v:stroke dashstyle="Solid" weight="0px" color="${buttonBgColor}"/>
|
|
1217
|
-
<w:anchorlock/>
|
|
1218
|
-
<v:textbox inset="0px,0px,0px,0px">
|
|
1219
|
-
<center dir="false" style="color:${buttonTextColor};font-family:'Montserrat',Arial,sans-serif;font-size:16px;font-weight:${buttonFontWeight};">
|
|
1220
|
-
<![endif]-->
|
|
1221
|
-
<a href="${safeButtonUrl}" style="background-color: ${buttonBgColor}; border: 0px solid transparent; border-radius: ${buttonRadius}; color: ${buttonTextColor}; display: inline-block; font-family: 'Montserrat', Arial, sans-serif; font-size: 16px; font-weight: ${buttonFontWeight}; mso-border-alt: none; padding: 10px 20px; text-align: center; text-decoration: none; text-transform: capitalize; word-break: keep-all;">
|
|
1222
|
-
${buttonText}
|
|
1223
|
-
</a>
|
|
1224
|
-
<!--[if mso]>
|
|
1225
|
-
</center>
|
|
1226
|
-
</v:textbox>
|
|
1227
|
-
</v:roundrect>
|
|
1228
|
-
<![endif]-->
|
|
1229
|
-
</div>
|
|
1230
|
-
</td>
|
|
1231
|
-
</tr>
|
|
1232
|
-
</table>
|
|
1233
|
-
|
|
1234
|
-
<!-- Copy Link -->
|
|
1235
|
-
<table class="paragraph_block" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1236
|
-
<tr>
|
|
1237
|
-
<td class="pad" style="padding-bottom:30px;padding-left:40px;padding-right:40px;">
|
|
1238
|
-
<div style="color:#737373;font-family:'Montserrat',Arial,sans-serif;font-size:12px;line-height:1.5;text-align:center;mso-line-height-alt:18px;">
|
|
1239
|
-
<p style="margin: 0 0 5px 0; word-break: break-word;">or copy and paste this link into your browser:</p>
|
|
1240
|
-
<a href="${safeButtonUrl}" style="color:#4a90d9;text-decoration:underline;word-break:break-all;">${safeButtonUrl}</a>
|
|
1241
|
-
</div>
|
|
1242
|
-
</td>
|
|
1243
|
-
</tr>
|
|
1244
|
-
</table>
|
|
1245
|
-
` : ""}
|
|
1246
|
-
|
|
1247
|
-
${securityWarning ? `
|
|
1248
|
-
<!-- Security Warning -->
|
|
1249
|
-
<table class="paragraph_block" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1250
|
-
<tr>
|
|
1251
|
-
<td class="pad" style="padding-left:40px;padding-right:40px;padding-bottom:20px;">
|
|
1252
|
-
<div style="background-color: #a1f1ff; border-radius: 8px; padding: 16px; display: flex; align-items: center; justify-content: center;">
|
|
1253
|
-
<p style="margin: 0; color: #01001b; font-family: 'Montserrat', Arial, sans-serif; font-size: 13px; line-height: 1.5; text-align: center;">
|
|
1254
|
-
${securityWarning}
|
|
1255
|
-
</p>
|
|
1256
|
-
</div>
|
|
1257
|
-
</td>
|
|
1258
|
-
</tr>
|
|
1259
|
-
</table>
|
|
1260
|
-
` : ""}
|
|
1261
|
-
|
|
1262
|
-
<!-- Footer Note -->
|
|
1263
|
-
<table class="paragraph_block" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1264
|
-
<tr>
|
|
1265
|
-
<td class="pad" style="padding-bottom:30px;padding-left:40px;padding-right:40px;">
|
|
1266
|
-
<div style="color:#737373;font-family:'Montserrat',Arial,sans-serif;font-size:13px;line-height:1.5;text-align:center;mso-line-height-alt:20px;">
|
|
1267
|
-
<p style="margin: 0; word-break: break-word;">${footerNote}</p>
|
|
1268
|
-
</div>
|
|
1269
|
-
</td>
|
|
1270
|
-
</tr>
|
|
1271
|
-
</table>
|
|
1272
|
-
|
|
1273
|
-
</td>
|
|
1274
|
-
</tr>
|
|
1275
|
-
</tbody>
|
|
1276
|
-
</table>
|
|
1277
1222
|
</td>
|
|
1278
1223
|
</tr>
|
|
1279
1224
|
</tbody>
|
|
1280
1225
|
</table>
|
|
1281
1226
|
|
|
1282
|
-
<!--
|
|
1283
|
-
<table class="row
|
|
1227
|
+
<!-- Footer -->
|
|
1228
|
+
<table class="row-content" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: ${brand.footerColor}; border-radius: 12px; max-width: 640px; width: 100%; margin: 16px auto 0 auto;">
|
|
1284
1229
|
<tbody>
|
|
1285
1230
|
<tr>
|
|
1286
|
-
<td
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
<tr>
|
|
1290
|
-
<td class="column column-1" width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; padding-bottom: 5px; vertical-align: top;">
|
|
1291
|
-
<table class="empty_block block-1" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
|
|
1292
|
-
<tr>
|
|
1293
|
-
<td class="pad">
|
|
1294
|
-
<div></div>
|
|
1295
|
-
</td>
|
|
1296
|
-
</tr>
|
|
1297
|
-
</table>
|
|
1298
|
-
</td>
|
|
1299
|
-
</tr>
|
|
1300
|
-
</tbody>
|
|
1301
|
-
</table>
|
|
1302
|
-
</td>
|
|
1303
|
-
</tr>
|
|
1304
|
-
</tbody>
|
|
1305
|
-
</table>
|
|
1306
|
-
|
|
1307
|
-
<!-- Footer Row -->
|
|
1308
|
-
<table class="row row-3" align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
|
|
1309
|
-
<tbody>
|
|
1310
|
-
<tr>
|
|
1311
|
-
<td>
|
|
1312
|
-
<table class="row-content stack" align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: ${footerColor}; color: #000000; max-width: 640px; width: 100%; margin: 0 auto;">
|
|
1313
|
-
<tbody>
|
|
1314
|
-
<tr>
|
|
1315
|
-
<td class="column column-1" width="100%" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; vertical-align: top; padding: 20px;">
|
|
1316
|
-
|
|
1317
|
-
${safeMarketingUrl ? `
|
|
1318
|
-
<!-- Policy Links -->
|
|
1319
|
-
<table class="paragraph_block" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1320
|
-
<tr>
|
|
1321
|
-
<td class="pad" style="padding-bottom:20px;padding-left:40px;padding-right:40px;padding-top:20px;">
|
|
1322
|
-
<div style="color:#ffffff;font-family:'Montserrat',Arial,sans-serif;font-size:13px;line-height:1.5;text-align:center;mso-line-height-alt:20px;">
|
|
1323
|
-
<p style="margin: 0; word-break: break-word;">
|
|
1324
|
-
<a href="${safeMarketingUrl}/privacy" style="color: #ffffff; text-decoration: underline;">Privacy Policy</a> | <a href="${safeMarketingUrl}/contact" style="color: #ffffff; text-decoration: underline;">Get in Touch</a>
|
|
1325
|
-
</p>
|
|
1326
|
-
</div>
|
|
1327
|
-
</td>
|
|
1328
|
-
</tr>
|
|
1329
|
-
</table>
|
|
1330
|
-
` : ""}
|
|
1331
|
-
|
|
1332
|
-
<!-- Copyright & Disclaimer -->
|
|
1333
|
-
<table class="paragraph_block block-1" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;">
|
|
1334
|
-
<tr>
|
|
1335
|
-
<td class="pad" style="padding-bottom:15px;padding-left:40px;padding-right:40px;">
|
|
1336
|
-
<div style="color:#a3a3a3;font-family:'Montserrat',Arial,sans-serif;font-size:12px;line-height:1.5;text-align:center;mso-line-height-alt:18px;">
|
|
1337
|
-
<p style="margin: 0 0 12px 0; word-break: break-word;">\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${safeAppName}. All rights reserved.</p>
|
|
1338
|
-
<p style="margin: 0; font-size: 11px; line-height: 1.5; word-break: break-word;">
|
|
1339
|
-
Please do not reply to this email as this address does not accept incoming messages. This service email contains essential information relating to your ${safeAppName} account.
|
|
1340
|
-
</p>
|
|
1341
|
-
</div>
|
|
1342
|
-
</td>
|
|
1343
|
-
</tr>
|
|
1344
|
-
</table>
|
|
1345
|
-
|
|
1346
|
-
</td>
|
|
1347
|
-
</tr>
|
|
1348
|
-
</tbody>
|
|
1349
|
-
</table>
|
|
1231
|
+
<td class="pad" style="padding: 24px 40px; color:#a3a3a3; font-family:${FONT}; font-size:12px; line-height:1.5; text-align:center; mso-line-height-alt:18px;">${links}
|
|
1232
|
+
<p style="margin: 0 0 8px 0; word-break: break-word;">\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${parts.appName}. All rights reserved.</p>
|
|
1233
|
+
<p style="margin: 0; font-size: 11px; word-break: break-word;">Please do not reply to this email as this address does not accept incoming messages. This service email contains essential information relating to your ${parts.appName} account.</p>
|
|
1350
1234
|
</td>
|
|
1351
1235
|
</tr>
|
|
1352
1236
|
</tbody>
|
|
1353
1237
|
</table>
|
|
1354
|
-
|
|
1355
1238
|
</td>
|
|
1356
1239
|
</tr>
|
|
1357
1240
|
</tbody>
|
|
@@ -1360,6 +1243,55 @@ function generateEmailTemplate(options) {
|
|
|
1360
1243
|
</html>
|
|
1361
1244
|
`;
|
|
1362
1245
|
}
|
|
1246
|
+
function generateEmailTemplate(options) {
|
|
1247
|
+
const { appUrl, buttonUrl } = options;
|
|
1248
|
+
const safeButtonUrl = buttonUrl ? escapeHtml(sanitizeEmailUrl(buttonUrl, appUrl)) : "";
|
|
1249
|
+
return renderLayout({
|
|
1250
|
+
title: options.heading,
|
|
1251
|
+
logoUrl: logoUrlFor(options.logoUrl, appUrl),
|
|
1252
|
+
logoSize: logoDimensions(options.logoWidth, options.logoHeight),
|
|
1253
|
+
appName: escapeHtml(options.appName ?? "App"),
|
|
1254
|
+
welcome: options.welcomeMessage ?? "",
|
|
1255
|
+
heading: options.heading,
|
|
1256
|
+
body: options.body,
|
|
1257
|
+
button: safeButtonUrl ? { label: options.buttonText, url: safeButtonUrl } : null,
|
|
1258
|
+
notice: options.securityWarning?.trim() ?? "",
|
|
1259
|
+
footerNote: options.footerNote,
|
|
1260
|
+
marketingUrl: marketingUrlFor(options.marketingUrl),
|
|
1261
|
+
brand: brandColours(options)
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
function renderEmail(content) {
|
|
1265
|
+
const { appUrl, branding = {} } = content;
|
|
1266
|
+
const link = (url) => escapeHtml(sanitizeEmailUrl(url, appUrl));
|
|
1267
|
+
const text = (value) => escapeHtml(value).replace(/\r?\n/g, "<br>");
|
|
1268
|
+
const brand = brandColours(branding);
|
|
1269
|
+
const paragraphs = content.paragraphs.map(
|
|
1270
|
+
(p) => `<p style="margin: 0 0 16px 0; word-break: break-word;">${text(p)}</p>`
|
|
1271
|
+
);
|
|
1272
|
+
const sections = (content.sections ?? []).map((section) => {
|
|
1273
|
+
const title = section.url ? `<a href="${link(section.url)}" style="color: ${brand.headingColor}; font-weight: 600; text-decoration: none;">${text(section.title)}</a>` : `<span style="color: ${brand.headingColor}; font-weight: 600;">${text(section.title)}</span>`;
|
|
1274
|
+
const rows = section.rows.map(
|
|
1275
|
+
(row) => `<li style="margin: 0 0 4px 0;">${row.url ? `<a href="${link(row.url)}" style="color: ${BODY_TEXT}; text-decoration: underline;">${text(row.text)}</a>` : text(row.text)}</li>`
|
|
1276
|
+
);
|
|
1277
|
+
return `<p style="margin: 8px 0 4px 0; word-break: break-word;">${title}</p>
|
|
1278
|
+
<ul style="margin: 0 0 16px 0; padding-left: 20px;">${rows.join("")}</ul>`;
|
|
1279
|
+
});
|
|
1280
|
+
return renderLayout({
|
|
1281
|
+
title: escapeHtml(content.heading),
|
|
1282
|
+
logoUrl: logoUrlFor(branding.logoUrl, appUrl),
|
|
1283
|
+
logoSize: logoDimensions(branding.logoWidth, branding.logoHeight),
|
|
1284
|
+
appName: escapeHtml(content.appName ?? "App"),
|
|
1285
|
+
welcome: "",
|
|
1286
|
+
heading: escapeHtml(content.heading),
|
|
1287
|
+
body: [...paragraphs, ...sections].join("\n "),
|
|
1288
|
+
button: content.button ? { label: escapeHtml(content.button.label), url: link(content.button.url) } : null,
|
|
1289
|
+
notice: content.notice ? text(content.notice) : "",
|
|
1290
|
+
footerNote: content.footerNote ? text(content.footerNote) : "",
|
|
1291
|
+
marketingUrl: marketingUrlFor(branding.marketingUrl),
|
|
1292
|
+
brand
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1363
1295
|
|
|
1364
1296
|
// src/core/passwordless.ts
|
|
1365
1297
|
var PASSWORDLESS_TTL_MS = 10 * 60 * 1e3;
|
|
@@ -6040,6 +5972,7 @@ export {
|
|
|
6040
5972
|
rateLimit,
|
|
6041
5973
|
recentPasswordlessFailures,
|
|
6042
5974
|
refreshSession,
|
|
5975
|
+
renderEmail,
|
|
6043
5976
|
requestEmailChange,
|
|
6044
5977
|
requireAuth,
|
|
6045
5978
|
requireVerifiedEmail,
|