@cosmicdrift/kumiko-renderer-mail-html 0.368.0 → 0.370.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/dist/feature.d.ts +1 -1
- package/dist/feature.js +3 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/mail-footer.d.ts +7 -0
- package/dist/mail-footer.js +8 -1
- package/dist/render.d.ts +3 -2
- package/dist/render.js +26 -1
- package/dist/structured-layout.d.ts +1 -1
- package/package.json +7 -7
- package/src/changes.json +1 -1
package/dist/feature.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FeatureDefinition } from "@cosmicdrift/kumiko-types/feature";
|
|
2
|
-
import { type MailHtmlRenderOptions } from "./render.
|
|
2
|
+
import { type MailHtmlRenderOptions } from "./render.ts";
|
|
3
3
|
export declare function createRendererMailHtmlFeature(options?: MailHtmlRenderOptions): FeatureDefinition;
|
package/dist/feature.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import { mailHtmlRender } from "./render.js";
|
|
2
|
+
import { mailHtmlRender, readMailChrome } from "./render.js";
|
|
3
3
|
// renderer-mail-html: plugin for renderer-foundation, renders `kind="mail"`
|
|
4
4
|
// requests to subject + email-safe HTML + plain text.
|
|
5
5
|
//
|
|
@@ -19,12 +19,13 @@ import { mailHtmlRender } from "./render.js";
|
|
|
19
19
|
// the tenant-editable footer region, so a tenant cannot remove it.
|
|
20
20
|
export function createRendererMailHtmlFeature(options = {}) {
|
|
21
21
|
return defineFeature("renderer-mail-html", (r) => {
|
|
22
|
-
r.describe('A `renderer-foundation` plugin that handles `RenderRequest { kind: "mail" }` and returns `{ subject, html, text, previewText? }` suitable for sending via `channel-email`. The mail template (`kind: "mail"`, document HTML, subject in `meta`) resolves through `template-resolver`\'s DB fallback, its body is compiled to Handlebars by template-resolver and rendered with escaping, then placed into an MJML layout (`kind: "mail-layout"`, slug `default` unless `meta.layoutSlug` says otherwise, an in-code structured layout with the tenant branding logo and accent color as last resort) that `mjml()` compiles to email-safe table HTML, with `html-to-text` producing the plain-text alternative. An optional `footer` resolver adds the platform imprint, privacy link and footer text below every structured layout, an optional `brandSuffix` resolver adds a word after the tenant name in the brand row of the in-code layout, and an optional `siteUrl` resolver supplies the site link of the card when the tenant branding has no site URL (without either, the link is left out). The brand row and `data-resource="logo"` images use the branding logo upload, or the branding logo https address when no file is uploaded. Mail meta `headerChip`, `tone` and `footerNote` add a chip beside the brand, the tone of the top line and chip, and a note above the site and unsubscribe links of the card. Seed an editable system layout with `seedSystemMailLayout(db)`. Requires `renderer-foundation` + `template-resolver`.');
|
|
22
|
+
r.describe('A `renderer-foundation` plugin that handles `RenderRequest { kind: "mail" }` and returns `{ subject, html, text, previewText? }` suitable for sending via `channel-email`. The mail template (`kind: "mail"`, document HTML, subject in `meta`) resolves through `template-resolver`\'s DB fallback, its body is compiled to Handlebars by template-resolver and rendered with escaping, then placed into an MJML layout (`kind: "mail-layout"`, slug `default` unless `meta.layoutSlug` says otherwise, an in-code structured layout with the tenant branding logo and accent color as last resort) that `mjml()` compiles to email-safe table HTML, with `html-to-text` producing the plain-text alternative. An optional `footer` resolver adds the platform imprint, privacy link and footer text below every structured layout, an optional `brandSuffix` resolver adds a word after the tenant name in the brand row of the in-code layout, and an optional `siteUrl` resolver supplies the site link of the card when the tenant branding has no site URL (without either, the link is left out). The brand row and `data-resource="logo"` images use the branding logo upload, or the branding logo https address when no file is uploaded. Mail meta `headerChip`, `tone` and `footerNote` add a chip beside the brand, the tone of the top line and chip, and a note above the site and unsubscribe links of the card. `readMailChrome` hands the same brand row and footer, resolved for one locale, to pages a recipient opens from a mail, such as the unsubscribe page. Seed an editable system layout with `seedSystemMailLayout(db)`. Requires `renderer-foundation` + `template-resolver`.');
|
|
23
23
|
r.requires({ features: ["renderer-foundation"] });
|
|
24
24
|
r.requires({ features: ["template-resolver"] });
|
|
25
25
|
r.useExtension("renderer", "mail-html", {
|
|
26
26
|
kinds: ["mail"],
|
|
27
27
|
render: (req, ctx) => mailHtmlRender(req, ctx, options),
|
|
28
|
+
readMailChrome: (req, ctx) => readMailChrome(req, ctx, options),
|
|
28
29
|
});
|
|
29
30
|
});
|
|
30
31
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { DEFAULT_MAIL_LAYOUT_MJML } from "./default-layout.
|
|
2
|
-
export { collectRegionResourceKeys, compileDocumentSource, createDocumentHandlebars, type DocumentFormat, mergeResourceFileRefs, readBrandingAccentColor, readDocumentFormat, readTenantName, resolveResourceFileRefs, } from "./document-kit.
|
|
3
|
-
export { createRendererMailHtmlFeature } from "./feature.
|
|
4
|
-
export type { MailFooter, MailFooterLink, MailFooterResolver } from "./mail-footer.
|
|
5
|
-
export { MAIL_CHROME_EN } from "./mail-strings.
|
|
6
|
-
export { type MailBrandSuffixResolver, type MailHtmlRenderOptions, type MailSiteUrlResolver, mailHtmlRender, } from "./render.
|
|
1
|
+
export { DEFAULT_MAIL_LAYOUT_MJML } from "./default-layout.ts";
|
|
2
|
+
export { collectRegionResourceKeys, compileDocumentSource, createDocumentHandlebars, type DocumentFormat, mergeResourceFileRefs, readBrandingAccentColor, readDocumentFormat, readTenantName, resolveResourceFileRefs, } from "./document-kit.ts";
|
|
3
|
+
export { createRendererMailHtmlFeature } from "./feature.ts";
|
|
4
|
+
export type { MailFooter, MailFooterLink, MailFooterResolver } from "./mail-footer.ts";
|
|
5
|
+
export { MAIL_CHROME_EN } from "./mail-strings.ts";
|
|
6
|
+
export { type MailBrandSuffixResolver, type MailHtmlRenderOptions, type MailSiteUrlResolver, mailHtmlRender, readMailChrome, } from "./render.ts";
|
package/dist/index.js
CHANGED
|
@@ -2,4 +2,4 @@ export { DEFAULT_MAIL_LAYOUT_MJML } from "./default-layout.js";
|
|
|
2
2
|
export { collectRegionResourceKeys, compileDocumentSource, createDocumentHandlebars, mergeResourceFileRefs, readBrandingAccentColor, readDocumentFormat, readTenantName, resolveResourceFileRefs, } from "./document-kit.js";
|
|
3
3
|
export { createRendererMailHtmlFeature } from "./feature.js";
|
|
4
4
|
export { MAIL_CHROME_EN } from "./mail-strings.js";
|
|
5
|
-
export { mailHtmlRender, } from "./render.js";
|
|
5
|
+
export { mailHtmlRender, readMailChrome, } from "./render.js";
|
package/dist/mail-footer.d.ts
CHANGED
|
@@ -13,12 +13,18 @@ export type MailFooterResolver = (input: {
|
|
|
13
13
|
readonly locale: string;
|
|
14
14
|
readonly ctx: RendererContext;
|
|
15
15
|
}) => MailFooter | null | Promise<MailFooter | null>;
|
|
16
|
+
type LabeledLink = {
|
|
17
|
+
readonly label: string;
|
|
18
|
+
readonly url: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function webHost(url: string): string | null;
|
|
16
21
|
export declare function buildMailBandLinksHtml(input: {
|
|
17
22
|
readonly siteUrl: string | undefined;
|
|
18
23
|
readonly unsubscribeUrl: string;
|
|
19
24
|
readonly locale: string;
|
|
20
25
|
readonly layoutLinksUnsubscribe: boolean;
|
|
21
26
|
}): string;
|
|
27
|
+
export declare function resolvedFooterLink(link: MailFooterLink | undefined, fallbackLabel: string): LabeledLink | undefined;
|
|
22
28
|
export declare function safeFooterUrl(link: MailFooterLink | undefined): string;
|
|
23
29
|
export declare function buildMailFooterHtml(input: {
|
|
24
30
|
readonly footer: MailFooter | null;
|
|
@@ -28,3 +34,4 @@ export declare function buildMailFooterHtml(input: {
|
|
|
28
34
|
readonly layoutLinksUnsubscribe: boolean;
|
|
29
35
|
}): string;
|
|
30
36
|
export declare function layoutLinksToPlaceholder(layoutHtml: string, name: string): boolean;
|
|
37
|
+
export {};
|
package/dist/mail-footer.js
CHANGED
|
@@ -8,7 +8,7 @@ function linkHtml(link, color = "#888") {
|
|
|
8
8
|
return null;
|
|
9
9
|
return `<a href="${escapeHtmlAttr(url)}" style="color:${escapeHtmlAttr(color)}">${escapeHtml(link.label)}</a>`;
|
|
10
10
|
}
|
|
11
|
-
function webHost(url) {
|
|
11
|
+
export function webHost(url) {
|
|
12
12
|
try {
|
|
13
13
|
const parsed = new URL(url);
|
|
14
14
|
return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.host : null;
|
|
@@ -33,6 +33,13 @@ export function buildMailBandLinksHtml(input) {
|
|
|
33
33
|
];
|
|
34
34
|
return links.filter((link) => link !== null).join(" · ");
|
|
35
35
|
}
|
|
36
|
+
export function resolvedFooterLink(link, fallbackLabel) {
|
|
37
|
+
if (link === undefined)
|
|
38
|
+
return undefined;
|
|
39
|
+
const url = link.url.trim();
|
|
40
|
+
const label = (link.label ?? fallbackLabel).trim();
|
|
41
|
+
return SAFE_FOOTER_URL.test(url) && label !== "" ? { label, url } : undefined;
|
|
42
|
+
}
|
|
36
43
|
export function safeFooterUrl(link) {
|
|
37
44
|
return link !== undefined && SAFE_FOOTER_URL.test(link.url.trim()) ? link.url.trim() : "";
|
|
38
45
|
}
|
package/dist/render.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type RendererContext, type RenderRequest, type RenderResponse } from "@cosmicdrift/kumiko-bundled-features/renderer-foundation";
|
|
2
|
-
import { type MailFooterResolver } from "./mail-footer.
|
|
1
|
+
import { type MailChromeRequest, type MailChrome as MailPageChrome, type RendererContext, type RenderRequest, type RenderResponse } from "@cosmicdrift/kumiko-bundled-features/renderer-foundation";
|
|
2
|
+
import { type MailFooterResolver } from "./mail-footer.ts";
|
|
3
3
|
export type MailBrandSuffixResolver = (input: {
|
|
4
4
|
readonly locale: string;
|
|
5
5
|
readonly ctx: RendererContext;
|
|
@@ -15,4 +15,5 @@ export type MailHtmlRenderOptions = {
|
|
|
15
15
|
/** Site link in the mail band when the tenant's branding has no site URL. */
|
|
16
16
|
readonly siteUrl?: MailSiteUrlResolver;
|
|
17
17
|
};
|
|
18
|
+
export declare function readMailChrome(req: MailChromeRequest, ctx: RendererContext, options?: MailHtmlRenderOptions): Promise<MailPageChrome>;
|
|
18
19
|
export declare function mailHtmlRender(req: RenderRequest, ctx: RendererContext, options?: MailHtmlRenderOptions): Promise<RenderResponse>;
|
package/dist/render.js
CHANGED
|
@@ -18,7 +18,7 @@ import { DEFAULT_MAIL_LAYOUT_SLUG } from "./default-layout.js";
|
|
|
18
18
|
import { collectRegionResourceKeys, compileDocumentSource, createDocumentHandlebars, LOGO_RESOURCE_KEY, mergeResourceFileRefs, readBrandingAccentColor, readBrandingLogo, readBrandingLogoUrl, readBrandingSiteUrl, readDocumentFormat, readTenantName, resolveResourceFileRefs, } from "./document-kit.js";
|
|
19
19
|
import { buildRenderedPdfAttachments, combineMailAttachments, mergeInheritedAttachments, } from "./mail-attachments.js";
|
|
20
20
|
import { brandHeaderHtml, DEFAULT_ACCENT_COLOR, readMailTone, toneColors, } from "./mail-chrome.js";
|
|
21
|
-
import { buildMailBandLinksHtml, buildMailFooterHtml, layoutLinksToPlaceholder, safeFooterUrl, } from "./mail-footer.js";
|
|
21
|
+
import { buildMailBandLinksHtml, buildMailFooterHtml, layoutLinksToPlaceholder, resolvedFooterLink, safeFooterUrl, webHost, } from "./mail-footer.js";
|
|
22
22
|
import { mailChromeText } from "./mail-strings.js";
|
|
23
23
|
import { MAIL_IMAGE_MAX_WIDTH_PX, renderStructuredLayoutMjml } from "./structured-layout.js";
|
|
24
24
|
const LINE_BREAKS = /[\r\n]+/g;
|
|
@@ -433,6 +433,31 @@ function renderFooterParts(args) {
|
|
|
433
433
|
: "",
|
|
434
434
|
};
|
|
435
435
|
}
|
|
436
|
+
export async function readMailChrome(req, ctx, options = {}) {
|
|
437
|
+
const { locale } = req;
|
|
438
|
+
const [tenantName, footer, siteUrl, brandSuffix, logoUrl, accentColor] = await Promise.all([
|
|
439
|
+
readTenantName(ctx),
|
|
440
|
+
resolveMailFooter(options, ctx, locale),
|
|
441
|
+
resolveMailSiteUrl(options, ctx, locale),
|
|
442
|
+
resolveBrandSuffix(options, ctx, locale),
|
|
443
|
+
readBrandingLogoUrl(ctx),
|
|
444
|
+
readBrandingAccentColor(ctx),
|
|
445
|
+
]);
|
|
446
|
+
const footerText = footer?.text?.trim() ?? "";
|
|
447
|
+
const imprint = resolvedFooterLink(footer?.imprint, mailChromeText(locale, "mail.footer.imprint"));
|
|
448
|
+
const privacy = resolvedFooterLink(footer?.privacy, mailChromeText(locale, "mail.footer.privacy"));
|
|
449
|
+
const safeSiteUrl = siteUrl?.trim();
|
|
450
|
+
return {
|
|
451
|
+
tenantName,
|
|
452
|
+
brandSuffix,
|
|
453
|
+
...(logoUrl !== undefined && { logoUrl }),
|
|
454
|
+
...(accentColor !== undefined && { accentColor }),
|
|
455
|
+
...(safeSiteUrl !== undefined && webHost(safeSiteUrl) !== null && { siteUrl: safeSiteUrl }),
|
|
456
|
+
...(footerText !== "" && { footerText }),
|
|
457
|
+
...(imprint !== undefined && { imprint }),
|
|
458
|
+
...(privacy !== undefined && { privacy }),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
436
461
|
export async function mailHtmlRender(req, ctx, options = {}) {
|
|
437
462
|
if (req.kind !== "mail") {
|
|
438
463
|
// Foundation selects plugins only for matching kinds; defensive guard.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MailLayoutAppearance } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
2
|
-
import { type ToneColors } from "./mail-chrome.
|
|
2
|
+
import { type ToneColors } from "./mail-chrome.ts";
|
|
3
3
|
export declare const MAIL_IMAGE_MAX_WIDTH_PX = 180;
|
|
4
4
|
export type StructuredLayoutInput = {
|
|
5
5
|
readonly layoutHtml: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-renderer-mail-html",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.370.0",
|
|
4
4
|
"description": "Renderer-Foundation plugin for branded HTML emails: mail-kind templates (document HTML + subject meta) rendered with isolated Handlebars into an MJML layout, plus plain text via html-to-text. Templates resolved from template-resolver.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
23
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
24
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
25
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
22
|
+
"@cosmicdrift/kumiko-bundled-features": "0.370.0",
|
|
23
|
+
"@cosmicdrift/kumiko-framework": "0.370.0",
|
|
24
|
+
"@cosmicdrift/kumiko-headless": "0.370.0",
|
|
25
|
+
"@cosmicdrift/kumiko-types": "0.370.0",
|
|
26
26
|
"handlebars": "^4.7.8",
|
|
27
27
|
"html-to-text": "^9.0.5",
|
|
28
28
|
"mjml": "^5.2.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
32
|
-
"@cosmicdrift/kumiko-testing": "0.
|
|
31
|
+
"@cosmicdrift/kumiko-locale-de": "0.370.0",
|
|
32
|
+
"@cosmicdrift/kumiko-testing": "0.370.0",
|
|
33
33
|
"@types/html-to-text": "^9.0.4",
|
|
34
34
|
"@types/mjml": "^5.0.0"
|
|
35
35
|
},
|
package/src/changes.json
CHANGED
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"version": "0.363.0",
|
|
79
79
|
"type": "breaking",
|
|
80
80
|
"title": "Package moved to the framework under the @cosmicdrift scope",
|
|
81
|
-
"detail": "Renamed from @cosmicdriftgamestudio/kumiko-renderer-mail-html (GitHub Packages, kumiko-enterprise) to @cosmicdrift/kumiko-renderer-mail-html on npmjs; the API
|
|
81
|
+
"detail": "Renamed from @cosmicdriftgamestudio/kumiko-renderer-mail-html (GitHub Packages, kumiko-enterprise) to @cosmicdrift/kumiko-renderer-mail-html on npmjs. The rename itself changes no API; the other 0.363.0 entries list the API changes of this release.",
|
|
82
82
|
"migration": "Replace @cosmicdriftgamestudio/kumiko-renderer-mail-html with @cosmicdrift/kumiko-renderer-mail-html in package.json and in every import; install from npmjs instead of GitHub Packages."
|
|
83
83
|
},
|
|
84
84
|
{
|