create-email-renderer 0.1.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 +119 -0
- package/dist/default-blocks.d.ts +5 -0
- package/dist/default-blocks.d.ts.map +1 -0
- package/dist/default-blocks.js +159 -0
- package/dist/default-blocks.js.map +1 -0
- package/dist/html-render.d.ts +14 -0
- package/dist/html-render.d.ts.map +1 -0
- package/dist/html-render.js +248 -0
- package/dist/html-render.js.map +1 -0
- package/dist/id.d.ts +2 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +4 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +11 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +106 -0
- package/dist/normalize.js.map +1 -0
- package/dist/richtext.d.ts +6 -0
- package/dist/richtext.d.ts.map +1 -0
- package/dist/richtext.js +61 -0
- package/dist/richtext.js.map +1 -0
- package/dist/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +59 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -0
- package/dist/types.js.map +1 -0
- package/dist/variables.d.ts +19 -0
- package/dist/variables.d.ts.map +1 -0
- package/dist/variables.js +74 -0
- package/dist/variables.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Normalización de payloads legacy o corruptos: completa props faltantes con
|
|
2
|
+
// los defaults de la blockLibrary, descarta tipos desconocidos, repara ids y
|
|
3
|
+
// coacciona tipos. Punto único de defensa para plantillas guardadas con una
|
|
4
|
+
// versión anterior del esquema (el editor al hidratar y el backend al parsear).
|
|
5
|
+
import { DEFAULT_BLOCK_LIBRARY, DEFAULT_SETTINGS, } from "./default-blocks.js";
|
|
6
|
+
import { newId } from "./id.js";
|
|
7
|
+
const coerceNumber = (value, fallback) => {
|
|
8
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
9
|
+
return value;
|
|
10
|
+
const parsed = parseFloat(String(value));
|
|
11
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
12
|
+
};
|
|
13
|
+
const normalizeColumns = (value, fallback) => {
|
|
14
|
+
if (!Array.isArray(value))
|
|
15
|
+
return fallback;
|
|
16
|
+
return value.map((col) => ({
|
|
17
|
+
id: typeof col?.id === "string" &&
|
|
18
|
+
col.id
|
|
19
|
+
? col.id
|
|
20
|
+
: newId(),
|
|
21
|
+
text: String(col?.text ?? ""),
|
|
22
|
+
}));
|
|
23
|
+
};
|
|
24
|
+
/** Rellena props faltantes/corruptas con los defaults del bloque y coacciona tipos. */
|
|
25
|
+
const normalizeProps = (rawProps, definition) => {
|
|
26
|
+
const props = structuredClone(definition.defaultProps);
|
|
27
|
+
const raw = rawProps && typeof rawProps === "object"
|
|
28
|
+
? rawProps
|
|
29
|
+
: {};
|
|
30
|
+
// Solo claves conocidas por el esquema actual: las props legadas desconocidas
|
|
31
|
+
// se descartan (así evolucionar el esquema no rompe plantillas viejas).
|
|
32
|
+
for (const key of Object.keys(props)) {
|
|
33
|
+
const value = raw[key];
|
|
34
|
+
if (value === undefined || value === null)
|
|
35
|
+
continue; // conserva el default
|
|
36
|
+
const fallback = props[key];
|
|
37
|
+
if (typeof fallback === "number") {
|
|
38
|
+
props[key] = coerceNumber(value, fallback);
|
|
39
|
+
}
|
|
40
|
+
else if (Array.isArray(fallback)) {
|
|
41
|
+
if (key === "items") {
|
|
42
|
+
props[key] = Array.isArray(value)
|
|
43
|
+
? value.map((item) => String(item))
|
|
44
|
+
: fallback;
|
|
45
|
+
}
|
|
46
|
+
else if (key === "columns") {
|
|
47
|
+
props[key] = normalizeColumns(value, fallback);
|
|
48
|
+
}
|
|
49
|
+
else if (Array.isArray(value)) {
|
|
50
|
+
props[key] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (typeof fallback === "string") {
|
|
54
|
+
props[key] = String(value);
|
|
55
|
+
}
|
|
56
|
+
else if (typeof fallback === "boolean") {
|
|
57
|
+
props[key] = Boolean(value);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
props[key] = value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return props;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Normaliza un array de bloques de origen desconocido (JSON de la BD, import,
|
|
67
|
+
* versión vieja del esquema): descarta tipos que no están en la librería,
|
|
68
|
+
* completa props con los defaults, repara ids faltantes y coacciona tipos.
|
|
69
|
+
* Nunca lanza.
|
|
70
|
+
*/
|
|
71
|
+
export const normalizeBlocks = (input, library = DEFAULT_BLOCK_LIBRARY) => {
|
|
72
|
+
if (!Array.isArray(input))
|
|
73
|
+
return [];
|
|
74
|
+
const blockMap = new Map(library.map((def) => [def.type, def]));
|
|
75
|
+
const blocks = [];
|
|
76
|
+
for (const raw of input) {
|
|
77
|
+
if (!raw || typeof raw !== "object")
|
|
78
|
+
continue;
|
|
79
|
+
const type = raw.type;
|
|
80
|
+
if (typeof type !== "string" || !blockMap.has(type)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const definition = blockMap.get(type);
|
|
84
|
+
const rawId = raw.id;
|
|
85
|
+
blocks.push({
|
|
86
|
+
id: typeof rawId === "string" && rawId ? rawId : newId(),
|
|
87
|
+
type: type,
|
|
88
|
+
props: normalizeProps(raw.props, definition),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return blocks;
|
|
92
|
+
};
|
|
93
|
+
/** Normaliza los settings: solo claves conocidas, coacción numérica, defaults. */
|
|
94
|
+
export const normalizeSettings = (input) => {
|
|
95
|
+
const raw = input && typeof input === "object"
|
|
96
|
+
? input
|
|
97
|
+
: {};
|
|
98
|
+
return {
|
|
99
|
+
pageBackground: typeof raw.pageBackground === "string"
|
|
100
|
+
? raw.pageBackground
|
|
101
|
+
: DEFAULT_SETTINGS.pageBackground,
|
|
102
|
+
cardBorderWidth: coerceNumber(raw.cardBorderWidth, DEFAULT_SETTINGS.cardBorderWidth),
|
|
103
|
+
cardBorderRadius: coerceNumber(raw.cardBorderRadius, DEFAULT_SETTINGS.cardBorderRadius),
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const sanitizeRichText: (html: string) => string;
|
|
2
|
+
export declare const escapeHtml: (text: string) => string;
|
|
3
|
+
export declare const isRichText: (content: string) => boolean;
|
|
4
|
+
export declare const normalizeBlockHtml: (html: string) => string;
|
|
5
|
+
export declare const renderRichText: (content: string) => string;
|
|
6
|
+
//# sourceMappingURL=richtext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"richtext.d.ts","sourceRoot":"","sources":["../src/richtext.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAe5C,CAAC;AAEL,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,MAKd,CAAC;AAE7B,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,OACT,CAAC;AAErC,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAKC,CAAC;AAmBpD,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAMhD,CAAC"}
|
package/dist/richtext.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import sanitizeHtml from "sanitize-html";
|
|
2
|
+
const RICH_TAGS = [
|
|
3
|
+
"p",
|
|
4
|
+
"br",
|
|
5
|
+
"strong",
|
|
6
|
+
"b",
|
|
7
|
+
"em",
|
|
8
|
+
"i",
|
|
9
|
+
"u",
|
|
10
|
+
"s",
|
|
11
|
+
"del",
|
|
12
|
+
"strike",
|
|
13
|
+
"code",
|
|
14
|
+
"a",
|
|
15
|
+
"ul",
|
|
16
|
+
"ol",
|
|
17
|
+
"li",
|
|
18
|
+
"span",
|
|
19
|
+
"blockquote",
|
|
20
|
+
];
|
|
21
|
+
export const sanitizeRichText = (html) => sanitizeHtml(html, {
|
|
22
|
+
allowedTags: RICH_TAGS,
|
|
23
|
+
allowedAttributes: {
|
|
24
|
+
a: ["href", "target", "rel", "style"],
|
|
25
|
+
span: ["style"],
|
|
26
|
+
},
|
|
27
|
+
allowedSchemes: ["http", "https", "mailto"],
|
|
28
|
+
transformTags: {
|
|
29
|
+
a: sanitizeHtml.simpleTransform("a", {
|
|
30
|
+
target: "_blank",
|
|
31
|
+
rel: "noopener",
|
|
32
|
+
style: "color:#a98a1e;text-decoration:underline;",
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
export const escapeHtml = (text) => text
|
|
37
|
+
.replace(/&/g, "&")
|
|
38
|
+
.replace(/</g, "<")
|
|
39
|
+
.replace(/>/g, ">")
|
|
40
|
+
.replace(/"/g, """);
|
|
41
|
+
export const isRichText = (content) => /<\/?[a-z][\s\S]*>/i.test(content);
|
|
42
|
+
export const normalizeBlockHtml = (html) => html
|
|
43
|
+
.replace(/<div([^>]*)>/gi, "<p$1>")
|
|
44
|
+
.replace(/<\/div>/gi, "</p>")
|
|
45
|
+
.replace(/<p[^>]*>\s*<br\s*\/?>\s*<\/p>/gi, "<p> </p>")
|
|
46
|
+
.replace(/<p[^>]*>\s*<\/p>/gi, "<p> </p>");
|
|
47
|
+
const applyRichInlineStyles = (html) => html
|
|
48
|
+
.replace(/<p(?![^>]*style=)/gi, '<p style="margin:0;padding:0"')
|
|
49
|
+
.replace(/<ul(?![^>]*style=)/gi, '<ul style="margin:0 0 6px;padding-left:20px"')
|
|
50
|
+
.replace(/<li(?![^>]*style=)/gi, '<li style="margin:0 0 4px"')
|
|
51
|
+
.replace(/<code(?![^>]*style=)/gi, '<code style="background:#f1e8dc;padding:1px 5px;border-radius:4px;font-size:0.9em"')
|
|
52
|
+
.replace(/<blockquote(?![^>]*style=)/gi, '<blockquote style="margin:0 0 6px;border-left:3px solid #d7b227;padding-left:12px"');
|
|
53
|
+
export const renderRichText = (content) => {
|
|
54
|
+
if (!content)
|
|
55
|
+
return "";
|
|
56
|
+
if (isRichText(content)) {
|
|
57
|
+
return applyRichInlineStyles(sanitizeRichText(normalizeBlockHtml(content)));
|
|
58
|
+
}
|
|
59
|
+
return `<span>${escapeHtml(content)}</span>`;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=richtext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"richtext.js","sourceRoot":"","sources":["../src/richtext.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,MAAM,SAAS,GAAG;IAChB,GAAG;IACH,IAAI;IACJ,QAAQ;IACR,GAAG;IACH,IAAI;IACJ,GAAG;IACH,GAAG;IACH,GAAG;IACH,KAAK;IACL,QAAQ;IACR,MAAM;IACN,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,YAAY;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAU,EAAE,CACvD,YAAY,CAAC,IAAI,EAAE;IACjB,WAAW,EAAE,SAAS;IACtB,iBAAiB,EAAE;QACjB,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC;QACrC,IAAI,EAAE,CAAC,OAAO,CAAC;KAChB;IACD,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;IAC3C,aAAa,EAAE;QACb,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,GAAG,EAAE;YACnC,MAAM,EAAE,QAAQ;YAChB,GAAG,EAAE,UAAU;YACf,KAAK,EAAE,0CAA0C;SAClD,CAAC;KACH;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAU,EAAE,CACjD,IAAI;KACD,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;KACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;KACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;KACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAE7B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAe,EAAW,EAAE,CACrD,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAErC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAU,EAAE,CACzD,IAAI;KACD,OAAO,CAAC,gBAAgB,EAAE,OAAO,CAAC;KAClC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;KAC5B,OAAO,CAAC,iCAAiC,EAAE,eAAe,CAAC;KAC3D,OAAO,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;AAEpD,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAU,EAAE,CACrD,IAAI;KACD,OAAO,CAAC,qBAAqB,EAAE,+BAA+B,CAAC;KAC/D,OAAO,CACN,sBAAsB,EACtB,8CAA8C,CAC/C;KACA,OAAO,CAAC,sBAAsB,EAAE,4BAA4B,CAAC;KAC7D,OAAO,CACN,wBAAwB,EACxB,oFAAoF,CACrF;KACA,OAAO,CACN,8BAA8B,EAC9B,oFAAoF,CACrF,CAAC;AAEN,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAU,EAAE;IACxD,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,qBAAqB,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,SAAS,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC;AAC/C,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EmailBlock, EmailContext, EmailPalette, EmailSettings } from "./types.js";
|
|
2
|
+
export interface TemplatePayload {
|
|
3
|
+
content: EmailBlock[];
|
|
4
|
+
settings: Partial<EmailSettings>;
|
|
5
|
+
}
|
|
6
|
+
export declare const parseTemplatePayload: (payload: string | object | null | undefined) => TemplatePayload;
|
|
7
|
+
export interface RenderTemplateEmailOptions {
|
|
8
|
+
subject: string;
|
|
9
|
+
payload: string | object | null | undefined;
|
|
10
|
+
context?: EmailContext;
|
|
11
|
+
settings?: Partial<EmailSettings>;
|
|
12
|
+
palette?: EmailPalette;
|
|
13
|
+
}
|
|
14
|
+
export interface RenderedTemplateEmail {
|
|
15
|
+
html: string;
|
|
16
|
+
subject: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Helper para renderizar una plantilla completa desde su payload JSON.
|
|
20
|
+
* Uso: `const {html, subject} = await renderTemplateEmail({subject, payload, context})`
|
|
21
|
+
*/
|
|
22
|
+
export declare const renderTemplateEmail: ({ subject, payload, context, settings: overrideSettings, palette, }: RenderTemplateEmailOptions) => Promise<RenderedTemplateEmail>;
|
|
23
|
+
export declare const buildTemplateContext: (base: EmailContext, extra?: Record<string, string | undefined | null>) => EmailContext;
|
|
24
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AAQpB,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CAClC;AAED,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,KAC1C,eAgBF,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAU,qEAMvC,0BAA0B,KAAG,OAAO,CAAC,qBAAqB,CAyB5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,YAAY,EAClB,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,KAChD,YAQF,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Entry server-safe: renderiza plantillas completas desde su payload JSON
|
|
2
|
+
// sin React. Pensado para route handlers / servicios (Node, Workers, edge).
|
|
3
|
+
import { resolveVariables, SAMPLE_CONTEXT } from "./variables.js";
|
|
4
|
+
import { renderEmailHtml } from "./html-render.js";
|
|
5
|
+
import { normalizeBlocks, normalizeSettings } from "./normalize.js";
|
|
6
|
+
import { DEFAULT_PALETTE } from "./default-blocks.js";
|
|
7
|
+
export const parseTemplatePayload = (payload) => {
|
|
8
|
+
if (!payload)
|
|
9
|
+
return { content: [], settings: {} };
|
|
10
|
+
try {
|
|
11
|
+
const parsed = typeof payload === "string" ? JSON.parse(payload) : payload;
|
|
12
|
+
return {
|
|
13
|
+
// Normaliza contra el esquema actual: descarta tipos desconocidos,
|
|
14
|
+
// completa props faltantes con defaults y repara ids.
|
|
15
|
+
content: normalizeBlocks(parsed?.content),
|
|
16
|
+
settings: parsed?.settings
|
|
17
|
+
? normalizeSettings(parsed.settings)
|
|
18
|
+
: {},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { content: [], settings: {} };
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Helper para renderizar una plantilla completa desde su payload JSON.
|
|
27
|
+
* Uso: `const {html, subject} = await renderTemplateEmail({subject, payload, context})`
|
|
28
|
+
*/
|
|
29
|
+
export const renderTemplateEmail = async ({ subject, payload, context = SAMPLE_CONTEXT, settings: overrideSettings, palette = DEFAULT_PALETTE, }) => {
|
|
30
|
+
const mergedContext = {
|
|
31
|
+
...SAMPLE_CONTEXT,
|
|
32
|
+
...(context || {}),
|
|
33
|
+
};
|
|
34
|
+
const { content: blocks, settings } = parseTemplatePayload(payload);
|
|
35
|
+
if (!blocks || blocks.length === 0) {
|
|
36
|
+
throw new Error("Template payload has no blocks");
|
|
37
|
+
}
|
|
38
|
+
const finalSettings = { ...settings, ...(overrideSettings || {}) };
|
|
39
|
+
const html = await renderEmailHtml({
|
|
40
|
+
blocks,
|
|
41
|
+
subject,
|
|
42
|
+
context: mergedContext,
|
|
43
|
+
settings: finalSettings,
|
|
44
|
+
palette,
|
|
45
|
+
});
|
|
46
|
+
const resolvedSubject = resolveVariables(subject, mergedContext);
|
|
47
|
+
return { html, subject: resolvedSubject };
|
|
48
|
+
};
|
|
49
|
+
export const buildTemplateContext = (base, extra) => {
|
|
50
|
+
const cleaned = { ...base };
|
|
51
|
+
if (extra) {
|
|
52
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
53
|
+
if (v != null && v !== "")
|
|
54
|
+
cleaned[k] = String(v);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { ...SAMPLE_CONTEXT, ...cleaned };
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAC5E,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAOpE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAYtD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,OAA2C,EAC1B,EAAE;IACnB,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,OAAe,CAAC;QACvE,OAAO;YACL,mEAAmE;YACnE,sDAAsD;YACtD,OAAO,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC;YACzC,QAAQ,EAAE,MAAM,EAAE,QAAQ;gBACxB,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACpC,CAAC,CAAC,EAAE;SACP,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACvC,CAAC;AACH,CAAC,CAAC;AAeF;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EAAE,EACxC,OAAO,EACP,OAAO,EACP,OAAO,GAAG,cAAc,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAG,eAAe,GACE,EAAkC,EAAE;IAC/D,MAAM,aAAa,GAAiB;QAClC,GAAG,cAAc;QACjB,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;KACnB,CAAC;IAEF,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEpE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,aAAa,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE,CAAC;IAEnE,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC;QACjC,MAAM;QACN,OAAO;QACP,OAAO,EAAE,aAAa;QACtB,QAAQ,EAAE,aAAa;QACvB,OAAO;KACR,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAEjE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,IAAkB,EAClB,KAAiD,EACnC,EAAE;IAChB,MAAM,OAAO,GAAiB,EAAE,GAAG,IAAI,EAAE,CAAC;IAC1C,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;gBAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,EAAE,CAAC;AAC3C,CAAC,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export type EmailBlockType = "header" | "hero" | "heading" | "text" | "list" | "button" | "image" | "quote" | "columns" | "divider" | "spacer" | "footer";
|
|
2
|
+
export interface BlockCommonProps {
|
|
3
|
+
align?: "left" | "center" | "right";
|
|
4
|
+
backgroundColor?: string;
|
|
5
|
+
paddingY?: number;
|
|
6
|
+
paddingX?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface HeaderProps extends BlockCommonProps {
|
|
9
|
+
brandName: string;
|
|
10
|
+
tagline?: string;
|
|
11
|
+
logoUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface HeroProps extends BlockCommonProps {
|
|
14
|
+
title: string;
|
|
15
|
+
subtitle?: string;
|
|
16
|
+
imageUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface HeadingProps extends BlockCommonProps {
|
|
19
|
+
text: string;
|
|
20
|
+
size?: number;
|
|
21
|
+
color?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface TextProps extends BlockCommonProps {
|
|
24
|
+
text: string;
|
|
25
|
+
size?: number;
|
|
26
|
+
color?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ListProps extends BlockCommonProps {
|
|
29
|
+
items: string[];
|
|
30
|
+
icon?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare const LIST_ICONS: string[];
|
|
33
|
+
export interface ButtonProps extends BlockCommonProps {
|
|
34
|
+
label: string;
|
|
35
|
+
href: string;
|
|
36
|
+
backgroundColor?: string;
|
|
37
|
+
color?: string;
|
|
38
|
+
blockBackgroundColor?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ImageProps extends BlockCommonProps {
|
|
41
|
+
src: string;
|
|
42
|
+
alt?: string;
|
|
43
|
+
width?: number;
|
|
44
|
+
href?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface QuoteProps extends BlockCommonProps {
|
|
47
|
+
text: string;
|
|
48
|
+
author?: string;
|
|
49
|
+
borderColor?: string;
|
|
50
|
+
borderWidth?: number;
|
|
51
|
+
marginLeft?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ColumnsProps extends BlockCommonProps {
|
|
54
|
+
columns: {
|
|
55
|
+
id: string;
|
|
56
|
+
text: string;
|
|
57
|
+
}[];
|
|
58
|
+
}
|
|
59
|
+
export interface DividerProps extends BlockCommonProps {
|
|
60
|
+
color?: string;
|
|
61
|
+
height?: number;
|
|
62
|
+
}
|
|
63
|
+
export interface SpacerProps {
|
|
64
|
+
height?: number;
|
|
65
|
+
backgroundColor?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface FooterProps {
|
|
68
|
+
text?: string;
|
|
69
|
+
brandName?: string;
|
|
70
|
+
backgroundColor?: string;
|
|
71
|
+
}
|
|
72
|
+
export type EmailBlockProps = HeaderProps | HeroProps | HeadingProps | TextProps | ListProps | ButtonProps | ImageProps | QuoteProps | ColumnsProps | DividerProps | SpacerProps | FooterProps;
|
|
73
|
+
export interface EmailBlock {
|
|
74
|
+
id: string;
|
|
75
|
+
type: EmailBlockType;
|
|
76
|
+
props: EmailBlockProps;
|
|
77
|
+
}
|
|
78
|
+
export interface EmailContext {
|
|
79
|
+
[key: string]: string;
|
|
80
|
+
}
|
|
81
|
+
export interface BlockDefinition {
|
|
82
|
+
type: EmailBlockType;
|
|
83
|
+
label: string;
|
|
84
|
+
description: string;
|
|
85
|
+
defaultProps: EmailBlockProps;
|
|
86
|
+
}
|
|
87
|
+
export interface EmailSettings {
|
|
88
|
+
pageBackground: string;
|
|
89
|
+
cardBorderWidth: number;
|
|
90
|
+
cardBorderRadius: number;
|
|
91
|
+
}
|
|
92
|
+
export interface EmailPalette {
|
|
93
|
+
INK: string;
|
|
94
|
+
DARK: string;
|
|
95
|
+
GOLD: string;
|
|
96
|
+
CREAM_DIM: string;
|
|
97
|
+
}
|
|
98
|
+
export declare const EMAIL_BLOCK_TYPES: EmailBlockType[];
|
|
99
|
+
export declare const buildBlockMap: (library: BlockDefinition[]) => Record<EmailBlockType, BlockDefinition>;
|
|
100
|
+
export declare const createBlock: (type: EmailBlockType, library: BlockDefinition[]) => EmailBlock;
|
|
101
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { newId } from "./id.js";
|
|
2
|
+
export const LIST_ICONS = [
|
|
3
|
+
"✓",
|
|
4
|
+
"•",
|
|
5
|
+
"●",
|
|
6
|
+
"→",
|
|
7
|
+
"★",
|
|
8
|
+
"✦",
|
|
9
|
+
"◆",
|
|
10
|
+
"▸",
|
|
11
|
+
"»",
|
|
12
|
+
"–",
|
|
13
|
+
];
|
|
14
|
+
export const EMAIL_BLOCK_TYPES = [
|
|
15
|
+
"header",
|
|
16
|
+
"hero",
|
|
17
|
+
"heading",
|
|
18
|
+
"text",
|
|
19
|
+
"list",
|
|
20
|
+
"button",
|
|
21
|
+
"image",
|
|
22
|
+
"quote",
|
|
23
|
+
"columns",
|
|
24
|
+
"divider",
|
|
25
|
+
"spacer",
|
|
26
|
+
"footer",
|
|
27
|
+
];
|
|
28
|
+
export const buildBlockMap = (library) => Object.fromEntries(library.map((def) => [def.type, def]));
|
|
29
|
+
export const createBlock = (type, library) => {
|
|
30
|
+
const map = buildBlockMap(library);
|
|
31
|
+
return {
|
|
32
|
+
id: newId(),
|
|
33
|
+
type,
|
|
34
|
+
props: { ...map[type].defaultProps },
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAoDhC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;CACJ,CAAC;AAyFF,MAAM,CAAC,MAAM,iBAAiB,GAAqB;IACjD,QAAQ;IACR,MAAM;IACN,SAAS;IACT,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,SAAS;IACT,SAAS;IACT,QAAQ;IACR,QAAQ;CACT,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,OAA0B,EACe,EAAE,CAC3C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAGvD,CAAC;AAEJ,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAoB,EACpB,OAA0B,EACd,EAAE;IACd,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO;QACL,EAAE,EAAE,KAAK,EAAE;QACX,IAAI;QACJ,KAAK,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE;KACrC,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type EmailContext } from "./types.js";
|
|
2
|
+
export interface EmailVariable {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export interface EmailVariableSection {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
variables: EmailVariable[];
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_BASE_VARIABLES: EmailVariable[];
|
|
13
|
+
export declare const DEFAULT_CONTEXTUAL_VARIABLES: EmailVariable[];
|
|
14
|
+
export declare const DEFAULT_VARIABLES: EmailVariable[];
|
|
15
|
+
export declare const SAMPLE_CONTEXT: EmailContext;
|
|
16
|
+
export declare const resolveVariables: (text: string, context: EmailContext) => string;
|
|
17
|
+
export declare const extractVariables: (text: string) => string[];
|
|
18
|
+
export declare const validateVariables: (text: string, knownKeys: string[]) => string[];
|
|
19
|
+
//# sourceMappingURL=variables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../src/variables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,aAAa,EAAE,CAAA;CAC3B;AAED,eAAO,MAAM,sBAAsB,EAAE,aAAa,EAcjD,CAAA;AAED,eAAO,MAAM,4BAA4B,EAAE,aAAa,EAcvD,CAAA;AAED,eAAO,MAAM,iBAAiB,EAAE,aAAa,EAG5C,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,YAgC5B,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,SAAS,YAAY,KAAG,MAGpE,CAAA;AAEH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAAM,EACA,CAAA;AAEtD,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,MAAM,EAAE,KAClB,MAAM,EAGR,CAAA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const DEFAULT_BASE_VARIABLES = [
|
|
2
|
+
{ key: "name", label: "Nombre completo" },
|
|
3
|
+
{ key: "firstName", label: "Nombre" },
|
|
4
|
+
{ key: "lastName", label: "Apellido" },
|
|
5
|
+
{ key: "email", label: "Correo electrónico" },
|
|
6
|
+
{ key: "phone", label: "Teléfono" },
|
|
7
|
+
{ key: "role", label: "Rol" },
|
|
8
|
+
{ key: "companyName", label: "Empresa / Marca" },
|
|
9
|
+
{ key: "unsubscribeUrl", label: "URL de baja" },
|
|
10
|
+
{ key: "link", label: "Enlace CTA" },
|
|
11
|
+
{ key: "date", label: "Fecha" },
|
|
12
|
+
{ key: "year", label: "Año" },
|
|
13
|
+
{ key: "siteUrl", label: "URL del sitio" },
|
|
14
|
+
{ key: "supportEmail", label: "Correo de soporte" },
|
|
15
|
+
];
|
|
16
|
+
export const DEFAULT_CONTEXTUAL_VARIABLES = [
|
|
17
|
+
{ key: "webinarName", label: "Nombre del webinar" },
|
|
18
|
+
{ key: "webinarDate", label: "Fecha del webinar" },
|
|
19
|
+
{ key: "webinarTime", label: "Hora del webinar" },
|
|
20
|
+
{ key: "webinarDuration", label: "Duración" },
|
|
21
|
+
{ key: "webinarUrl", label: "URL del webinar" },
|
|
22
|
+
{ key: "registerUrl", label: "URL de registro" },
|
|
23
|
+
{ key: "liveUrl", label: "URL en vivo" },
|
|
24
|
+
{ key: "slotsLeft", label: "Cupos restantes" },
|
|
25
|
+
{ key: "reminderDate", label: "Fecha de recordatorio" },
|
|
26
|
+
{ key: "webinarHost", label: "Anfitrión" },
|
|
27
|
+
{ key: "completeRegistrationUrl", label: "URL completar registro" },
|
|
28
|
+
{ key: "resetPasswordUrl", label: "URL restablecer contraseña" },
|
|
29
|
+
{ key: "confirmEmailUrl", label: "URL confirmar correo" },
|
|
30
|
+
];
|
|
31
|
+
export const DEFAULT_VARIABLES = [
|
|
32
|
+
...DEFAULT_BASE_VARIABLES,
|
|
33
|
+
...DEFAULT_CONTEXTUAL_VARIABLES,
|
|
34
|
+
];
|
|
35
|
+
export const SAMPLE_CONTEXT = {
|
|
36
|
+
name: "Juan Pérez",
|
|
37
|
+
firstName: "Juan",
|
|
38
|
+
lastName: "Pérez",
|
|
39
|
+
email: "juan@ejemplo.com",
|
|
40
|
+
phone: "+57 300 111 2233",
|
|
41
|
+
role: "Instructor",
|
|
42
|
+
companyName: "Mi Empresa",
|
|
43
|
+
unsubscribeUrl: "https://www.ejemplo.com/baja",
|
|
44
|
+
link: "https://www.ejemplo.com/",
|
|
45
|
+
date: "5 de septiembre de 2026",
|
|
46
|
+
year: "2026",
|
|
47
|
+
siteUrl: "https://www.ejemplo.com",
|
|
48
|
+
supportEmail: "soporte@ejemplo.com",
|
|
49
|
+
webinarName: "Webinar de ejemplo",
|
|
50
|
+
webinarDate: "5 de septiembre de 2026",
|
|
51
|
+
webinarTime: "19:00",
|
|
52
|
+
webinarDuration: "90 minutos",
|
|
53
|
+
webinarUrl: "https://www.ejemplo.com/webinars/ejemplo",
|
|
54
|
+
webinarSlug: "aprende-antes-de-invertir",
|
|
55
|
+
registerUrl: "https://www.ejemplo.com/registro",
|
|
56
|
+
liveUrl: "https://www.ejemplo.com",
|
|
57
|
+
slotsLeft: "15",
|
|
58
|
+
reminderDate: "3 de septiembre de 2026",
|
|
59
|
+
webinarHost: "Equipo de Tu Empresa",
|
|
60
|
+
completeRegistrationUrl: "https://www.ejemplo.com/completar-registro",
|
|
61
|
+
resetPasswordUrl: "https://www.ejemplo.com/restablecer-contrasena",
|
|
62
|
+
confirmEmailUrl: "https://www.ejemplo.com/confirmar-correo",
|
|
63
|
+
courseName: "Curso de Finanzas Personales",
|
|
64
|
+
productName: "Curso de Finanzas Personales",
|
|
65
|
+
amountVes: "2500,00",
|
|
66
|
+
paymentUrl: "https://www.ejemplo.com/billing/demo/123",
|
|
67
|
+
};
|
|
68
|
+
export const resolveVariables = (text, context) => text.replace(/\{(\w+)\}/g, (match, key) => key in context ? context[key] : match);
|
|
69
|
+
export const extractVariables = (text) => Array.from(text.matchAll(/\{(\w+)\}/g), (m) => m[1]);
|
|
70
|
+
export const validateVariables = (text, knownKeys) => {
|
|
71
|
+
const used = extractVariables(text);
|
|
72
|
+
return used.filter((key) => !knownKeys.includes(key));
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=variables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variables.js","sourceRoot":"","sources":["../src/variables.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-email-renderer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React-free email template renderer (JSON blocks -> email-safe HTML) for back-ends and edge runtimes",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./types": {
|
|
14
|
+
"types": "./dist/types.d.ts",
|
|
15
|
+
"import": "./dist/types.js"
|
|
16
|
+
},
|
|
17
|
+
"./variables": {
|
|
18
|
+
"types": "./dist/variables.d.ts",
|
|
19
|
+
"import": "./dist/variables.js"
|
|
20
|
+
},
|
|
21
|
+
"./richtext": {
|
|
22
|
+
"types": "./dist/richtext.d.ts",
|
|
23
|
+
"import": "./dist/richtext.js"
|
|
24
|
+
},
|
|
25
|
+
"./default-blocks": {
|
|
26
|
+
"types": "./dist/default-blocks.d.ts",
|
|
27
|
+
"import": "./dist/default-blocks.js"
|
|
28
|
+
},
|
|
29
|
+
"./normalize": {
|
|
30
|
+
"types": "./dist/normalize.d.ts",
|
|
31
|
+
"import": "./dist/normalize.js"
|
|
32
|
+
},
|
|
33
|
+
"./html-render": {
|
|
34
|
+
"types": "./dist/html-render.d.ts",
|
|
35
|
+
"import": "./dist/html-render.js"
|
|
36
|
+
},
|
|
37
|
+
"./server": {
|
|
38
|
+
"types": "./dist/server.d.ts",
|
|
39
|
+
"import": "./dist/server.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"sanitize-html": "^2.17.6"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^24",
|
|
50
|
+
"@types/sanitize-html": "^2.13.0",
|
|
51
|
+
"typescript": "~6"
|
|
52
|
+
},
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"author": "asmel2020",
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"homepage": "https://github.com/asmel2020/creator-email-templates#readme",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/asmel2020/creator-email-templates.git",
|
|
62
|
+
"directory": "packages/create-email-renderer"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "tsc -p tsconfig.json",
|
|
66
|
+
"lint": "tsc --noEmit",
|
|
67
|
+
"typecheck": "tsc --noEmit",
|
|
68
|
+
"check-types": "tsc --noEmit"
|
|
69
|
+
}
|
|
70
|
+
}
|