@stacksjs/email 0.74.69 → 0.75.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/template.d.ts +17 -2
- package/dist/template.js +1 -1
- package/package.json +13 -13
package/dist/template.d.ts
CHANGED
|
@@ -126,8 +126,23 @@ export declare interface TemplateOptions {
|
|
|
126
126
|
subject?: string
|
|
127
127
|
inline?: boolean
|
|
128
128
|
}
|
|
129
|
-
/**
|
|
130
|
-
export type
|
|
129
|
+
/** A single value a template can print. */
|
|
130
|
+
export type TemplateScalar = string | number | boolean | undefined | null | SafeHtml;
|
|
131
|
+
/**
|
|
132
|
+
* Allowed types for email template variable values.
|
|
133
|
+
*
|
|
134
|
+
* Lists and records are for `.stx` templates, which receive the variables as
|
|
135
|
+
* props and can `@foreach` over a list of rows (a digest's top pages, an
|
|
136
|
+
* order's line items). The type used to stop at scalars, so a caller passing
|
|
137
|
+
* the rows its own `.stx` template loops over had to cast them past it.
|
|
138
|
+
*
|
|
139
|
+
* A plain `.html` template has only `{{ name }}` substitution and nothing to
|
|
140
|
+
* iterate with, so a list or record there renders as empty rather than as
|
|
141
|
+
* `[object Object]`.
|
|
142
|
+
*/
|
|
143
|
+
export type TemplateVariableValue = | TemplateScalar
|
|
144
|
+
| readonly TemplateVariableValue[]
|
|
145
|
+
| { readonly [key: string]: TemplateVariableValue }
|
|
131
146
|
/** Map of variable names to their values for template replacement */
|
|
132
147
|
export type TemplateVariables = Record<string, TemplateVariableValue>;
|
|
133
148
|
/**
|
package/dist/template.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var {require}=import.meta;import{config}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{fs}from"@stacksjs/storage";import{defaultsResourcesPath,resourcesPath,storagePath}from"@stacksjs/path";import{join,resolve as resolvePath}from"node:path";import{inlineCss,shouldInlineByDefault}from"./css-inliner";export class SafeHtml{value;__safeHtml=!0;constructor(value){this.value=value}}export function safe(html){return new SafeHtml(html)}function getDefaultVariables(){const primaryColor=config.app.primaryColor||"#3b82f6";return{appName:config.app.name||"Stacks",appUrl:config.app.url||"https://localhost",primaryColor,primaryColorDark:darkenColor(primaryColor,15),year:new Date().getFullYear()}}function darkenColor(hex,percent){const num=Number.parseInt(hex.replace("#",""),16),amt=Math.round(2.55*percent),R=Math.max(0,(num>>16)-amt),G=Math.max(0,(num>>8&255)-amt),B=Math.max(0,(num&255)-amt);return`#${(16777216+R*65536+G*256+B).toString(16).slice(1)}`}export function escapeHtml(input){return input.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function replaceVariables(html,variables){let result=html;for(const[key,value]of Object.entries(variables)){const escapedKey=key.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),regex=new RegExp(`\\{\\{\\s*${escapedKey}\\s*\\}\\}`,"g");result=result.replace(regex,renderTemplateValue(value))}return result}function renderTemplateValue(value){if(value===null||value===void 0)return"";if(value instanceof SafeHtml)return value.value;return escapeHtml(String(value))}const templateRoots=[(relativePath)=>resourcesPath(join("emails",relativePath)),(relativePath)=>defaultsResourcesPath(join("emails",relativePath))];let templateRegistry=null,templateRegistryLoaded=!1,templateRegistryCwd=null;function loadTemplateRegistry(){const cwd=process.cwd();if(templateRegistryLoaded&&templateRegistryCwd===cwd)return templateRegistry;templateRegistry=null;templateRegistryLoaded=!0;templateRegistryCwd=cwd;try{const dir=storagePath("framework/auto-imports"),module=require(`${dir}/emails.ts`);if(!module.emails)return null;templateRegistry=Object.fromEntries(Object.entries(module.emails).map(([name,file])=>[name,{path:resolvePath(dir,file),type:file.endsWith(".stx")?"stx":"html"}]))}catch{templateRegistry=null}return templateRegistry}export function resetTemplateRegistry(){templateRegistry=null;templateRegistryLoaded=!1;templateRegistryCwd=null}function resolveTemplatePath(templateName){const registry=loadTemplateRegistry();if(registry){const bare=templateName.replace(/\.(?:stx|html)$/,""),hit=registry[bare];if(hit){if(templateName.endsWith(".stx")&&hit.type!=="stx");else if(templateName.endsWith(".html")&&hit.type!=="html");else if(fs.existsSync(hit.path))return hit}}for(const root of templateRoots){if(templateName.endsWith(".stx")){const fullPath=root(templateName);if(fs.existsSync(fullPath))return{path:fullPath,type:"stx"};continue}if(templateName.endsWith(".html")){const fullPath=root(templateName);if(fs.existsSync(fullPath))return{path:fullPath,type:"html"};continue}const stxPath=root(`${templateName}.stx`);if(fs.existsSync(stxPath))return{path:stxPath,type:"stx"};const htmlPath=root(`${templateName}.html`);if(fs.existsSync(htmlPath))return{path:htmlPath,type:"html"}}return null}function loadHtmlTemplate(templatePath){const path=templatePath.endsWith(".html")?templatePath:`${templatePath}.html`;for(const root of templateRoots){const fullPath=root(path);if(fs.existsSync(fullPath))return fs.readFileSync(fullPath,"utf-8")}return null}function loadLayout(layoutName){return loadHtmlTemplate(`layouts/${layoutName}`)}export function htmlToText(html){return((value)=>value.replace(/ /g," ").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'|'/g,"'").replace(/©/g,"(c)").replace(/&#(\d+);/g,(_,code)=>String.fromCodePoint(Number(code))).replace(/&#x([\da-f]+);/gi,(_,code)=>String.fromCodePoint(Number.parseInt(code,16))).replace(/&/g,"&"))(html.replace(/<(head|style|script|title)\b[^>]*>[\s\S]*?<\/\1>/gi,"").replace(/<!--[\s\S]*?-->/g,"").replace(/<a\b[^>]*?\bhref\s*=\s*(["'])(.*?)\1[^>]*>([\s\S]*?)<\/a>/gi,(_,_quote,href,inner)=>{const label=inner.replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim(),url=href.trim();if(!url||url==="#"||url.startsWith("javascript:"))return label;if(`mailto:${label}`===url)return label;if(!label||label===url)return url;return`${label} (${url})`}).replace(/<br\s*\/?>/gi,`
|
|
1
|
+
var {require}=import.meta;import{config}from"@stacksjs/config";import{log}from"@stacksjs/logging";import{fs}from"@stacksjs/storage";import{defaultsResourcesPath,resourcesPath,storagePath}from"@stacksjs/path";import{join,resolve as resolvePath}from"node:path";import{inlineCss,shouldInlineByDefault}from"./css-inliner";export class SafeHtml{value;__safeHtml=!0;constructor(value){this.value=value}}export function safe(html){return new SafeHtml(html)}function getDefaultVariables(){const primaryColor=config.app.primaryColor||"#3b82f6";return{appName:config.app.name||"Stacks",appUrl:config.app.url||"https://localhost",primaryColor,primaryColorDark:darkenColor(primaryColor,15),year:new Date().getFullYear()}}function darkenColor(hex,percent){const num=Number.parseInt(hex.replace("#",""),16),amt=Math.round(2.55*percent),R=Math.max(0,(num>>16)-amt),G=Math.max(0,(num>>8&255)-amt),B=Math.max(0,(num&255)-amt);return`#${(16777216+R*65536+G*256+B).toString(16).slice(1)}`}export function escapeHtml(input){return input.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function replaceVariables(html,variables){let result=html;for(const[key,value]of Object.entries(variables)){const escapedKey=key.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),regex=new RegExp(`\\{\\{\\s*${escapedKey}\\s*\\}\\}`,"g");result=result.replace(regex,renderTemplateValue(value))}return result}function renderTemplateValue(value){if(value===null||value===void 0)return"";if(value instanceof SafeHtml)return value.value;if(typeof value==="object")return"";return escapeHtml(String(value))}const templateRoots=[(relativePath)=>resourcesPath(join("emails",relativePath)),(relativePath)=>defaultsResourcesPath(join("emails",relativePath))];let templateRegistry=null,templateRegistryLoaded=!1,templateRegistryCwd=null;function loadTemplateRegistry(){const cwd=process.cwd();if(templateRegistryLoaded&&templateRegistryCwd===cwd)return templateRegistry;templateRegistry=null;templateRegistryLoaded=!0;templateRegistryCwd=cwd;try{const dir=storagePath("framework/auto-imports"),module=require(`${dir}/emails.ts`);if(!module.emails)return null;templateRegistry=Object.fromEntries(Object.entries(module.emails).map(([name,file])=>[name,{path:resolvePath(dir,file),type:file.endsWith(".stx")?"stx":"html"}]))}catch{templateRegistry=null}return templateRegistry}export function resetTemplateRegistry(){templateRegistry=null;templateRegistryLoaded=!1;templateRegistryCwd=null}function resolveTemplatePath(templateName){const registry=loadTemplateRegistry();if(registry){const bare=templateName.replace(/\.(?:stx|html)$/,""),hit=registry[bare];if(hit){if(templateName.endsWith(".stx")&&hit.type!=="stx");else if(templateName.endsWith(".html")&&hit.type!=="html");else if(fs.existsSync(hit.path))return hit}}for(const root of templateRoots){if(templateName.endsWith(".stx")){const fullPath=root(templateName);if(fs.existsSync(fullPath))return{path:fullPath,type:"stx"};continue}if(templateName.endsWith(".html")){const fullPath=root(templateName);if(fs.existsSync(fullPath))return{path:fullPath,type:"html"};continue}const stxPath=root(`${templateName}.stx`);if(fs.existsSync(stxPath))return{path:stxPath,type:"stx"};const htmlPath=root(`${templateName}.html`);if(fs.existsSync(htmlPath))return{path:htmlPath,type:"html"}}return null}function loadHtmlTemplate(templatePath){const path=templatePath.endsWith(".html")?templatePath:`${templatePath}.html`;for(const root of templateRoots){const fullPath=root(path);if(fs.existsSync(fullPath))return fs.readFileSync(fullPath,"utf-8")}return null}function loadLayout(layoutName){return loadHtmlTemplate(`layouts/${layoutName}`)}export function htmlToText(html){return((value)=>value.replace(/ /g," ").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'|'/g,"'").replace(/©/g,"(c)").replace(/&#(\d+);/g,(_,code)=>String.fromCodePoint(Number(code))).replace(/&#x([\da-f]+);/gi,(_,code)=>String.fromCodePoint(Number.parseInt(code,16))).replace(/&/g,"&"))(html.replace(/<(head|style|script|title)\b[^>]*>[\s\S]*?<\/\1>/gi,"").replace(/<!--[\s\S]*?-->/g,"").replace(/<a\b[^>]*?\bhref\s*=\s*(["'])(.*?)\1[^>]*>([\s\S]*?)<\/a>/gi,(_,_quote,href,inner)=>{const label=inner.replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim(),url=href.trim();if(!url||url==="#"||url.startsWith("javascript:"))return label;if(`mailto:${label}`===url)return label;if(!label||label===url)return url;return`${label} (${url})`}).replace(/<br\s*\/?>/gi,`
|
|
2
2
|
`).replace(/<\/(p|div|h[1-6]|li|tr|table)>/gi,`
|
|
3
3
|
`).replace(/<\/td>/gi,"\t").replace(/<[^>]*>/g,"")).split(`
|
|
4
4
|
`).map((line)=>line.replace(/[ \t]+/g," ").trim()).join(`
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/email",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.75.0",
|
|
6
6
|
"description": "The Stacks Email integration. Painlessly create & manage your inboxes, templates, and send emails.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -61,26 +61,26 @@
|
|
|
61
61
|
"prepublishOnly": "bun run build"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@stacksjs/config": "0.
|
|
65
|
-
"@stacksjs/database": "0.
|
|
66
|
-
"@stacksjs/events": "0.
|
|
67
|
-
"@stacksjs/logging": "0.
|
|
64
|
+
"@stacksjs/config": "0.75.0",
|
|
65
|
+
"@stacksjs/database": "0.75.0",
|
|
66
|
+
"@stacksjs/events": "0.75.0",
|
|
67
|
+
"@stacksjs/logging": "0.75.0",
|
|
68
68
|
"@stacksjs/mail": "^0.3.6",
|
|
69
|
-
"@stacksjs/path": "0.
|
|
70
|
-
"@stacksjs/storage": "0.
|
|
71
|
-
"@stacksjs/strings": "0.
|
|
69
|
+
"@stacksjs/path": "0.75.0",
|
|
70
|
+
"@stacksjs/storage": "0.75.0",
|
|
71
|
+
"@stacksjs/strings": "0.75.0",
|
|
72
72
|
"@stacksjs/stx": "^0.2.307",
|
|
73
73
|
"@stacksjs/ts-cloud": "^0.16.0",
|
|
74
|
-
"@stacksjs/utils": "0.
|
|
74
|
+
"@stacksjs/utils": "0.75.0"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@stacksjs/cli": "0.
|
|
78
|
-
"@stacksjs/error-handling": "0.
|
|
79
|
-
"@stacksjs/types": "0.
|
|
77
|
+
"@stacksjs/cli": "0.75.0",
|
|
78
|
+
"@stacksjs/error-handling": "0.75.0",
|
|
79
|
+
"@stacksjs/types": "0.75.0",
|
|
80
80
|
"better-dx": "^0.2.24"
|
|
81
81
|
},
|
|
82
82
|
"peerDependencies": {
|
|
83
|
-
"@stacksjs/queue": "0.
|
|
83
|
+
"@stacksjs/queue": "0.75.0"
|
|
84
84
|
},
|
|
85
85
|
"peerDependenciesMeta": {
|
|
86
86
|
"@stacksjs/queue": {
|