@ecency/render-helper 2.4.32 → 2.4.34

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.
@@ -1,13 +1,13 @@
1
- import { DOMParser as DOMParser$1, XMLSerializer as XMLSerializer$1 } from '@xmldom/xmldom';
1
+ import { DOMParser as DOMParser$1, XMLSerializer } from '@xmldom/xmldom';
2
2
  import xss from 'xss';
3
3
  import multihash from 'multihashes';
4
4
  import querystring from 'querystring';
5
+ import { LRUCache } from 'lru-cache';
5
6
  import { Remarkable } from 'remarkable';
6
7
  import { linkify as linkify$1 } from 'remarkable/linkify';
7
- import he2 from 'he';
8
8
  import * as htmlparser2 from 'htmlparser2';
9
9
  import * as domSerializerModule from 'dom-serializer';
10
- import { LRUCache } from 'lru-cache';
10
+ import he from 'he';
11
11
 
12
12
  // src/consts/white-list.const.ts
13
13
  var WHITE_LIST = [
@@ -168,13 +168,13 @@ var ALLOWED_ATTRIBUTES = {
168
168
  "del": [],
169
169
  "ins": []
170
170
  };
171
- var hasDOMParser = typeof globalThis.DOMParser !== "undefined";
172
- var hasXMLSerializer = typeof globalThis.XMLSerializer !== "undefined";
173
- var lenientErrorHandler = (level, msg, _context) => {
174
- return void 0;
175
- };
176
- var DOMParser = hasDOMParser ? new globalThis.DOMParser() : new DOMParser$1({ onError: lenientErrorHandler });
177
- var XMLSerializer = hasXMLSerializer ? globalThis.XMLSerializer : XMLSerializer$1;
171
+ function createParser() {
172
+ return new DOMParser$1({
173
+ onError(level, msg) {
174
+ }
175
+ });
176
+ }
177
+ var DOMParser = createParser();
178
178
 
179
179
  // src/helper.ts
180
180
  function removeDuplicateAttributes(html) {
@@ -296,6 +296,14 @@ function sanitizeHtml(html) {
296
296
  });
297
297
  }
298
298
  var proxyBase = "https://images.ecency.com";
299
+ var urlHashCache = new LRUCache({ max: 500 });
300
+ function getUrlHash(url) {
301
+ const cached = urlHashCache.get(url);
302
+ if (cached) return cached;
303
+ const hash = multihash.toB58String(Buffer.from(url));
304
+ urlHashCache.set(url, hash);
305
+ return hash;
306
+ }
299
307
  function setProxyBase(p2) {
300
308
  proxyBase = p2;
301
309
  }
@@ -346,7 +354,7 @@ function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
346
354
  if (pHash) {
347
355
  return `${proxyBase}/p/${pHash}?${qs}`;
348
356
  }
349
- const b58url = multihash.toB58String(Buffer.from(realUrl.toString()));
357
+ const b58url = getUrlHash(realUrl.toString());
350
358
  return `${proxyBase}/p/${b58url}?${qs}`;
351
359
  }
352
360
  var SRCSET_WIDTHS = [320, 600, 800, 1024, 1280];
@@ -1590,8 +1598,7 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
1590
1598
  traverse(doc, forApp, 0, { firstImageFound: false }, parentDomain, seoContext, renderOptions);
1591
1599
  output = serializer.serializeToString(doc);
1592
1600
  } catch (fallbackError) {
1593
- const escapedContent = he2.encode(output || md.render(input));
1594
- output = `<p dir="auto">${escapedContent}</p>`;
1601
+ output = sanitizeHtml(output || md.render(input));
1595
1602
  }
1596
1603
  }
1597
1604
  if (forApp && output && entityPlaceholders.length > 0) {
@@ -1600,7 +1607,7 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
1600
1607
  output = output.split(placeholder).join(entity);
1601
1608
  });
1602
1609
  }
1603
- output = output.replace(/ xmlns="http:\/\/www.w3.org\/1999\/xhtml"/g, "").replace('<body id="root">', "").replace("</body>", "").trim();
1610
+ output = output.replace(/ xmlns="http:\/\/www.w3.org\/1999\/xhtml"/g, "").replace(/^<\?xml[^?]*\?>/, "").replace(/^<!DOCTYPE[^>]*>/i, "").replace(/<\/?html[^>]*>/g, "").replace(/<head[^>]*>[\s\S]*?<\/head>/g, "").replace('<body id="root">', "").replace("</body>", "").trim();
1604
1611
  return sanitizeHtml(output);
