create-email-renderer 0.1.0 → 0.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 +106 -2
- package/SKILL.md +189 -0
- package/dist/build.d.ts +52 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +169 -0
- package/dist/build.js.map +1 -0
- package/dist/default-blocks.d.ts.map +1 -1
- package/dist/default-blocks.js +357 -5
- package/dist/default-blocks.js.map +1 -1
- package/dist/html-render.d.ts +4 -2
- package/dist/html-render.d.ts.map +1 -1
- package/dist/html-render.js +694 -54
- package/dist/html-render.js.map +1 -1
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +20 -3
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/normalize.d.ts +3 -1
- package/dist/normalize.d.ts.map +1 -1
- package/dist/normalize.js +120 -40
- package/dist/normalize.js.map +1 -1
- package/dist/records.d.ts +8 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +81 -0
- package/dist/records.js.map +1 -0
- package/dist/registry.d.ts +29 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +31 -0
- package/dist/registry.js.map +1 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -1
- package/dist/server.js.map +1 -1
- package/dist/tracking.d.ts +12 -0
- package/dist/tracking.d.ts.map +1 -0
- package/dist/tracking.js +78 -0
- package/dist/tracking.js.map +1 -0
- package/dist/types.d.ts +354 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +82 -0
- package/dist/types.js.map +1 -1
- package/docs/BLOCKS.md +467 -0
- package/docs/MCP.md +186 -0
- package/llms.txt +15 -0
- package/package.json +17 -4
package/README.md
CHANGED
|
@@ -4,6 +4,18 @@ Renderiza plantillas de email por bloques a **HTML email-safe sin React**. JS pu
|
|
|
4
4
|
|
|
5
5
|
Es el compañero de [`create-email-template`](https://www.npmjs.com/package/create-email-template) (editor visual). Comparten el mismo core: los tipos, los defaults y la normalización son idénticos en ambos lados, por lo que el preview del editor y el HTML final nunca divergen.
|
|
6
6
|
|
|
7
|
+
## ¿Programas con una IA o vas a integrarlo?
|
|
8
|
+
|
|
9
|
+
La documentación para agentes viaja dentro del paquete:
|
|
10
|
+
|
|
11
|
+
- **[`SKILL.md`](./SKILL.md)** — orientación: modelo mental del payload, los 3 flujos, recetas
|
|
12
|
+
(tarea → API) y reglas de oro.
|
|
13
|
+
- **[`docs/BLOCKS.md`](./docs/BLOCKS.md)** — catálogo de los **25 bloques** con props, defaults,
|
|
14
|
+
variantes y ejemplos `blockJson` copiables.
|
|
15
|
+
- **[`docs/MCP.md`](./docs/MCP.md)** — cómo exponer el renderer como **servidor MCP** (tools
|
|
16
|
+
`list_blocks`, `build_block`, `render_email`, `validate_template`…).
|
|
17
|
+
- **[`llms.txt`](./llms.txt)** — índice corto para herramientas que lo buscan por convención.
|
|
18
|
+
|
|
7
19
|
## Instalación
|
|
8
20
|
|
|
9
21
|
```sh
|
|
@@ -39,8 +51,9 @@ await emailClient.send({ to: user.email, subject, html });
|
|
|
39
51
|
| `subject` | `string` | — (obligatorio) | Asunto del correo. **Resuelve variables**: `"Hola {firstName}"` → `"Hola Danny"`. También queda en `<title>` y en el preview oculto del email. |
|
|
40
52
|
| `payload` | `string \| object \| null` | — | El JSON del editor. Tolera `null`/`undefined`/string inválido (devuelve vacío). |
|
|
41
53
|
| `context` | `EmailContext` | `SAMPLE_CONTEXT` | Valores para las variables `{key}`. Se mezcla sobre `SAMPLE_CONTEXT`, así que los correos de prueba siempre se ven completos aunque falten claves. |
|
|
42
|
-
| `settings` | `Partial<EmailSettings>` | settings del payload | Sobrescribe `{ pageBackground, cardBorderWidth, cardBorderRadius }` guardados. |
|
|
54
|
+
| `settings` | `Partial<EmailSettings>` | settings del payload | Sobrescribe `{ pageBackground, cardBorderWidth, cardBorderRadius, fontFamily }` guardados. |
|
|
43
55
|
| `palette` | `EmailPalette` | `DEFAULT_PALETTE` | Sobrescribe los colores: `{ INK, DARK, GOLD, CREAM_DIM }`. |
|
|
56
|
+
| `tracking` | `EmailTracking` | — | Trackeo **por envío**: pixel de apertura y reescritura de enlaces. Ver [Trackeo](#trackeo-aperturas-y-clics). |
|
|
44
57
|
|
|
45
58
|
**Comportamiento**: lanza `Template payload has no blocks` si tras normalizar no queda ningún bloque. En cualquier otro caso de datos sucios, normaliza sin quejarse (ver [Normalización](#normalización-de-payloads)).
|
|
46
59
|
|
|
@@ -97,9 +110,99 @@ Esto significa que **añadir props nuevas a un bloque no rompe las plantillas ya
|
|
|
97
110
|
| `extractVariables(text)` / `validateVariables(text, knownKeys)` | Inspección de variables usadas/no reconocidas. |
|
|
98
111
|
| `renderRichText(html)` | Sanitiza y aplica estilos inline al rich text del editor. |
|
|
99
112
|
| `sanitizeRichText` / `escapeHtml` / `normalizeBlockHtml` / `isRichText` | Piezas del pipeline por separado. |
|
|
100
|
-
| `
|
|
113
|
+
| `blockJson(type, props?)` | Constructor **tipado** de un bloque: defaults del esquema, coerción de tipos e ids automáticos. Tipo desconocido → `null`. |
|
|
114
|
+
| `templateJson(blocks, settings?)` | Arma el payload completo (`{ content, settings }`) para `renderTemplateEmail`. |
|
|
115
|
+
| `createBlock(type, library)` | Crea un bloque nuevo con defaultProps (helper de bajo nivel del editor). |
|
|
101
116
|
| Defaults | `DEFAULT_BLOCK_LIBRARY`, `DEFAULT_PALETTE`, `DEFAULT_SETTINGS`, `DEFAULT_VARIABLES`, `SAMPLE_CONTEXT`. |
|
|
102
117
|
|
|
118
|
+
## Construir bloques desde el back-end (`blockJson`)
|
|
119
|
+
|
|
120
|
+
Para inyectar contenido que no vive en la plantilla (un producto, un carrito, una imagen) no
|
|
121
|
+
hace falta escribir el JSON a mano: `blockJson` parte de los **defaults del esquema vivo**,
|
|
122
|
+
coacciona tipos, genera los ids y completa los arrays de registros.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { blockJson, templateJson } from "create-email-renderer";
|
|
126
|
+
|
|
127
|
+
// Un bloque suelto: lo que no pases queda con su default.
|
|
128
|
+
const promo = blockJson("image", { src: "https://…/promo.jpg", alt: "Promo" });
|
|
129
|
+
|
|
130
|
+
// Carrito real: los registros se completan solos (id, imageUrl, quantity…).
|
|
131
|
+
const carrito = blockJson("checkout", {
|
|
132
|
+
heading: "Tu pedido está listo",
|
|
133
|
+
lines: cart.items.map((i) => ({ name: i.name, price: i.price, quantity: String(i.qty) })),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Correo completo listo para enviar.
|
|
137
|
+
const { html, subject } = await renderTemplateEmail({
|
|
138
|
+
subject: "Tu pedido {orderId}",
|
|
139
|
+
payload: templateJson([promo, carrito], { cardBorderWidth: 0 }),
|
|
140
|
+
context: { orderId: "A-123" },
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- **Posicional**: `blockJson(type, props?)` y `templateJson(blocks, settings?)`.
|
|
145
|
+
- **Tipado**: el editor autocompleta solo las props del tipo elegido; una prop inexistente es error de compilación.
|
|
146
|
+
- **Tolerante**: un tipo desconocido devuelve `null` (y `templateJson` lo descarta).
|
|
147
|
+
- **Anidamiento**: `columns` / `blocks` aceptan `blockJson(...)`, el atajo `[type, props]` o `{ type, props }`; se respeta la profundidad máxima (`MAX_BLOCK_DEPTH`).
|
|
148
|
+
- **Ids**: nunca los administras, se generan con `newId()`.
|
|
149
|
+
|
|
150
|
+
## Trackeo (aperturas y clics)
|
|
151
|
+
|
|
152
|
+
Opcional y **por envío** (no se guarda en la plantilla, así que el preview del editor nunca
|
|
153
|
+
lleva pixel). Con `tracking` apagado la salida es idéntica a no usarlo.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
await renderTemplateEmail({
|
|
157
|
+
subject: "Tu carrito te espera",
|
|
158
|
+
payload,
|
|
159
|
+
context: { email: "ana@ejemplo.com" },
|
|
160
|
+
tracking: {
|
|
161
|
+
pixelUrl: "https://track.mi-app.com/o?cid=cart-123&e={email}", // apertura (1×1)
|
|
162
|
+
clickUrl: "https://track.mi-app.com/c?cid=cart-123&u={url}", // clics
|
|
163
|
+
utm: { source: "email", medium: "email", campaign: "carrito" },
|
|
164
|
+
exclude: ["/baja"], // extra opcional
|
|
165
|
+
// transformLink: (href) => `https://mi-redirect/?to=${encodeURIComponent(href)}`,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
| Campo | Qué hace |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `pixelUrl` | Inyecta un `<img width="1" height="1">` antes de `</body>`. Acepta `{variables}`. |
|
|
173
|
+
| `clickUrl` | Reescribe cada `<a href>`: el destino va en `{url}` (codificado) y el tracker recibe las mismas `{variables}`. |
|
|
174
|
+
| `utm` | Añade `utm_*` al destino **antes** de pasarlo por el tracker (respeta los parámetros que ya existían). |
|
|
175
|
+
| `exclude` | Substrings de href que no se reescriben; se suman a los de por defecto (`mailto:`, `tel:`, `sms:`, `#`, `unsubscribe`, `/baja`, `optout`…). |
|
|
176
|
+
| `transformLink` | Control total: devuelve el href final tú mismo. |
|
|
177
|
+
|
|
178
|
+
**Caveats honestos**
|
|
179
|
+
|
|
180
|
+
- Las **aperturas** ya no son fiables: Apple Mail precarga las imágenes (MPP) y Gmail las sirve
|
|
181
|
+
por proxy. Úsalo como tendencia, no como verdad.
|
|
182
|
+
- El **click tracking** cambia la URL visible al pasar el ratón y la vista previa del enlace en
|
|
183
|
+
algunos clientes; y **nunca** debe pasar por el tracker el enlace de baja.
|
|
184
|
+
- Si tu ESP (Mailflare, Resend, SES…) ya trackea, no lo dupliques: aquí tienes `transformLink`
|
|
185
|
+
como salida de emergencia.
|
|
186
|
+
|
|
187
|
+
## Tipografía
|
|
188
|
+
|
|
189
|
+
El correo lleva un **stack de fuentes de sistema** (lista ordenada: el cliente usa la primera que
|
|
190
|
+
tenga instalada) para no depender de la fuente por defecto del cliente —que en Gmail/Outlook suele
|
|
191
|
+
ser Times New Roman—:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
await renderTemplateEmail({
|
|
195
|
+
subject: "Hola",
|
|
196
|
+
payload,
|
|
197
|
+
settings: { fontFamily: "Georgia, 'Times New Roman', serif" }, // o "" para no emitir nada
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`FONT_STACKS` trae 7 grupos listos (Sistema, Arial/Helvetica, Verdana/Tahoma, Trebuchet MS,
|
|
202
|
+
Georgia, Times New Roman y Monoespaciada) y `DEFAULT_SETTINGS.fontFamily` es el stack de sistema.
|
|
203
|
+
Las **webfonts** (`@font-face`) no son fiables: Gmail las elimina y Outlook escritorio las ignora,
|
|
204
|
+
así que conviene dejar siempre un fallback de sistema al final del stack.
|
|
205
|
+
|
|
103
206
|
## Subpaths
|
|
104
207
|
|
|
105
208
|
Todo está disponible desde la raíz. Si prefieres imports granulares (menos bundle en serverless):
|
|
@@ -112,6 +215,7 @@ create-email-renderer/types → todos los tipos + createBlock
|
|
|
112
215
|
create-email-renderer/variables → variables, contextos y resolve
|
|
113
216
|
create-email-renderer/richtext → helpers de rich text
|
|
114
217
|
create-email-renderer/default-blocks → defaults de bloques, paleta y settings
|
|
218
|
+
create-email-renderer/build → blockJson, templateJson
|
|
115
219
|
```
|
|
116
220
|
|
|
117
221
|
## Licencia
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-email-renderer
|
|
3
|
+
description: Render and build email templates as JSON blocks into email-safe HTML without React (Node, Workers, edge)
|
|
4
|
+
licence: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: asmel2020
|
|
7
|
+
version: 1.0.0
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Skill: `create-email-renderer`
|
|
11
|
+
|
|
12
|
+
Renderiza plantillas de email **por bloques** (JSON → HTML email-safe) **sin React**. JS puro:
|
|
13
|
+
corre en Node, Cloudflare Workers, Vercel Edge, Deno y Bun. Es el compañero sin UI de
|
|
14
|
+
`create-email-template` (el editor visual): comparten el mismo core, así que el preview del
|
|
15
|
+
editor y el HTML final nunca divergen.
|
|
16
|
+
|
|
17
|
+
- 📖 Catálogo de los **25 bloques** (props, defaults, variantes, ejemplos): [`docs/BLOCKS.md`](./docs/BLOCKS.md)
|
|
18
|
+
- 🔌 Cómo exponerlo como **MCP**: [`docs/MCP.md`](./docs/MCP.md)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Cuándo usar esto
|
|
23
|
+
|
|
24
|
+
| Quieres… | Usa |
|
|
25
|
+
|---|---|
|
|
26
|
+
| Mandar un correo desde el back-end a partir de una plantilla guardada | `renderTemplateEmail` |
|
|
27
|
+
| Construir el correo por código (sin editor) | `blockJson` + `templateJson` |
|
|
28
|
+
| Inyectar datos reales (carrito, pedido, productos) en una plantilla guardada | mutar `content` del payload y renderizar |
|
|
29
|
+
| Leer/limpiar un payload viejo o sucio | `parseTemplatePayload` / `normalizeBlocks` |
|
|
30
|
+
| Píxel de apertura y tracking de clics | opción `tracking` |
|
|
31
|
+
|
|
32
|
+
## Instalación
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install create-email-renderer
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Sin React, sin DOM, sin peer deps. Única dependencia: `sanitize-html`.
|
|
39
|
+
|
|
40
|
+
## Modelo mental (30 segundos)
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
payload = { content: EmailBlock[], settings } ← lo que guarda el editor
|
|
44
|
+
└── block = { id, type, props } ← uno de los 25 tipos
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
1. **`content`** es una lista ordenada de bloques. Cada bloque tiene un `type` y sus `props`.
|
|
48
|
+
2. Lo que no venga en `props` se completa con el **default del esquema**, y lo desconocido se
|
|
49
|
+
descarta (`normalizeBlocks`) → **añadir props nuevas no rompe plantillas viejas**.
|
|
50
|
+
3. Las variables `{clave}` se resuelven con el `context` en tiempo de render.
|
|
51
|
+
4. El HTML final es tablas con estilos inline (`<table role="presentation">`), email-safe.
|
|
52
|
+
|
|
53
|
+
## Los 3 flujos
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
① Editor (create-email-template) ──getPayload()──▶ { content, settings } ──PUT──▶ tu backend
|
|
57
|
+
② Tu backend ──renderTemplateEmail({ subject, payload, context })──▶ { html, subject } ──▶ ESP
|
|
58
|
+
③ Tu backend ──blockJson()/templateJson()──▶ payload ──▶ mismo render (sin editor de por medio)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Recetas (tarea → API)
|
|
62
|
+
|
|
63
|
+
### Renderizar una plantilla guardada
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { renderTemplateEmail } from "create-email-renderer/server";
|
|
67
|
+
|
|
68
|
+
const { html, subject } = await renderTemplateEmail({
|
|
69
|
+
subject: "Hola {firstName}", // resuelve variables
|
|
70
|
+
payload: template.payload, // string JSON u objeto {content, settings}
|
|
71
|
+
context: { firstName: user.name },
|
|
72
|
+
settings: { cardBorderWidth: 0 }, // sobrescribe los settings guardados
|
|
73
|
+
palette: { INK: "#111", DARK: "#000", GOLD: "#d7b227", CREAM_DIM: "#aaa" },
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- `payload` tolera `null`/string inválido (devuelve vacío) pero **lanza** `Template payload has no blocks` si tras normalizar no queda ningún bloque.
|
|
78
|
+
- No re-exporta `renderEmailHtml` (el paquete UI tiene su versión React con el mismo nombre). Para el HTML puro: `create-email-renderer/html-render`.
|
|
79
|
+
|
|
80
|
+
### Construir un bloque (tipado, con defaults e ids)
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { blockJson, templateJson } from "create-email-renderer";
|
|
84
|
+
|
|
85
|
+
blockJson("image", { src: "https://…/foto.jpg", alt: "Foto" });
|
|
86
|
+
blockJson("checkout", { lines: [{ name: "Camiseta", price: "$20" }] }); // id/quantity se rellenan
|
|
87
|
+
blockJson("columns", { columns: [{ blocks: [["text", { text: "Hola" }]] }] });
|
|
88
|
+
|
|
89
|
+
templateJson([/* bloques */], { fontFamily: "" }); // → { content, settings } listo para render
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- Posicional y **tipado** (`blockJson("image", {` autocompleta solo las props de `image`).
|
|
93
|
+
- Tipo desconocido → `null` (y `templateJson` lo descarta).
|
|
94
|
+
- **Nunca administras ids**: se generan para el bloque y para cada registro.
|
|
95
|
+
- Hijos: acepta `blockJson(...)`, `[type, props]` o `{ type, props }`; respeta `MAX_BLOCK_DEPTH = 1`.
|
|
96
|
+
|
|
97
|
+
### Inyectar el carrito / datos del pedido
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { parseTemplatePayload } from "create-email-renderer";
|
|
101
|
+
|
|
102
|
+
const { content, settings } = parseTemplatePayload(template.payload);
|
|
103
|
+
const blocks = content.map((b) =>
|
|
104
|
+
b.type === "checkout"
|
|
105
|
+
? { ...b, props: { ...b.props, heading: "Tu pedido está listo",
|
|
106
|
+
lines: cart.items.map((i) => ({ name: i.name, price: i.price, quantity: String(i.qty) })) } }
|
|
107
|
+
: b,
|
|
108
|
+
);
|
|
109
|
+
const html = await renderEmailHtml({ blocks, subject, context, settings });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`normalize` repara ids/tipos de los registros, así que puedes construir el array "flojo".
|
|
113
|
+
Ver [`docs/BLOCKS.md`](./docs/BLOCKS.md) para las props de cada bloque y
|
|
114
|
+
[`docs/MCP.md`](./docs/MCP.md) para exponer esto como tool.
|
|
115
|
+
|
|
116
|
+
### Tracking (opt-in, por envío)
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
await renderTemplateEmail({
|
|
120
|
+
subject, payload, context,
|
|
121
|
+
tracking: {
|
|
122
|
+
pixelUrl: "https://track.mi-app.com/o?cid=123&e={email}", // apertura 1×1
|
|
123
|
+
clickUrl: "https://track.mi-app.com/c?cid=123&u={url}", // clics
|
|
124
|
+
utm: { source: "email", medium: "email", campaign: "carrito" },
|
|
125
|
+
// exclude: ["/baja"], transformLink: (href) => …
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Nunca se guarda en la plantilla (no contamina el preview) y con `tracking` apagado la salida es
|
|
131
|
+
idéntica. La baja (`/baja`, `unsubscribe`, `mailto:`…) **no** se reescribe ni con `exclude` por
|
|
132
|
+
defecto.
|
|
133
|
+
|
|
134
|
+
### Otros helpers
|
|
135
|
+
|
|
136
|
+
| Export | Para qué |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `parseTemplatePayload(raw)` | `{ content, settings }` normalizado, nunca lanza. |
|
|
139
|
+
| `normalizeBlocks(input, library?)` / `normalizeSettings(input)` | Limpiar payloads legacy. |
|
|
140
|
+
| `resolveVariables(text, ctx)` / `extractVariables` / `validateVariables` | Variables `{key}`. |
|
|
141
|
+
| `buildTemplateContext(base, extra?)` | Contexto limpio (quita `null`/`""`) sobre `SAMPLE_CONTEXT`. |
|
|
142
|
+
| `renderRichText` / `sanitizeRichText` / `escapeHtml` | Pipeline de rich text. |
|
|
143
|
+
| `DEFAULT_BLOCK_LIBRARY` / `DEFAULT_PALETTE` / `DEFAULT_SETTINGS` / `SAMPLE_CONTEXT` | Defaults. |
|
|
144
|
+
| `listBlockDefinitions()` / `registerBlock()` | Registry vivo: catálogo y plugins. |
|
|
145
|
+
|
|
146
|
+
## Subpaths
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
create-email-renderer → todo
|
|
150
|
+
create-email-renderer/server → parseTemplatePayload, renderTemplateEmail, buildTemplateContext
|
|
151
|
+
create-email-renderer/html-render → renderEmailHtml
|
|
152
|
+
create-email-renderer/build → blockJson, templateJson
|
|
153
|
+
create-email-renderer/normalize → normalizeBlocks, normalizeSettings
|
|
154
|
+
create-email-renderer/types → tipos (EmailBlock, EmailBlockType, EmailSettings…)
|
|
155
|
+
create-email-renderer/variables → variables + contextos
|
|
156
|
+
create-email-renderer/richtext → helpers de rich text
|
|
157
|
+
create-email-renderer/default-blocks → defaults de bloques, paleta y settings
|
|
158
|
+
create-email-renderer/registry → registerBlock, listBlockDefinitions
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Reglas de oro (no las rompas)
|
|
162
|
+
|
|
163
|
+
1. **Este paquete nunca depende de React** ni de nada que lo arrastre. Si algo necesita DOM/JSX,
|
|
164
|
+
pertenece a `create-email-template`.
|
|
165
|
+
2. **El core vive aquí**: tipos, defaults, normalización y preset de bloques. El paquete UI los
|
|
166
|
+
reexporta con shims de una línea. No dupliques esa lógica.
|
|
167
|
+
3. **Todo helper nuevo debe ser puro y no-lanzador** con datos corruptos (salvo `blockJson` con
|
|
168
|
+
tipo desconocido → `null`, y `renderTemplateEmail` sin bloques → throw).
|
|
169
|
+
4. **Es aditivo por diseño**: no cambies defaults ni el HTML existente sin querer; hay un snapshot
|
|
170
|
+
de paridad por tipo de bloque para vigilarlo.
|
|
171
|
+
|
|
172
|
+
## Errores comunes
|
|
173
|
+
|
|
174
|
+
| Síntoma | Causa |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `Template payload has no blocks` | Todo el `content` se descartó al normalizar (tipos desconocidos). |
|
|
177
|
+
| `{firstName}` sale literal en el correo | La clave no está en el `context` (las desconocidas se dejan tal cual). |
|
|
178
|
+
| El correo se ve con otra tipografía | `settings.fontFamily` vacío ⇒ hereda la del cliente; pon un stack. |
|
|
179
|
+
| Las imágenes se estiran | `imageHeight` con `object-fit` en Outlook escritorio; usa `0`. |
|
|
180
|
+
| Las imágenes no cargan en Gmail | Son `data:` (SVG inline); Gmail las descarta. Usa URLs `https:`. |
|
|
181
|
+
| Un array de registros queda vacío | Usaste `items` para registros: los registros van en `lines`/`products`/… |
|
|
182
|
+
| El bloque anidado desaparece | `MAX_BLOCK_DEPTH = 1`: los hijos no pueden contener bloques. |
|
|
183
|
+
|
|
184
|
+
## Verificación antes de dar algo por hecho
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
pnpm --filter create-email-renderer test # snapshots de paridad + unitarios
|
|
188
|
+
pnpm lint && pnpm check-types && pnpm build
|
|
189
|
+
```
|
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { BlockPropsMap, EmailBlock, EmailBlockType, EmailSettings } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Registro de un array de registros en la entrada: sin `id` y con todos los
|
|
4
|
+
* campos opcionales (el constructor rellena ids y defaults).
|
|
5
|
+
*/
|
|
6
|
+
export type RecordInput<T> = Partial<Omit<T, "id">>;
|
|
7
|
+
/**
|
|
8
|
+
* Props de entrada de un bloque: todo opcional (los defaults completan) y los
|
|
9
|
+
* arrays de registros aceptan entradas sin `id`.
|
|
10
|
+
*/
|
|
11
|
+
export type BlockInputProps<T extends EmailBlockType> = Omit<{
|
|
12
|
+
[K in keyof BlockPropsMap[T]]?: BlockPropsMap[T][K] extends Array<infer I> ? I extends {
|
|
13
|
+
id: string;
|
|
14
|
+
} ? RecordInput<I>[] : BlockPropsMap[T][K] : BlockPropsMap[T][K];
|
|
15
|
+
}, never>;
|
|
16
|
+
/** Celda de un contenedor: ancho + hijos (bloques o atajos). */
|
|
17
|
+
export interface ColumnInput {
|
|
18
|
+
id?: string;
|
|
19
|
+
width?: number;
|
|
20
|
+
blocks?: BlockInput[];
|
|
21
|
+
}
|
|
22
|
+
/** Bloque ya construido o el atajo `[type, props]` / `{ type, props }`. */
|
|
23
|
+
export type BlockShorthand<T extends EmailBlockType = EmailBlockType> = {
|
|
24
|
+
[K in T]: [K, BlockInputProps<K>?] | {
|
|
25
|
+
type: K;
|
|
26
|
+
props?: BlockInputProps<K>;
|
|
27
|
+
};
|
|
28
|
+
}[T];
|
|
29
|
+
export type BlockInput = EmailBlock | BlockShorthand | (BlockInputProps<EmailBlockType> & {
|
|
30
|
+
type: EmailBlockType;
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Construye un bloque a partir de su tipo y (opcionalmente) props parciales.
|
|
34
|
+
* Lo que no pases queda con el default del esquema; los ids se generan solos.
|
|
35
|
+
* Devuelve `null` si el tipo no existe en la librería viva.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* blockJson("image", { src: "https://…/foto.jpg", alt: "Foto" })
|
|
39
|
+
* blockJson("checkout", { lines: [{ name: "Camiseta", price: "$20" }] })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function blockJson<T extends EmailBlockType>(type: T, props?: BlockInputProps<T>): EmailBlock;
|
|
43
|
+
export declare function blockJson(type: string, props?: Record<string, unknown>): EmailBlock | null;
|
|
44
|
+
/**
|
|
45
|
+
* Construye el payload completo (`{ content, settings }`) listo para
|
|
46
|
+
* `renderTemplateEmail({ payload })`. Descarta los bloques inválidos (`null`).
|
|
47
|
+
*/
|
|
48
|
+
export declare const templateJson: (blocks: Array<EmailBlock | null | undefined>, settings?: Partial<EmailSettings>) => {
|
|
49
|
+
content: EmailBlock[];
|
|
50
|
+
settings: Partial<EmailSettings>;
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,aAAa,EAEb,UAAU,EAEV,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAapB;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,cAAc,IAAI,IAAI,CAC1D;KACG,CAAC,IAAI,MAAM,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GACtE,CAAC,SAAS;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GACtB,WAAW,CAAC,CAAC,CAAC,EAAE,GAChB,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACrB,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACxB,EACD,KAAK,CACN,CAAC;AAEF,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,2EAA2E;AAC3E,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAAI;KACrE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAA;KAAE;CAC7E,CAAC,CAAC,CAAC,CAAC;AAEL,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,cAAc,GACd,CAAC,eAAe,CAAC,cAAc,CAAC,GAAG;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AAyIjE;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,cAAc,EAChD,IAAI,EAAE,CAAC,EACP,KAAK,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,UAAU,CAAC;AACd,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,UAAU,GAAG,IAAI,CAAC;AAerB;;;GAGG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,KAAK,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,EAC5C,WAAW,OAAO,CAAC,aAAa,CAAC,KAChC;IAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;CAO1D,CAAC"}
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// Constructor de bloques para consumidores sin editor (back-end, Workers,
|
|
2
|
+
// scripts): arma un `EmailBlock` válido partiendo de los defaults del esquema
|
|
3
|
+
// vivo, coacciona tipos, genera ids y completa los arrays de registros.
|
|
4
|
+
// Es puramente aditivo: no altera `normalize`, el render ni los defaults.
|
|
5
|
+
import { DEFAULT_BLOCK_LIBRARY, DEFAULT_SETTINGS, } from "./default-blocks.js";
|
|
6
|
+
import { newId } from "./id.js";
|
|
7
|
+
import { coerceNumber, normalizeRecordArray, RECORD_ARRAY_FIELDS, } from "./records.js";
|
|
8
|
+
import { listBlockDefinitions } from "./registry.js";
|
|
9
|
+
import { normalizeSettings } from "./normalize.js";
|
|
10
|
+
import { isContainerType } from "./types.js";
|
|
11
|
+
/** Props de layout opcionales (mismo conjunto que normaliza `normalize.ts`). */
|
|
12
|
+
const LAYOUT_KEYS = [
|
|
13
|
+
"paddingTop",
|
|
14
|
+
"paddingRight",
|
|
15
|
+
"paddingBottom",
|
|
16
|
+
"paddingLeft",
|
|
17
|
+
"marginTop",
|
|
18
|
+
"marginBottom",
|
|
19
|
+
"gap",
|
|
20
|
+
];
|
|
21
|
+
const isEmailBlock = (value) => {
|
|
22
|
+
const block = value;
|
|
23
|
+
return (!!block &&
|
|
24
|
+
typeof block === "object" &&
|
|
25
|
+
typeof block.id === "string" &&
|
|
26
|
+
typeof block.type === "string" &&
|
|
27
|
+
!!block.props &&
|
|
28
|
+
typeof block.props === "object");
|
|
29
|
+
};
|
|
30
|
+
/** Normaliza las formas aceptadas de un hijo a `[type, props]`. */
|
|
31
|
+
const asShorthand = (value) => {
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
const [type, props] = value;
|
|
34
|
+
return typeof type === "string" ? { type, props } : null;
|
|
35
|
+
}
|
|
36
|
+
if (value && typeof value === "object") {
|
|
37
|
+
const raw = value;
|
|
38
|
+
return typeof raw.type === "string"
|
|
39
|
+
? { type: raw.type, props: raw.props ?? {} }
|
|
40
|
+
: null;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
44
|
+
const resolveDefinition = (type) => {
|
|
45
|
+
const live = listBlockDefinitions();
|
|
46
|
+
const library = live.length > 0 ? live : DEFAULT_BLOCK_LIBRARY;
|
|
47
|
+
return library.find((def) => def.type === type);
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Construye las props de un bloque: defaults del esquema + lo que pases,
|
|
51
|
+
* coaccionando tipos y completando registros e hijos.
|
|
52
|
+
*/
|
|
53
|
+
const buildProps = (definition, input, depth) => {
|
|
54
|
+
const props = structuredClone(definition.defaultProps);
|
|
55
|
+
const def = definition.type;
|
|
56
|
+
for (const key of Object.keys(props)) {
|
|
57
|
+
const value = input[key];
|
|
58
|
+
if (value === undefined || value === null)
|
|
59
|
+
continue;
|
|
60
|
+
const fallback = props[key];
|
|
61
|
+
if (key === "columns" && Array.isArray(fallback)) {
|
|
62
|
+
props[key] = buildColumns(value, depth);
|
|
63
|
+
}
|
|
64
|
+
else if (key === "blocks" && def === "container") {
|
|
65
|
+
props[key] = buildBlockList(value, depth + 1);
|
|
66
|
+
}
|
|
67
|
+
else if (key === "columns" && def === "gallery") {
|
|
68
|
+
props[key] = coerceNumber(value, fallback);
|
|
69
|
+
}
|
|
70
|
+
else if (RECORD_ARRAY_FIELDS[key]) {
|
|
71
|
+
props[key] = normalizeRecordArray(value, fallback, RECORD_ARRAY_FIELDS[key]);
|
|
72
|
+
}
|
|
73
|
+
else if (typeof fallback === "number") {
|
|
74
|
+
props[key] = coerceNumber(value, fallback);
|
|
75
|
+
}
|
|
76
|
+
else if (typeof fallback === "boolean") {
|
|
77
|
+
props[key] = value === true || value === "true";
|
|
78
|
+
}
|
|
79
|
+
else if (Array.isArray(fallback)) {
|
|
80
|
+
props[key] = Array.isArray(value) ? value.map((v) => String(v)) : fallback;
|
|
81
|
+
}
|
|
82
|
+
else if (typeof fallback === "string") {
|
|
83
|
+
props[key] = String(value);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
props[key] = value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Overrides de layout opcionales que no viven en los defaults.
|
|
90
|
+
for (const key of LAYOUT_KEYS) {
|
|
91
|
+
const value = input[key];
|
|
92
|
+
if (value === undefined || value === null)
|
|
93
|
+
continue;
|
|
94
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
95
|
+
props[key] = value;
|
|
96
|
+
}
|
|
97
|
+
else if (typeof value === "string" && value.trim() !== "") {
|
|
98
|
+
const parsed = parseFloat(value);
|
|
99
|
+
if (Number.isFinite(parsed))
|
|
100
|
+
props[key] = parsed;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return props;
|
|
104
|
+
};
|
|
105
|
+
/** Construye una lista de bloques (hijos de contenedores/columnas). */
|
|
106
|
+
const buildBlockList = (input, depth) => {
|
|
107
|
+
if (!Array.isArray(input))
|
|
108
|
+
return [];
|
|
109
|
+
const blocks = [];
|
|
110
|
+
for (const entry of input) {
|
|
111
|
+
if (isEmailBlock(entry)) {
|
|
112
|
+
// Ya es un bloque (p. ej. salido de `blockJson`): se respeta tal cual,
|
|
113
|
+
// salvo que sea un contenedor demasiado profundo.
|
|
114
|
+
if (depth > 0 && isContainerType(entry.type))
|
|
115
|
+
continue;
|
|
116
|
+
blocks.push(entry);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const shorthand = asShorthand(entry);
|
|
120
|
+
if (!shorthand)
|
|
121
|
+
continue;
|
|
122
|
+
if (depth > 0 && isContainerType(shorthand.type))
|
|
123
|
+
continue;
|
|
124
|
+
const definition = resolveDefinition(shorthand.type);
|
|
125
|
+
if (!definition)
|
|
126
|
+
continue;
|
|
127
|
+
blocks.push({
|
|
128
|
+
id: newId(),
|
|
129
|
+
type: definition.type,
|
|
130
|
+
props: buildProps(definition, shorthand.props ?? {}, depth),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return blocks;
|
|
134
|
+
};
|
|
135
|
+
/** Construye las celdas de `columns` / `grid` / `footer`. */
|
|
136
|
+
const buildColumns = (input, depth) => {
|
|
137
|
+
if (!Array.isArray(input))
|
|
138
|
+
return [];
|
|
139
|
+
return input.map((raw) => {
|
|
140
|
+
const col = (raw ?? {});
|
|
141
|
+
const id = typeof col.id === "string" && col.id ? col.id : newId();
|
|
142
|
+
const blocks = buildBlockList(col.blocks, depth + 1);
|
|
143
|
+
const width = coerceNumber(col.width, 0);
|
|
144
|
+
return width > 0 ? { id, blocks, width } : { id, blocks };
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
export function blockJson(type, props) {
|
|
148
|
+
if (typeof type !== "string" || !type)
|
|
149
|
+
return null;
|
|
150
|
+
const definition = resolveDefinition(type);
|
|
151
|
+
if (!definition)
|
|
152
|
+
return null;
|
|
153
|
+
return {
|
|
154
|
+
id: newId(),
|
|
155
|
+
type: definition.type,
|
|
156
|
+
props: buildProps(definition, props ?? {}, 0),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Construye el payload completo (`{ content, settings }`) listo para
|
|
161
|
+
* `renderTemplateEmail({ payload })`. Descarta los bloques inválidos (`null`).
|
|
162
|
+
*/
|
|
163
|
+
export const templateJson = (blocks, settings) => ({
|
|
164
|
+
content: blocks.filter((block) => !!block && !!block.props),
|
|
165
|
+
settings: settings
|
|
166
|
+
? normalizeSettings({ ...DEFAULT_SETTINGS, ...settings })
|
|
167
|
+
: {},
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-blocks.d.ts","sourceRoot":"","sources":["../src/default-blocks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"default-blocks.d.ts","sourceRoot":"","sources":["../src/default-blocks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE9E,eAAO,MAAM,eAAe,EAAE,YAK7B,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,aAK9B,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,eAAe,EAwelD,CAAA"}
|