@emailens/engine 0.9.4 → 0.9.6

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/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { E as EmailClient, F as Framework, T as TransformResult, C as CSSWarning, a as CodeFix, D as DiffResult, b as ExportPromptOptions, A as AiProvider, c as AiFixResult, S as SupportLevel, d as SpamAnalysisOptions, e as SpamReport, L as LinkReport, f as AccessibilityReport, I as ImageReport, g as InboxPreview, h as SizeReport, i as TemplateReport, j as DeliverabilityReport } from './types-Duj14jTL.cjs';
2
- export { k as AccessibilityIssue, l as ClientTruncation, m as DeliverabilityCheck, n as DeliverabilityIssue, o as EstimateOptions, p as ExportScope, q as FixType, r as ImageInfo, s as ImageIssue, t as InboxPreviewIssue, u as InputFormat, v as LinkIssue, P as PreviewResult, w as SizeIssue, x as SpamIssue, y as TemplateIssue, z as TokenEstimate, B as TokenEstimateWithWarnings, G as estimateAiFixTokens, H as generateFixPrompt, J as heuristicTokenCount } from './types-Duj14jTL.cjs';
3
- export { C as CompileError, a as CompileReactEmailOptions, S as SandboxStrategy } from './react-email-BFwlVmzZ.cjs';
1
+ import { E as EmailClient, F as Framework, T as TransformResult, C as CSSWarning, a as CodeFix, D as DiffResult, b as ExportPromptOptions, A as AiProvider, c as AiFixResult, S as SupportLevel, d as SpamAnalysisOptions, e as SpamReport, L as LinkReport, f as AccessibilityReport, I as ImageReport, g as InboxPreview, h as SizeReport, i as TemplateReport, j as DeliverabilityReport } from './types-WvVf2OXX.cjs';
2
+ export { k as AccessibilityIssue, B as BaseIssue, l as ClientTruncation, m as DeliverabilityCheck, n as DeliverabilityIssue, o as EstimateOptions, p as ExportScope, q as FixType, r as ImageInfo, s as ImageIssue, t as InboxPreviewIssue, u as InputFormat, v as LinkIssue, P as PreviewResult, w as Severity, x as SizeIssue, y as SpamIssue, z as TemplateIssue, G as TokenEstimate, H as TokenEstimateWithWarnings, J as estimateAiFixTokens, K as generateFixPrompt, M as heuristicTokenCount } from './types-WvVf2OXX.cjs';
3
+ export { C as CompileError, a as CompileReactEmailOptions, S as SandboxStrategy } from './react-email-M23kFFxl.cjs';
4
4
 
5
5
  declare const EMAIL_CLIENTS: EmailClient[];
6
6
  declare function getClient(id: string): EmailClient | undefined;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { E as EmailClient, F as Framework, T as TransformResult, C as CSSWarning, a as CodeFix, D as DiffResult, b as ExportPromptOptions, A as AiProvider, c as AiFixResult, S as SupportLevel, d as SpamAnalysisOptions, e as SpamReport, L as LinkReport, f as AccessibilityReport, I as ImageReport, g as InboxPreview, h as SizeReport, i as TemplateReport, j as DeliverabilityReport } from './types-Duj14jTL.js';
2
- export { k as AccessibilityIssue, l as ClientTruncation, m as DeliverabilityCheck, n as DeliverabilityIssue, o as EstimateOptions, p as ExportScope, q as FixType, r as ImageInfo, s as ImageIssue, t as InboxPreviewIssue, u as InputFormat, v as LinkIssue, P as PreviewResult, w as SizeIssue, x as SpamIssue, y as TemplateIssue, z as TokenEstimate, B as TokenEstimateWithWarnings, G as estimateAiFixTokens, H as generateFixPrompt, J as heuristicTokenCount } from './types-Duj14jTL.js';
3
- export { C as CompileError, a as CompileReactEmailOptions, S as SandboxStrategy } from './react-email-BENS7LIn.js';
1
+ import { E as EmailClient, F as Framework, T as TransformResult, C as CSSWarning, a as CodeFix, D as DiffResult, b as ExportPromptOptions, A as AiProvider, c as AiFixResult, S as SupportLevel, d as SpamAnalysisOptions, e as SpamReport, L as LinkReport, f as AccessibilityReport, I as ImageReport, g as InboxPreview, h as SizeReport, i as TemplateReport, j as DeliverabilityReport } from './types-WvVf2OXX.js';
2
+ export { k as AccessibilityIssue, B as BaseIssue, l as ClientTruncation, m as DeliverabilityCheck, n as DeliverabilityIssue, o as EstimateOptions, p as ExportScope, q as FixType, r as ImageInfo, s as ImageIssue, t as InboxPreviewIssue, u as InputFormat, v as LinkIssue, P as PreviewResult, w as Severity, x as SizeIssue, y as SpamIssue, z as TemplateIssue, G as TokenEstimate, H as TokenEstimateWithWarnings, J as estimateAiFixTokens, K as generateFixPrompt, M as heuristicTokenCount } from './types-WvVf2OXX.js';
3
+ export { C as CompileError, a as CompileReactEmailOptions, S as SandboxStrategy } from './react-email-TJF6usIm.js';
4
4
 