1605
1612
  }
1606
1613
  var mdInstance = null;
@@ -1619,7 +1626,7 @@ function simpleMarkdownToHTML(input) {
1619
1626
  const html = getMd().render(input);
1620
1627
  return sanitizeHtml(html);
1621
1628
  }
1622
- var cache = new LRUCache({ max: 60 });
1629
+ var cache = new LRUCache({ max: 500 });
1623
1630
  function setCacheSize(size) {
1624
1631
  cache = new LRUCache({ max: size });
1625
1632
  }
@@ -1650,6 +1657,40 @@ var gifLinkRegex = /\.(gif)$/i;
1650
1657
  function isGifLink(link) {
1651
1658
  return gifLinkRegex.test(link);
1652
1659
  }
1660
+ var BACKTICK_FENCE_RE = /```[\s\S]*?```/g;
1661
+ var TILDE_FENCE_RE = /~~~[\s\S]*?~~~/g;
1662
+ var INLINE_CODE_RE = /`[^`\n]*`/g;
1663
+ var INDENTED_CODE_RE = /^(?: {4}|\t).+$/gm;
1664
+ var MD_IMAGE_RE = /!\[[^\]]*\]\(\s*([^)\s]+)(?:\s+["'][^"']*["'])?\s*\)/;
1665
+ var HTML_IMAGE_RE = /<img\b[^>]*?\bsrc\s*=\s*["']([^"']+)["']/i;
1666
+ var SAFE_URL_RE = /^https?:\/\//i;
1667
+ function findFirstImageUrl(body) {
1668
+ if (!body) return null;
1669
+ const cleaned = body.replace(BACKTICK_FENCE_RE, "").replace(TILDE_FENCE_RE, "").replace(INLINE_CODE_RE, "").replace(INDENTED_CODE_RE, "");
1670
+ const mdMatch = cleaned.match(MD_IMAGE_RE);
1671
+ const htmlMatch = cleaned.match(HTML_IMAGE_RE);
1672
+ if (mdMatch) {
1673
+ const url = mdMatch[1];
1674
+ if (!url || !SAFE_URL_RE.test(url) || url.includes("(")) {
1675
+ return null;
1676
+ }
1677
+ }
1678
+ const mdValid = !!mdMatch;
1679
+ const htmlValid = !!(htmlMatch && htmlMatch[1] && SAFE_URL_RE.test(htmlMatch[1]));
1680
+ if (mdValid && htmlValid) {
1681
+ return (mdMatch.index ?? 0) < (htmlMatch.index ?? 0) ? mdMatch[1] : htmlMatch[1];
1682
+ }
1683
+ if (mdValid) return mdMatch[1];
1684
+ if (htmlValid) return htmlMatch[1];
1685
+ return null;
1686
+ }
1687
+ function proxifyFound(src, width, height, format) {
1688
+ const decoded = he.decode(src);
1689
+ if (isGifLink(decoded)) {
1690
+ return proxifyImageSrc(decoded, 0, 0, format);
1691
+ }
1692
+ return proxifyImageSrc(decoded, width, height, format);
1693
+ }
1653
1694
  function getImage(entry, width = 0, height = 0, format = "match") {
1654
1695
  let meta;
1655
1696
  if (typeof entry.json_metadata === "object") {
@@ -1662,7 +1703,7 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1662
1703
  }
1663
1704
  }
1664
1705
  if (meta && typeof meta.image === "string" && meta.image.length > 0) {
1665
- const decodedImage = he2.decode(meta.image);
1706
+ const decodedImage = he.decode(meta.image);
1666
1707
  if (isGifLink(decodedImage)) {
1667
1708
  return proxifyImageSrc(decodedImage, 0, 0, format);
1668
1709
  }
@@ -1670,7 +1711,7 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1670
1711
  }
1671
1712
  if (meta && meta.image && !!meta.image.length && meta.image[0]) {
1672
1713
  if (typeof meta.image[0] === "string") {
1673
- const decodedImage = he2.decode(meta.image[0]);
1714
+ const decodedImage = he.decode(meta.image[0]);
1674
1715
  if (isGifLink(decodedImage)) {
1675
1716
  return proxifyImageSrc(decodedImage, 0, 0, format);
1676
1717
  }
@@ -1681,6 +1722,10 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1681
1722
  }
1682
1723
  return proxifyImageSrc(meta.image[0], width, height, format);
1683
1724
  }
1725
+ const fast = findFirstImageUrl(entry.body);
1726
+ if (fast) {
1727
+ return proxifyFound(fast, width, height, format);
1728
+ }
1684
1729
  const html = markdown2Html(entry);
1685
1730
  const doc = createDoc(html);
1686
1731
  if (!doc) {
@@ -1692,16 +1737,16 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1692
1737
  if (!src) {
1693
1738
  return null;
1694
1739
  }
1695
- const decodedSrc = he2.decode(src);
1696
- if (isGifLink(decodedSrc)) {
1697
- return proxifyImageSrc(decodedSrc, 0, 0, format);
1698
- }
1699
- return proxifyImageSrc(decodedSrc, width, height, format);
1740
+ return proxifyFound(src, width, height, format);
1700
1741
  }
1701
1742
  return null;
1702
1743
  }
1703
1744
  function catchPostImage(obj, width = 0, height = 0, format = "match") {
1704
1745
  if (typeof obj === "string") {
1746
+ const fast = findFirstImageUrl(obj);
1747
+ if (fast) {
1748
+ return proxifyFound(fast, width, height, format);
1749
+ }
1705
1750
  const html = markdown2Html(obj);
1706
1751
  const doc = createDoc(html);
1707
1752
  if (!doc) {
@@ -1713,11 +1758,7 @@ function catchPostImage(obj, width = 0, height = 0, format = "match") {
1713
1758
  if (!src) {
1714
1759
  return null;
1715
1760
  }
1716
- const decodedSrc = he2.decode(src);
1717
- if (isGifLink(decodedSrc)) {
1718
- return proxifyImageSrc(decodedSrc, 0, 0, format);
1719
- }
1720
- return proxifyImageSrc(decodedSrc, width, height, format);
1761
+ return proxifyFound(src, width, height, format);
1721
1762
  }
1722
1763
  return null;
1723
1764
  }
@@ -1730,6 +1771,20 @@ function catchPostImage(obj, width = 0, height = 0, format = "match") {
1730
1771
  cacheSet(key, res);
1731
1772
  return res;
1732
1773
  }
1774
+ var summaryRenderer = new Remarkable({
1775
+ html: true,
1776
+ breaks: true,
1777
+ typographer: false
1778
+ });
1779
+ summaryRenderer.core.ruler.enable(["abbr"]);
1780
+ summaryRenderer.block.ruler.enable(["footnote", "deflist"]);
1781
+ summaryRenderer.inline.ruler.enable([
1782
+ "footnote_inline",
1783
+ "ins",
1784
+ "mark",
1785
+ "sub",
1786
+ "sup"
1787
+ ]);
1733
1788
  var joint = (arr, limit = 200) => {
1734
1789
  let result = "";
1735
1790
  if (arr) {
@@ -1755,25 +1810,6 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
1755
1810
  return "";
1756
1811
  }
1757
1812
  entryBody = cleanReply(entryBody);
1758
- const mdd = new Remarkable({
1759
- html: true,
1760
- breaks: true,
1761
- typographer: false
1762
- }).use(linkify$1);
1763
- mdd.core.ruler.enable([
1764
- "abbr"
1765
- ]);
1766
- mdd.block.ruler.enable([
1767
- "footnote",
1768
- "deflist"
1769
- ]);
1770
- mdd.inline.ruler.enable([
1771
- "footnote_inline",
1772
- "ins",
1773
- "mark",
1774
- "sub",
1775
- "sup"
1776
- ]);
1777
1813
  const entities = entryBody.match(ENTITY_REGEX);
1778
1814
  const entityPlaceholders = [];
1779
1815
  if (entities && platform !== "web") {
@@ -1786,7 +1822,7 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
1786
1822
  }
1787
1823
  let text2 = "";
1788
1824
  try {
1789
- text2 = mdd.render(entryBody);
1825
+ text2 = summaryRenderer.render(entryBody);
1790
1826
  } catch (err) {
1791
1827
  console.error("[postBodySummary] Failed to render markdown:", {
1792
1828
  error: err instanceof Error ? err.message : String(err),
@@ -1806,7 +1842,7 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
1806
1842
  text2 = joint(text2.split(" "), length);
1807
1843
  }
1808
1844
  if (text2) {
1809
- text2 = he2.decode(text2);
1845
+ text2 = he.decode(text2);
1810
1846
  }
1811
1847
  return text2;
1812
1848
  }