@astralibx/email-rule-engine 14.0.0 → 14.0.2

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 CHANGED
@@ -41,7 +41,7 @@ const engine = createEmailRuleEngine({
41
41
  text: params.textBody,
42
42
  });
43
43
  },
44
- selectAgent: async () => ({ accountId: 'default', email: 'noreply@myapp.com', metadata: {} }),
44
+ selectAgent: async () => ({ accountId: 'default', contactValue: 'noreply@myapp.com', metadata: {} }),
45
45
  findIdentifier: async (email) => {
46
46
  const contact = await Contact.findOne({ email });
47
47
  return contact ? { id: contact._id.toString(), contactId: contact._id.toString() } : null;
package/dist/index.cjs CHANGED
@@ -37,9 +37,8 @@ function renderMjml(body) {
37
37
  minify: false
38
38
  });
39
39
  if (result.errors?.length) {
40
- const critical = result.errors.filter((e) => e.tagName !== void 0);
41
- if (critical.length > 0) {
42
- throw new Error(`MJML compilation errors: ${critical.map((e) => e.message).join("; ")}`);
40
+ for (const err of result.errors) {
41
+ console.warn(`MJML warning: ${err.message || JSON.stringify(err)}`);
43
42
  }
44
43
  }
45
44
  return result.html;
@@ -58,7 +57,10 @@ var DATE_FORMAT_OPTIONS = {
58
57
  month: "short",
59
58
  year: "numeric"
60
59
  };
60
+ var registered = false;
61
61
  function registerEmailHelpers() {
62
+ if (registered) return;
63
+ registered = true;
62
64
  Handlebars__default.default.registerHelper("currency", (val) => {
63
65
  const num = Number(val);
64
66
  if (isNaN(num)) return String(val ?? "");
@@ -71,6 +73,8 @@ function registerEmailHelpers() {
71
73
  return d.toLocaleDateString("en-IN", DATE_FORMAT_OPTIONS);
72
74
  });
73
75
  }
76
+
77
+ // src/index.ts
74
78
  function createEmailRuleEngine(config) {
75
79
  registerEmailHelpers();
76
80
  const coreConfig = {
@@ -92,13 +96,13 @@ function createEmailRuleEngine(config) {
92
96
  textBody: text,
93
97
  ruleId: params.ruleId,
94
98
  autoApprove: params.autoApprove,
95
- attachments: params.metadata?.attachments ?? void 0
99
+ attachments: Array.isArray(params.metadata?.attachments) ? params.metadata.attachments : void 0
96
100
  });
97
101
  },
98
102
  sendTest: config.adapters.sendTestEmail ? async (to, body, subject, metadata) => {
99
103
  const html = renderMjml(body);
100
104
  const text = htmlToPlainText(html);
101
- await config.adapters.sendTestEmail(to, subject || "", html, text, metadata?.attachments ?? void 0);
105
+ await config.adapters.sendTestEmail(to, subject || "", html, text, Array.isArray(metadata?.attachments) ? metadata.attachments : void 0);
102
106
  } : void 0
103
107
  }
104
108
  };
@@ -109,11 +113,5 @@ exports.createEmailRuleEngine = createEmailRuleEngine;
109
113
  exports.htmlToPlainText = htmlToPlainText;
110
114
  exports.registerEmailHelpers = registerEmailHelpers;
111
115
  exports.renderMjml = renderMjml;
112
- Object.keys(ruleEngine).forEach(function (k) {
113
- if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
114
- enumerable: true,
115
- get: function () { return ruleEngine[k]; }
116
- });
117
- });
118
116
  //# sourceMappingURL=index.cjs.map