5
5
  declare const EMAIL_CLIENTS: EmailClient[];
6
6
  declare function getClient(id: string): EmailClient | undefined;
package/dist/index.js CHANGED
@@ -8306,7 +8306,8 @@ function generateFixPrompt(options) {
8306
8306
  scores,
8307
8307
  scope,
8308
8308
  selectedClientId,
8309
- format = "html"
8309
+ format = "html",
8310
+ intent
8310
8311
  } = options;
8311
8312
  const filteredWarnings = scope === "current" && selectedClientId ? warnings.filter((w) => w.client === selectedClientId) : warnings;
8312
8313
  const filteredScores = scope === "current" && selectedClientId ? { [selectedClientId]: scores[selectedClientId] } : scores;
@@ -8329,6 +8330,16 @@ function generateFixPrompt(options) {
8329
8330
  - **Scope:** ${clientLabel}
8330
8331
  - **Issues found:** ${errorCount} error${errorCount !== 1 ? "s" : ""}, ${warnCount} warning${warnCount !== 1 ? "s" : ""}, ${infoCount} info`
8331
8332
  );
8333
+ const trimmedIntent = intent == null ? void 0 : intent.trim();
8334
+ if (trimmedIntent) {
8335
+ sections.push(
8336
+ `## User Intent
8337
+
8338
+ The user described what they want this email to achieve. Honor it where possible, but never at the cost of breaking email-client compatibility:
8339
+
8340
+ ` + trimmedIntent
8341
+ );
8342
+ }
8332
8343
  sections.push(
8333
8344
  `## Original Email Code
8334
8345
 
@@ -8564,8 +8575,17 @@ function extractCode(response) {
8564
8575
  return response.trim();
8565
8576
  }
8566
8577
 
8567
- // src/spam-scorer.ts
8578
+ // src/parse-html.ts
8568
8579
  import * as cheerio5 from "cheerio";
8580
+ function fromHtml(html, empty, fn) {
8581
+ if (!html || !html.trim()) return empty;
8582
+ if (html.length > MAX_HTML_SIZE) {
8583
+ throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
8584
+ }
8585
+ return fn(cheerio5.load(html), html);
8586
+ }
8587
+
8588
+ // src/spam-scorer.ts
8569
8589
  var SPAM_TRIGGER_PHRASES = [
8570
8590
  "act now",
8571
8591
  "limited time",
@@ -8995,18 +9015,10 @@ function analyzeSpamFromDom($, options) {
8995
9015
  return { score, level, issues };
8996
9016
  }
8997
9017
  function analyzeSpam(html, options) {
8998
- if (!html || !html.trim()) {
8999
- return { score: 100, level: "low", issues: [] };
9000
- }
9001
- if (html.length > MAX_HTML_SIZE) {
9002
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9003
- }
9004
- const $ = cheerio5.load(html);
9005
- return analyzeSpamFromDom($, options);
9018
+ return fromHtml(html, EMPTY_SPAM, ($) => analyzeSpamFromDom($, options));
9006
9019
  }
9007
9020
 
9008
9021
  // src/link-validator.ts
9009
- import * as cheerio6 from "cheerio";
9010
9022
  function classifyHref(href) {
9011
9023
  if (!href || !href.trim()) return "empty";
9012
9024
  const h = href.trim().toLowerCase();
@@ -9192,22 +9204,10 @@ function validateLinksFromDom($) {
9192
9204
  return { totalLinks, issues, breakdown };
9193
9205
  }
9194
9206
  function validateLinks(html) {
9195
- if (!html || !html.trim()) {
9196
- return {
9197
- totalLinks: 0,
9198
- issues: [],
9199
- breakdown: { https: 0, http: 0, mailto: 0, tel: 0, anchor: 0, javascript: 0, protocolRelative: 0, other: 0 }
9200
- };
9201
- }
9202
- if (html.length > MAX_HTML_SIZE) {
9203
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9204
- }
9205
- const $ = cheerio6.load(html);
9206
- return validateLinksFromDom($);
9207
+ return fromHtml(html, EMPTY_LINKS, validateLinksFromDom);
9207
9208
  }
9208
9209
 
9209
9210
  // src/accessibility-checker.ts
9210
- import * as cheerio7 from "cheerio";
9211
9211
  var RULE_PENALTY_CAPS = {
9212
9212
  "img-missing-alt": 3,
9213
9213
  "link-generic-text": 3,
@@ -9504,18 +9504,10 @@ function checkAccessibilityFromDom($) {
9504
9504
  return { score, issues };
9505
9505
  }
9506
9506
  function checkAccessibility(html) {
9507
- if (!html || !html.trim()) {
9508
- return { score: 100, issues: [] };
9509
- }
9510
- if (html.length > MAX_HTML_SIZE) {
9511
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9512
- }
9513
- const $ = cheerio7.load(html);
9514
- return checkAccessibilityFromDom($);
9507
+ return fromHtml(html, EMPTY_ACCESSIBILITY, checkAccessibilityFromDom);
9515
9508
  }
9516
9509
 
9517
9510
  // src/image-analyzer.ts
9518
- import * as cheerio8 from "cheerio";
9519
9511
  var DATA_URI_WARN_BYTES = 100 * 1024;
9520
9512
  var TOTAL_DATA_URI_WARN_BYTES = 500 * 1024;
9521
9513
  var HIGH_IMAGE_COUNT = 10;
@@ -9673,39 +9665,24 @@ function analyzeImagesFromDom($) {
9673
9665
  return { total: images.length, totalDataUriBytes, issues, images };
9674
9666
  }
9675
9667
  function analyzeImages(html) {
9676
- if (!html || !html.trim()) {
9677
- return { total: 0, totalDataUriBytes: 0, issues: [], images: [] };
9678
- }
9679
- if (html.length > MAX_HTML_SIZE) {
9680
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9681
- }
9682
- const $ = cheerio8.load(html);
9683
- return analyzeImagesFromDom($);
9668
+ return fromHtml(html, EMPTY_IMAGES, analyzeImagesFromDom);
9684
9669
  }
9685
9670
 
9686
9671
  // src/inbox-preview.ts
9687
- import * as cheerio9 from "cheerio";
9688
9672
  var MAX_SUBJECT_LENGTH = 60;
9689
9673
  var MAX_PREHEADER_LENGTH = 100;
9690
9674
  var MIN_PREHEADER_LENGTH = 30;
9691
9675
  var EMOJI_PATTERN = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{2B50}-\u{2B55}\u{FE00}-\u{FE0F}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{200D}\u{20E3}\u{E0020}-\u{E007F}]/u;
9692
9676
  var ZWNJ_PADDING_PATTERN = /(\u200C\s*( |\u00A0)\s*){2,}|(‌\s* \s*){2,}/;
9693
9677
  function extractInboxPreview(html) {
9694
- if (!html || !html.trim()) {
9695
- return {
9696
- subject: null,
9697
- preheader: null,
9698
- subjectLength: 0,
9699
- preheaderLength: 0,
9700
- truncation: [],
9701
- issues: [{ rule: "missing-subject", severity: "warning", message: "No <title> tag found. Most email clients use this as the subject line." }]
9702
- };
9703
- }
9704
- if (html.length > MAX_HTML_SIZE) {
9705
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9706
- }
9707
- const $ = cheerio9.load(html);
9708
- return extractInboxPreviewFromDom($);
9678
+ return fromHtml(html, {
9679
+ subject: null,
9680
+ preheader: null,
9681
+ subjectLength: 0,
9682
+ preheaderLength: 0,
9683
+ truncation: [],
9684
+ issues: [{ rule: "missing-subject", severity: "warning", message: "No <title> tag found. Most email clients use this as the subject line." }]
9685
+ }, extractInboxPreviewFromDom);
9709
9686
  }
9710
9687
  function extractInboxPreviewFromDom($) {
9711
9688
  var _a, _b;
@@ -9872,7 +9849,6 @@ function getFirstVisibleText($, body) {
9872
9849
  }
9873
9850
 
9874
9851
  // src/size-checker.ts
9875
- import * as cheerio10 from "cheerio";
9876
9852
  function humanizeBytes(bytes) {
9877
9853
  if (bytes < 1024) return `${bytes} B`;
9878
9854
  const kb = bytes / 1024;
@@ -9904,18 +9880,10 @@ function checkSizeFromDom(_$, html) {
9904
9880
  return { htmlBytes, humanSize, clipped, issues };
9905
9881
  }
9906
9882
  function checkSize(html) {
9907
- if (!html || !html.trim()) {
9908
- return { htmlBytes: 0, humanSize: "0 B", clipped: false, issues: [] };
9909
- }
9910
- if (html.length > MAX_HTML_SIZE) {
9911
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9912
- }
9913
- const $ = cheerio10.load(html);
9914
- return checkSizeFromDom($, html);
9883
+ return fromHtml(html, EMPTY_SIZE, checkSizeFromDom);
9915
9884
  }
9916
9885
 
9917
9886
  // src/template-checker.ts
9918
- import * as cheerio11 from "cheerio";
9919
9887
  function checkTemplateVariablesFromDom($) {
9920
9888
  const issues = [];
9921
9889
  const seen = /* @__PURE__ */ new Set();
@@ -9972,38 +9940,23 @@ function extractTextContent($) {
9972
9940
  return clone.text();
9973
9941
  }
9974
9942
  function checkTemplateVariables(html) {
9975
- if (!html || !html.trim()) {
9976
- return { unresolvedCount: 0, issues: [] };
9977
- }
9978
- if (html.length > MAX_HTML_SIZE) {
9979
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
9980
- }
9981
- const $ = cheerio11.load(html);
9982
- return checkTemplateVariablesFromDom($);
9943
+ return fromHtml(html, EMPTY_TEMPLATE, checkTemplateVariablesFromDom);
9983
9944
  }
9984
9945
 
9985
9946
  // src/audit.ts
9986
- import * as cheerio12 from "cheerio";
9987
- function auditEmail(html, options) {
9947
+ var EMPTY_AUDIT = {
9948
+ compatibility: { warnings: [], scores: {} },
9949
+ spam: EMPTY_SPAM,
9950
+ links: EMPTY_LINKS,
9951
+ accessibility: EMPTY_ACCESSIBILITY,
9952
+ images: EMPTY_IMAGES,
9953
+ inboxPreview: EMPTY_INBOX_PREVIEW,
9954
+ size: EMPTY_SIZE,
9955
+ templateVariables: EMPTY_TEMPLATE
9956
+ };
9957
+ function runAudit($, html, framework, options) {
9988
9958
  var _a;
9989
- if (!html || !html.trim()) {
9990
- return {
9991
- compatibility: { warnings: [], scores: {} },
9992
- spam: EMPTY_SPAM,
9993
- links: EMPTY_LINKS,
9994
- accessibility: EMPTY_ACCESSIBILITY,
9995
- images: EMPTY_IMAGES,
9996
- inboxPreview: EMPTY_INBOX_PREVIEW,
9997
- size: EMPTY_SIZE,
9998
- templateVariables: EMPTY_TEMPLATE
9999
- };
10000
- }
10001
- if (html.length > MAX_HTML_SIZE) {
10002
- throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
10003
- }
10004
- const framework = options == null ? void 0 : options.framework;
10005
9959
  const skip = new Set((_a = options == null ? void 0 : options.skip) != null ? _a : []);
10006
- const $ = cheerio12.load(html);
10007
9960
  const warnings = skip.has("compatibility") ? [] : analyzeEmailFromDom($, framework);
10008
9961
  const scores = skip.has("compatibility") ? {} : generateCompatibilityScore(warnings);
10009
9962
  const spam = skip.has("spam") ? EMPTY_SPAM : analyzeSpamFromDom($, options == null ? void 0 : options.spam);
@@ -10015,11 +9968,14 @@ function auditEmail(html, options) {
10015
9968
  const templateVariables = skip.has("templateVariables") ? EMPTY_TEMPLATE : checkTemplateVariablesFromDom($);
10016
9969
  return { compatibility: { warnings, scores }, spam, links, accessibility, images, inboxPreview, size, templateVariables };
10017
9970
  }
9971
+ function auditEmail(html, options) {
9972
+ return fromHtml(html, EMPTY_AUDIT, ($, h) => runAudit($, h, options == null ? void 0 : options.framework, options));
9973
+ }
10018
9974
 
10019
9975
  // src/plain-text.ts
10020
- import * as cheerio13 from "cheerio";
9976
+ import * as cheerio6 from "cheerio";
10021
9977
  function toPlainText(html) {
10022
- const $ = cheerio13.load(html);
9978
+ const $ = cheerio6.load(html);
10023
9979
  $("style, script, head").remove();
10024
9980
  $("[data-skip-in-text='true']").remove();
10025
9981
  const lines = [];
@@ -10121,23 +10077,14 @@ function toPlainText(html) {
10121
10077
  }
10122
10078
 
10123
10079
  // src/session.ts
10124
- import * as cheerio14 from "cheerio";
10080
+ import * as cheerio7 from "cheerio";
10125
10081
  function createSession(html, options) {
10126
10082
  if (!html || !html.trim()) {
10127
10083
  const fw = options == null ? void 0 : options.framework;
10128
10084
  return {
10129
10085
  html: html || "",
10130
10086
  framework: fw,
10131
- audit: () => ({
10132
- compatibility: { warnings: [], scores: {} },
10133
- spam: EMPTY_SPAM,
10134
- links: EMPTY_LINKS,
10135
- accessibility: EMPTY_ACCESSIBILITY,
10136
- images: EMPTY_IMAGES,
10137
- inboxPreview: EMPTY_INBOX_PREVIEW,
10138
- size: EMPTY_SIZE,
10139
- templateVariables: EMPTY_TEMPLATE
10140
- }),
10087
+ audit: () => EMPTY_AUDIT,
10141
10088
  analyze: () => [],
10142
10089
  score: () => ({}),
10143
10090
  analyzeSpam: () => EMPTY_SPAM,
@@ -10155,24 +10102,13 @@ function createSession(html, options) {
10155
10102
  if (html.length > MAX_HTML_SIZE) {
10156
10103
  throw new Error(`HTML input exceeds ${MAX_HTML_SIZE / 1024}KB limit.`);
10157
10104
  }
10158
- const $ = cheerio14.load(html);
10105
+ const $ = cheerio7.load(html);
10159
10106
  const framework = options == null ? void 0 : options.framework;
10160
10107
  return {
10161
10108
  html,
10162
10109
  framework,
10163
10110
  audit(opts) {
10164
- var _a;
10165
- const skip = new Set((_a = opts == null ? void 0 : opts.skip) != null ? _a : []);
10166
- const warnings = skip.has("compatibility") ? [] : analyzeEmailFromDom($, framework);
10167
- const scores = skip.has("compatibility") ? {} : generateCompatibilityScore(warnings);
10168
- const spam = skip.has("spam") ? EMPTY_SPAM : analyzeSpamFromDom($, opts == null ? void 0 : opts.spam);
10169
- const links = skip.has("links") ? EMPTY_LINKS : validateLinksFromDom($);
10170
- const accessibility = skip.has("accessibility") ? EMPTY_ACCESSIBILITY : checkAccessibilityFromDom($);
10171
- const images = skip.has("images") ? EMPTY_IMAGES : analyzeImagesFromDom($);
10172
- const inboxPreview = skip.has("inboxPreview") ? EMPTY_INBOX_PREVIEW : extractInboxPreviewFromDom($);
10173
- const size = skip.has("size") ? EMPTY_SIZE : checkSizeFromDom($, html);
10174
- const templateVariables = skip.has("templateVariables") ? EMPTY_TEMPLATE : checkTemplateVariablesFromDom($);
10175
- return { compatibility: { warnings, scores }, spam, links, accessibility, images, inboxPreview, size, templateVariables };
10111
+ return runAudit($, html, framework, opts);
10176
10112
  },
10177
10113
  analyze() {
10178
10114
  return analyzeEmailFromDom($, framework);