119
117
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mjml-renderer.ts","../src/email-helpers.ts","../src/index.ts"],"names":["mjml2html","convert","Handlebars","createRuleEngine"],"mappings":"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","file":"index.cjs","sourcesContent":["import mjml2html from 'mjml';\nimport { convert } from 'html-to-text';\n\nconst MJML_BASE_OPEN = `<mjml>\n <mj-head>\n <mj-attributes>\n <mj-all font-family=\"Arial, sans-serif\" />\n <mj-text font-size=\"15px\" color=\"#333333\" line-height=\"1.6\" />\n </mj-attributes>\n </mj-head>\n <mj-body background-color=\"#ffffff\">\n <mj-section padding=\"20px\">\n <mj-column>\n <mj-text>`;\n\nconst MJML_BASE_CLOSE = ` </mj-text>\n </mj-column>\n </mj-section>\n </mj-body>\n</mjml>`;\n\nexport function renderMjml(body: string): string {\n if (!body.includes('<mj-') && !body.trim().startsWith('<mjml')) {\n return body;\n }\n\n const fullMjml = body.trim().startsWith('<mjml')\n ? body\n : `${MJML_BASE_OPEN}${body}${MJML_BASE_CLOSE}`;\n\n const result = mjml2html(fullMjml, {\n validationLevel: 'soft',\n minify: false,\n });\n\n if (result.errors?.length) {\n const critical = result.errors.filter((e: any) => e.tagName !== undefined);\n if (critical.length > 0) {\n throw new Error(`MJML compilation errors: ${critical.map((e: any) => e.message).join('; ')}`);\n }\n }\n\n return result.html;\n}\n\nexport function htmlToPlainText(html: string): string {\n return convert(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n { selector: 'img', format: 'skip' },\n ],\n });\n}\n","import Handlebars from 'handlebars';\n\nconst DATE_FORMAT_OPTIONS: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n};\n\nexport function registerEmailHelpers(): void {\n Handlebars.registerHelper('currency', (val: any) => {\n const num = Number(val);\n if (isNaN(num)) return String(val ?? '');\n return `₹${num.toLocaleString('en-IN')}`;\n });\n\n Handlebars.registerHelper('formatDate', (date: any) => {\n if (!date) return '';\n const d = new Date(date);\n if (isNaN(d.getTime())) return String(date);\n return d.toLocaleDateString('en-IN', DATE_FORMAT_OPTIONS);\n });\n}\n","import {\n createRuleEngine,\n type RuleEngine,\n type RuleEngineConfig,\n type SendParams,\n} from '@astralibx/rule-engine';\nimport { renderMjml, htmlToPlainText } from './mjml-renderer';\nimport { registerEmailHelpers } from './email-helpers';\n\nexport interface EmailSendParams {\n identifierId: string;\n contactId: string;\n accountId: string;\n subject: string;\n htmlBody: string;\n textBody: string;\n ruleId: string;\n autoApprove: boolean;\n attachments?: Array<{ filename: string; url: string; contentType: string }>;\n}\n\nexport interface EmailRuleEngineConfig extends Omit<RuleEngineConfig, 'adapters'> {\n adapters: Omit<RuleEngineConfig['adapters'], 'send' | 'sendTest'> & {\n sendEmail: (params: EmailSendParams) => Promise<void>;\n sendTestEmail?: (to: string, subject: string, html: string, text: string, attachments?: Array<{ filename: string; url: string; contentType: string }>) => Promise<void>;\n };\n}\n\nexport function createEmailRuleEngine(config: EmailRuleEngineConfig): RuleEngine {\n // Register email-specific helpers before engine creation\n registerEmailHelpers();\n\n const coreConfig: RuleEngineConfig = {\n ...config,\n adapters: {\n queryUsers: config.adapters.queryUsers,\n resolveData: config.adapters.resolveData,\n selectAgent: config.adapters.selectAgent,\n findIdentifier: config.adapters.findIdentifier,\n send: async (params: SendParams) => {\n const html = renderMjml(params.body);\n const text = params.textBody || htmlToPlainText(html);\n await config.adapters.sendEmail({\n identifierId: params.identifierId,\n contactId: params.contactId,\n accountId: params.accountId,\n subject: params.subject || '',\n htmlBody: html,\n textBody: text,\n ruleId: params.ruleId,\n autoApprove: params.autoApprove,\n attachments: (params.metadata?.attachments as any[]) ?? undefined,\n });\n },\n sendTest: config.adapters.sendTestEmail\n ? async (to: string, body: string, subject?: string, metadata?: Record<string, unknown>) => {\n const html = renderMjml(body);\n const text = htmlToPlainText(html);\n await config.adapters.sendTestEmail!(to, subject || '', html, text, (metadata?.attachments as any[]) ?? undefined);\n }\n : undefined,\n },\n };\n\n return createRuleEngine(coreConfig);\n}\n\n// Re-export everything from core\nexport * from '@astralibx/rule-engine';\n\n// Export email-specific utilities\nexport { renderMjml, htmlToPlainText } from './mjml-renderer';\nexport { registerEmailHelpers } from './email-helpers';\n"]}
1
+ {"version":3,"sources":["../src/mjml-renderer.ts","../src/email-helpers.ts","../src/index.ts"],"names":["mjml2html","convert","Handlebars","createRuleEngine"],"mappings":"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","file":"index.cjs","sourcesContent":["import mjml2html from 'mjml';\nimport { convert } from 'html-to-text';\n\nconst MJML_BASE_OPEN = `<mjml>\n <mj-head>\n <mj-attributes>\n <mj-all font-family=\"Arial, sans-serif\" />\n <mj-text font-size=\"15px\" color=\"#333333\" line-height=\"1.6\" />\n </mj-attributes>\n </mj-head>\n <mj-body background-color=\"#ffffff\">\n <mj-section padding=\"20px\">\n <mj-column>\n <mj-text>`;\n\nconst MJML_BASE_CLOSE = ` </mj-text>\n </mj-column>\n </mj-section>\n </mj-body>\n</mjml>`;\n\nexport function renderMjml(body: string): string {\n if (!body.includes('<mj-') && !body.trim().startsWith('<mjml')) {\n return body;\n }\n\n const fullMjml = body.trim().startsWith('<mjml')\n ? body\n : `${MJML_BASE_OPEN}${body}${MJML_BASE_CLOSE}`;\n\n const result = mjml2html(fullMjml, {\n validationLevel: 'soft',\n minify: false,\n });\n\n if (result.errors?.length) {\n // Log all MJML warnings/errors for debugging\n for (const err of result.errors) {\n console.warn(`MJML warning: ${(err as any).message || JSON.stringify(err)}`);\n }\n }\n\n return result.html;\n}\n\nexport function htmlToPlainText(html: string): string {\n return convert(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n { selector: 'img', format: 'skip' },\n ],\n });\n}\n","import Handlebars from 'handlebars';\n\nconst DATE_FORMAT_OPTIONS: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n};\n\nlet registered = false;\n\nexport function registerEmailHelpers(): void {\n if (registered) return;\n registered = true;\n Handlebars.registerHelper('currency', (val: any) => {\n const num = Number(val);\n if (isNaN(num)) return String(val ?? '');\n return `₹${num.toLocaleString('en-IN')}`;\n });\n\n Handlebars.registerHelper('formatDate', (date: any) => {\n if (!date) return '';\n const d = new Date(date);\n if (isNaN(d.getTime())) return String(date);\n return d.toLocaleDateString('en-IN', DATE_FORMAT_OPTIONS);\n });\n}\n","import {\n createRuleEngine,\n type RuleEngine,\n type RuleEngineConfig,\n type SendParams,\n} from '@astralibx/rule-engine';\nimport { renderMjml, htmlToPlainText } from './mjml-renderer';\nimport { registerEmailHelpers } from './email-helpers';\n\nexport interface EmailSendParams {\n identifierId: string;\n contactId: string;\n accountId: string;\n subject: string;\n htmlBody: string;\n textBody: string;\n ruleId: string;\n autoApprove: boolean;\n attachments?: Array<{ filename: string; url: string; contentType: string }>;\n}\n\nexport interface EmailRuleEngineConfig extends Omit<RuleEngineConfig, 'adapters'> {\n adapters: Omit<RuleEngineConfig['adapters'], 'send' | 'sendTest'> & {\n sendEmail: (params: EmailSendParams) => Promise<void>;\n sendTestEmail?: (to: string, subject: string, html: string, text: string, attachments?: Array<{ filename: string; url: string; contentType: string }>) => Promise<void>;\n };\n}\n\nexport function createEmailRuleEngine(config: EmailRuleEngineConfig): RuleEngine {\n // Register email-specific helpers before engine creation\n registerEmailHelpers();\n\n const coreConfig: RuleEngineConfig = {\n ...config,\n adapters: {\n queryUsers: config.adapters.queryUsers,\n resolveData: config.adapters.resolveData,\n selectAgent: config.adapters.selectAgent,\n findIdentifier: config.adapters.findIdentifier,\n send: async (params: SendParams) => {\n const html = renderMjml(params.body);\n const text = params.textBody || htmlToPlainText(html);\n await config.adapters.sendEmail({\n identifierId: params.identifierId,\n contactId: params.contactId,\n accountId: params.accountId,\n subject: params.subject || '',\n htmlBody: html,\n textBody: text,\n ruleId: params.ruleId,\n autoApprove: params.autoApprove,\n attachments: Array.isArray(params.metadata?.attachments) ? params.metadata.attachments : undefined,\n });\n },\n sendTest: config.adapters.sendTestEmail\n ? async (to: string, body: string, subject?: string, metadata?: Record<string, unknown>) => {\n const html = renderMjml(body);\n const text = htmlToPlainText(html);\n await config.adapters.sendTestEmail!(to, subject || '', html, text, Array.isArray(metadata?.attachments) ? metadata.attachments : undefined);\n }\n : undefined,\n },\n };\n\n return createRuleEngine(coreConfig);\n}\n\n// Export email-specific utilities\nexport { renderMjml, htmlToPlainText } from './mjml-renderer';\nexport { registerEmailHelpers } from './email-helpers';\nexport type { RuleEngine } from '@astralibx/rule-engine';\n"]}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RuleEngineConfig, RuleEngine } from '@astralibx/rule-engine';
2
- export * from '@astralibx/rule-engine';
2
+ export { RuleEngine } from '@astralibx/rule-engine';
3
3
 
4
4
  declare function renderMjml(body: string): string;
5
5
  declare function htmlToPlainText(html: string): string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RuleEngineConfig, RuleEngine } from '@astralibx/rule-engine';
2
- export * from '@astralibx/rule-engine';
2
+ export { RuleEngine } from '@astralibx/rule-engine';
3
3
 
4
4
  declare function renderMjml(body: string): string;
5
5
  declare function htmlToPlainText(html: string): string;
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { createRuleEngine } from '@astralibx/rule-engine';
2
- export * from '@astralibx/rule-engine';
3
2
  import mjml2html from 'mjml';
4
3
  import { convert } from 'html-to-text';
5
4
  import Handlebars from 'handlebars';
@@ -31,9 +30,8 @@ function renderMjml(body) {
31
30
  minify: false
32
31
  });
33
32
  if (result.errors?.length) {
34
- const critical = result.errors.filter((e) => e.tagName !== void 0);
35
- if (critical.length > 0) {
36
- throw new Error(`MJML compilation errors: ${critical.map((e) => e.message).join("; ")}`);
33
+ for (const err of result.errors) {
34
+ console.warn(`MJML warning: ${err.message || JSON.stringify(err)}`);
37
35
  }
38
36
  }
39
37
  return result.html;
@@ -52,7 +50,10 @@ var DATE_FORMAT_OPTIONS = {
52
50
  month: "short",
53
51
  year: "numeric"
54
52
  };
53
+ var registered = false;
55
54
  function registerEmailHelpers() {
55
+ if (registered) return;
56
+ registered = true;
56
57
  Handlebars.registerHelper("currency", (val) => {
57
58
  const num = Number(val);
58
59
  if (isNaN(num)) return String(val ?? "");
@@ -65,6 +66,8 @@ function registerEmailHelpers() {
65
66
  return d.toLocaleDateString("en-IN", DATE_FORMAT_OPTIONS);
66
67
  });
67
68
  }
69
+
70
+ // src/index.ts
68
71
  function createEmailRuleEngine(config) {
69
72
  registerEmailHelpers();
70
73
  const coreConfig = {
@@ -86,13 +89,13 @@ function createEmailRuleEngine(config) {
86
89
  textBody: text,
87
90
  ruleId: params.ruleId,
88
91
  autoApprove: params.autoApprove,
89
- attachments: params.metadata?.attachments ?? void 0
92
+ attachments: Array.isArray(params.metadata?.attachments) ? params.metadata.attachments : void 0
90
93
  });
91
94
  },
92
95
  sendTest: config.adapters.sendTestEmail ? async (to, body, subject, metadata) => {
93
96
  const html = renderMjml(body);
94
97
  const text = htmlToPlainText(html);
95
- await config.adapters.sendTestEmail(to, subject || "", html, text, metadata?.attachments ?? void 0);
98
+ await config.adapters.sendTestEmail(to, subject || "", html, text, Array.isArray(metadata?.attachments) ? metadata.attachments : void 0);
96
99
  } : void 0
97
100
  }
98
101
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mjml-renderer.ts","../src/email-helpers.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import mjml2html from 'mjml';\nimport { convert } from 'html-to-text';\n\nconst MJML_BASE_OPEN = `<mjml>\n <mj-head>\n <mj-attributes>\n <mj-all font-family=\"Arial, sans-serif\" />\n <mj-text font-size=\"15px\" color=\"#333333\" line-height=\"1.6\" />\n </mj-attributes>\n </mj-head>\n <mj-body background-color=\"#ffffff\">\n <mj-section padding=\"20px\">\n <mj-column>\n <mj-text>`;\n\nconst MJML_BASE_CLOSE = ` </mj-text>\n </mj-column>\n </mj-section>\n </mj-body>\n</mjml>`;\n\nexport function renderMjml(body: string): string {\n if (!body.includes('<mj-') && !body.trim().startsWith('<mjml')) {\n return body;\n }\n\n const fullMjml = body.trim().startsWith('<mjml')\n ? body\n : `${MJML_BASE_OPEN}${body}${MJML_BASE_CLOSE}`;\n\n const result = mjml2html(fullMjml, {\n validationLevel: 'soft',\n minify: false,\n });\n\n if (result.errors?.length) {\n const critical = result.errors.filter((e: any) => e.tagName !== undefined);\n if (critical.length > 0) {\n throw new Error(`MJML compilation errors: ${critical.map((e: any) => e.message).join('; ')}`);\n }\n }\n\n return result.html;\n}\n\nexport function htmlToPlainText(html: string): string {\n return convert(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n { selector: 'img', format: 'skip' },\n ],\n });\n}\n","import Handlebars from 'handlebars';\n\nconst DATE_FORMAT_OPTIONS: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n};\n\nexport function registerEmailHelpers(): void {\n Handlebars.registerHelper('currency', (val: any) => {\n const num = Number(val);\n if (isNaN(num)) return String(val ?? '');\n return `₹${num.toLocaleString('en-IN')}`;\n });\n\n Handlebars.registerHelper('formatDate', (date: any) => {\n if (!date) return '';\n const d = new Date(date);\n if (isNaN(d.getTime())) return String(date);\n return d.toLocaleDateString('en-IN', DATE_FORMAT_OPTIONS);\n });\n}\n","import {\n createRuleEngine,\n type RuleEngine,\n type RuleEngineConfig,\n type SendParams,\n} from '@astralibx/rule-engine';\nimport { renderMjml, htmlToPlainText } from './mjml-renderer';\nimport { registerEmailHelpers } from './email-helpers';\n\nexport interface EmailSendParams {\n identifierId: string;\n contactId: string;\n accountId: string;\n subject: string;\n htmlBody: string;\n textBody: string;\n ruleId: string;\n autoApprove: boolean;\n attachments?: Array<{ filename: string; url: string; contentType: string }>;\n}\n\nexport interface EmailRuleEngineConfig extends Omit<RuleEngineConfig, 'adapters'> {\n adapters: Omit<RuleEngineConfig['adapters'], 'send' | 'sendTest'> & {\n sendEmail: (params: EmailSendParams) => Promise<void>;\n sendTestEmail?: (to: string, subject: string, html: string, text: string, attachments?: Array<{ filename: string; url: string; contentType: string }>) => Promise<void>;\n };\n}\n\nexport function createEmailRuleEngine(config: EmailRuleEngineConfig): RuleEngine {\n // Register email-specific helpers before engine creation\n registerEmailHelpers();\n\n const coreConfig: RuleEngineConfig = {\n ...config,\n adapters: {\n queryUsers: config.adapters.queryUsers,\n resolveData: config.adapters.resolveData,\n selectAgent: config.adapters.selectAgent,\n findIdentifier: config.adapters.findIdentifier,\n send: async (params: SendParams) => {\n const html = renderMjml(params.body);\n const text = params.textBody || htmlToPlainText(html);\n await config.adapters.sendEmail({\n identifierId: params.identifierId,\n contactId: params.contactId,\n accountId: params.accountId,\n subject: params.subject || '',\n htmlBody: html,\n textBody: text,\n ruleId: params.ruleId,\n autoApprove: params.autoApprove,\n attachments: (params.metadata?.attachments as any[]) ?? undefined,\n });\n },\n sendTest: config.adapters.sendTestEmail\n ? async (to: string, body: string, subject?: string, metadata?: Record<string, unknown>) => {\n const html = renderMjml(body);\n const text = htmlToPlainText(html);\n await config.adapters.sendTestEmail!(to, subject || '', html, text, (metadata?.attachments as any[]) ?? undefined);\n }\n : undefined,\n },\n };\n\n return createRuleEngine(coreConfig);\n}\n\n// Re-export everything from core\nexport * from '@astralibx/rule-engine';\n\n// Export email-specific utilities\nexport { renderMjml, htmlToPlainText } from './mjml-renderer';\nexport { registerEmailHelpers } from './email-helpers';\n"]}
1
+ {"version":3,"sources":["../src/mjml-renderer.ts","../src/email-helpers.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import mjml2html from 'mjml';\nimport { convert } from 'html-to-text';\n\nconst MJML_BASE_OPEN = `<mjml>\n <mj-head>\n <mj-attributes>\n <mj-all font-family=\"Arial, sans-serif\" />\n <mj-text font-size=\"15px\" color=\"#333333\" line-height=\"1.6\" />\n </mj-attributes>\n </mj-head>\n <mj-body background-color=\"#ffffff\">\n <mj-section padding=\"20px\">\n <mj-column>\n <mj-text>`;\n\nconst MJML_BASE_CLOSE = ` </mj-text>\n </mj-column>\n </mj-section>\n </mj-body>\n</mjml>`;\n\nexport function renderMjml(body: string): string {\n if (!body.includes('<mj-') && !body.trim().startsWith('<mjml')) {\n return body;\n }\n\n const fullMjml = body.trim().startsWith('<mjml')\n ? body\n : `${MJML_BASE_OPEN}${body}${MJML_BASE_CLOSE}`;\n\n const result = mjml2html(fullMjml, {\n validationLevel: 'soft',\n minify: false,\n });\n\n if (result.errors?.length) {\n // Log all MJML warnings/errors for debugging\n for (const err of result.errors) {\n console.warn(`MJML warning: ${(err as any).message || JSON.stringify(err)}`);\n }\n }\n\n return result.html;\n}\n\nexport function htmlToPlainText(html: string): string {\n return convert(html, {\n wordwrap: 80,\n selectors: [\n { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },\n { selector: 'img', format: 'skip' },\n ],\n });\n}\n","import Handlebars from 'handlebars';\n\nconst DATE_FORMAT_OPTIONS: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n};\n\nlet registered = false;\n\nexport function registerEmailHelpers(): void {\n if (registered) return;\n registered = true;\n Handlebars.registerHelper('currency', (val: any) => {\n const num = Number(val);\n if (isNaN(num)) return String(val ?? '');\n return `₹${num.toLocaleString('en-IN')}`;\n });\n\n Handlebars.registerHelper('formatDate', (date: any) => {\n if (!date) return '';\n const d = new Date(date);\n if (isNaN(d.getTime())) return String(date);\n return d.toLocaleDateString('en-IN', DATE_FORMAT_OPTIONS);\n });\n}\n","import {\n createRuleEngine,\n type RuleEngine,\n type RuleEngineConfig,\n type SendParams,\n} from '@astralibx/rule-engine';\nimport { renderMjml, htmlToPlainText } from './mjml-renderer';\nimport { registerEmailHelpers } from './email-helpers';\n\nexport interface EmailSendParams {\n identifierId: string;\n contactId: string;\n accountId: string;\n subject: string;\n htmlBody: string;\n textBody: string;\n ruleId: string;\n autoApprove: boolean;\n attachments?: Array<{ filename: string; url: string; contentType: string }>;\n}\n\nexport interface EmailRuleEngineConfig extends Omit<RuleEngineConfig, 'adapters'> {\n adapters: Omit<RuleEngineConfig['adapters'], 'send' | 'sendTest'> & {\n sendEmail: (params: EmailSendParams) => Promise<void>;\n sendTestEmail?: (to: string, subject: string, html: string, text: string, attachments?: Array<{ filename: string; url: string; contentType: string }>) => Promise<void>;\n };\n}\n\nexport function createEmailRuleEngine(config: EmailRuleEngineConfig): RuleEngine {\n // Register email-specific helpers before engine creation\n registerEmailHelpers();\n\n const coreConfig: RuleEngineConfig = {\n ...config,\n adapters: {\n queryUsers: config.adapters.queryUsers,\n resolveData: config.adapters.resolveData,\n selectAgent: config.adapters.selectAgent,\n findIdentifier: config.adapters.findIdentifier,\n send: async (params: SendParams) => {\n const html = renderMjml(params.body);\n const text = params.textBody || htmlToPlainText(html);\n await config.adapters.sendEmail({\n identifierId: params.identifierId,\n contactId: params.contactId,\n accountId: params.accountId,\n subject: params.subject || '',\n htmlBody: html,\n textBody: text,\n ruleId: params.ruleId,\n autoApprove: params.autoApprove,\n attachments: Array.isArray(params.metadata?.attachments) ? params.metadata.attachments : undefined,\n });\n },\n sendTest: config.adapters.sendTestEmail\n ? async (to: string, body: string, subject?: string, metadata?: Record<string, unknown>) => {\n const html = renderMjml(body);\n const text = htmlToPlainText(html);\n await config.adapters.sendTestEmail!(to, subject || '', html, text, Array.isArray(metadata?.attachments) ? metadata.attachments : undefined);\n }\n : undefined,\n },\n };\n\n return createRuleEngine(coreConfig);\n}\n\n// Export email-specific utilities\nexport { renderMjml, htmlToPlainText } from './mjml-renderer';\nexport { registerEmailHelpers } from './email-helpers';\nexport type { RuleEngine } from '@astralibx/rule-engine';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astralibx/email-rule-engine",
3
- "version": "14.0.0",
3
+ "version": "14.0.2",
4
4
  "description": "Email automation engine — thin wrapper over @astralibx/rule-engine with MJML rendering",
5
5
  "repository": {
6
6
  "type": "git",
@@ -49,8 +49,8 @@
49
49
  "mjml": "^4.0.0"
50
50
  },
51
51
  "peerDependencies": {
52
- "@astralibx/rule-engine": "^1.0.0",
53
52
  "express": "^4.18.0 || ^5.0.0",
53
+ "handlebars": "^4.7.0",
54
54
  "ioredis": "^5.0.0",
55
55
  "mongoose": "^7.0.0 || ^8.0.0"
56
56
  },
@@ -60,9 +60,7 @@
60
60
  "@types/node": "^22.0.0",
61
61
  "@vitest/coverage-v8": "^3.0.0",
62
62
  "express": "^5.0.0",
63
- "html-to-text": "^9.0.5",
64
63
  "ioredis": "^5.4.2",
65
- "mjml": "^4.15.3",
66
64
  "mongodb-memory-server": "^10.0.0",
67
65
  "mongoose": "^8.12.1",
68
66
  "typescript": "^5.8.2",