@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.
@@ -4,12 +4,12 @@ var xmldom = require('@xmldom/xmldom');
4
4
  var xss = require('xss');
5
5
  var multihash = require('multihashes');
6
6
  var querystring = require('querystring');
7
+ var lruCache = require('lru-cache');
7
8
  var remarkable = require('remarkable');
8
9
  var linkify$1 = require('remarkable/linkify');
9
- var he2 = require('he');
10
10
  var htmlparser2 = require('htmlparser2');
11
11
  var domSerializerModule = require('dom-serializer');
12
- var lruCache = require('lru-cache');
12
+ var he = require('he');
13
13
 
14
14
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
15
 
@@ -34,9 +34,9 @@ function _interopNamespace(e) {
34
34
  var xss__default = /*#__PURE__*/_interopDefault(xss);
35
35
  var multihash__default = /*#__PURE__*/_interopDefault(multihash);
36
36
  var querystring__default = /*#__PURE__*/_interopDefault(querystring);
37
- var he2__default = /*#__PURE__*/_interopDefault(he2);
38
37
  var htmlparser2__namespace = /*#__PURE__*/_interopNamespace(htmlparser2);
39
38
  var domSerializerModule__namespace = /*#__PURE__*/_interopNamespace(domSerializerModule);
39
+ var he__default = /*#__PURE__*/_interopDefault(he);
40
40
 
41
41
  // src/consts/white-list.const.ts
42
42
  var WHITE_LIST = [
@@ -197,16 +197,13 @@ var ALLOWED_ATTRIBUTES = {
197
197
  "del": [],
198
198
  "ins": []
199
199
  };
200
- var hasDOMParser = typeof globalThis.DOMParser !== "undefined";
201
- var hasXMLSerializer = typeof globalThis.XMLSerializer !== "undefined";
202
- var lenientErrorHandler = (level, msg, _context) => {
203
- if (process.env.NODE_ENV === "development") {
204
- console.warn("[DOMParser]", level, msg);
205
- }
206
- return void 0;
207
- };
208
- var DOMParser = hasDOMParser ? new globalThis.DOMParser() : new xmldom.DOMParser({ onError: lenientErrorHandler });
209
- var XMLSerializer = hasXMLSerializer ? globalThis.XMLSerializer : xmldom.XMLSerializer;
200
+ function createParser() {
201
+ return new xmldom.DOMParser({
202
+ onError(level, msg) {
203
+ }
204
+ });
205
+ }
206
+ var DOMParser = createParser();
210
207
 
211
208
  // src/helper.ts
212
209
  function removeDuplicateAttributes(html) {
@@ -287,7 +284,7 @@ function isValidUsername(username) {
287
284
 
288
285
  // src/methods/get-inner-html.method.ts
289
286
  function getSerializedInnerHTML(node) {
290
- const serializer = new XMLSerializer();
287
+ const serializer = new xmldom.XMLSerializer();
291
288
  if (node.childNodes[0]) {
292
289
  return serializer.serializeToString(node.childNodes[0]);
293
290
  }
@@ -328,6 +325,14 @@ function sanitizeHtml(html) {
328
325
  });
329
326
  }
330
327
  var proxyBase = "https://images.ecency.com";
328
+ var urlHashCache = new lruCache.LRUCache({ max: 500 });
329
+ function getUrlHash(url) {
330
+ const cached = urlHashCache.get(url);
331
+ if (cached) return cached;
332
+ const hash = multihash__default.default.toB58String(Buffer.from(url));
333
+ urlHashCache.set(url, hash);
334
+ return hash;
335
+ }
331
336
  function setProxyBase(p2) {
332
337
  proxyBase = p2;
333
338
  }
@@ -378,7 +383,7 @@ function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
378
383
  if (pHash) {
379
384
  return `${proxyBase}/p/${pHash}?${qs}`;
380
385
  }
381
- const b58url = multihash__default.default.toB58String(Buffer.from(realUrl.toString()));
386
+ const b58url = getUrlHash(realUrl.toString());
382
387
  return `${proxyBase}/p/${b58url}?${qs}`;
383
388
  }
384
389
  var SRCSET_WIDTHS = [320, 600, 800, 1024, 1280];
@@ -1587,7 +1592,7 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
1587
1592
  "sub",
1588
1593
  "sup"
1589
1594
  ]);
1590
- const serializer = new XMLSerializer();
1595
+ const serializer = new xmldom.XMLSerializer();
1591
1596
  if (!input) {
1592
1597
  return "";
1593
1598
  }
@@ -1622,8 +1627,7 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
1622
1627
  traverse(doc, forApp, 0, { firstImageFound: false }, parentDomain, seoContext, renderOptions);
1623
1628
  output = serializer.serializeToString(doc);
1624
1629
  } catch (fallbackError) {
1625
- const escapedContent = he2__default.default.encode(output || md.render(input));
1626
- output = `<p dir="auto">${escapedContent}</p>`;
1630
+ output = sanitizeHtml(output || md.render(input));
1627
1631
  }
1628
1632
  }
1629
1633
  if (forApp && output && entityPlaceholders.length > 0) {
@@ -1632,7 +1636,7 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
1632
1636
  output = output.split(placeholder).join(entity);
1633
1637
  });
1634
1638
  }
1635
- output = output.replace(/ xmlns="http:\/\/www.w3.org\/1999\/xhtml"/g, "").replace('<body id="root">', "").replace("</body>", "").trim();
1639
+ 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();
1636
1640
  return sanitizeHtml(output);
1637
1641
  }
1638
1642
  var mdInstance = null;
@@ -1651,7 +1655,7 @@ function simpleMarkdownToHTML(input) {
1651
1655
  const html = getMd().render(input);
1652
1656
  return sanitizeHtml(html);
1653
1657
  }
1654
- var cache = new lruCache.LRUCache({ max: 60 });
1658
+ var cache = new lruCache.LRUCache({ max: 500 });
1655
1659
  function setCacheSize(size) {
1656
1660
  cache = new lruCache.LRUCache({ max: size });
1657
1661
  }
@@ -1682,6 +1686,40 @@ var gifLinkRegex = /\.(gif)$/i;
1682
1686
  function isGifLink(link) {
1683
1687
  return gifLinkRegex.test(link);
1684
1688
  }
1689
+ var BACKTICK_FENCE_RE = /```[\s\S]*?```/g;
1690
+ var TILDE_FENCE_RE = /~~~[\s\S]*?~~~/g;
1691
+ var INLINE_CODE_RE = /`[^`\n]*`/g;
1692
+ var INDENTED_CODE_RE = /^(?: {4}|\t).+$/gm;
1693
+ var MD_IMAGE_RE = /!\[[^\]]*\]\(\s*([^)\s]+)(?:\s+["'][^"']*["'])?\s*\)/;
1694
+ var HTML_IMAGE_RE = /<img\b[^>]*?\bsrc\s*=\s*["']([^"']+)["']/i;
1695
+ var SAFE_URL_RE = /^https?:\/\//i;
1696
+ function findFirstImageUrl(body) {
1697
+ if (!body) return null;
1698
+ const cleaned = body.replace(BACKTICK_FENCE_RE, "").replace(TILDE_FENCE_RE, "").replace(INLINE_CODE_RE, "").replace(INDENTED_CODE_RE, "");
1699
+ const mdMatch = cleaned.match(MD_IMAGE_RE);
1700
+ const htmlMatch = cleaned.match(HTML_IMAGE_RE);
1701
+ if (mdMatch) {
1702
+ const url = mdMatch[1];
1703
+ if (!url || !SAFE_URL_RE.test(url) || url.includes("(")) {
1704
+ return null;
1705
+ }
1706
+ }
1707
+ const mdValid = !!mdMatch;
1708
+ const htmlValid = !!(htmlMatch && htmlMatch[1] && SAFE_URL_RE.test(htmlMatch[1]));
1709
+ if (mdValid && htmlValid) {
1710
+ return (mdMatch.index ?? 0) < (htmlMatch.index ?? 0) ? mdMatch[1] : htmlMatch[1];
1711
+ }
1712
+ if (mdValid) return mdMatch[1];
1713
+ if (htmlValid) return htmlMatch[1];
1714
+ return null;
1715
+ }
1716
+ function proxifyFound(src, width, height, format) {
1717
+ const decoded = he__default.default.decode(src);
1718
+ if (isGifLink(decoded)) {
1719
+ return proxifyImageSrc(decoded, 0, 0, format);
1720
+ }
1721
+ return proxifyImageSrc(decoded, width, height, format);
1722
+ }
1685
1723
  function getImage(entry, width = 0, height = 0, format = "match") {
1686
1724
  let meta;
1687
1725
  if (typeof entry.json_metadata === "object") {
@@ -1694,7 +1732,7 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1694
1732
  }
1695
1733
  }
1696
1734
  if (meta && typeof meta.image === "string" && meta.image.length > 0) {
1697
- const decodedImage = he2__default.default.decode(meta.image);
1735
+ const decodedImage = he__default.default.decode(meta.image);
1698
1736
  if (isGifLink(decodedImage)) {
1699
1737
  return proxifyImageSrc(decodedImage, 0, 0, format);
1700
1738
  }
@@ -1702,7 +1740,7 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1702
1740
  }
1703
1741
  if (meta && meta.image && !!meta.image.length && meta.image[0]) {
1704
1742
  if (typeof meta.image[0] === "string") {
1705
- const decodedImage = he2__default.default.decode(meta.image[0]);
1743
+ const decodedImage = he__default.default.decode(meta.image[0]);
1706
1744
  if (isGifLink(decodedImage)) {
1707
1745
  return proxifyImageSrc(decodedImage, 0, 0, format);
1708
1746
  }
@@ -1713,6 +1751,10 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1713
1751
  }
1714
1752
  return proxifyImageSrc(meta.image[0], width, height, format);
1715
1753
  }
1754
+ const fast = findFirstImageUrl(entry.body);
1755
+ if (fast) {
1756
+ return proxifyFound(fast, width, height, format);
1757
+ }
1716
1758
  const html = markdown2Html(entry);
1717
1759
  const doc = createDoc(html);
1718
1760
  if (!doc) {
@@ -1724,16 +1766,16 @@ function getImage(entry, width = 0, height = 0, format = "match") {
1724
1766
  if (!src) {
1725
1767
  return null;
1726
1768
  }
1727
- const decodedSrc = he2__default.default.decode(src);
1728
- if (isGifLink(decodedSrc)) {
1729
- return proxifyImageSrc(decodedSrc, 0, 0, format);
1730
- }
1731
- return proxifyImageSrc(decodedSrc, width, height, format);
1769
+ return proxifyFound(src, width, height, format);
1732
1770
  }
1733
1771
  return null;
1734
1772
  }
1735
1773
  function catchPostImage(obj, width = 0, height = 0, format = "match") {
1736
1774
  if (typeof obj === "string") {
1775
+ const fast = findFirstImageUrl(obj);
1776
+ if (fast) {
1777
+ return proxifyFound(fast, width, height, format);
1778
+ }
1737
1779
  const html = markdown2Html(obj);
1738
1780
  const doc = createDoc(html);
1739
1781
  if (!doc) {
@@ -1745,11 +1787,7 @@ function catchPostImage(obj, width = 0, height = 0, format = "match") {
1745
1787
  if (!src) {
1746
1788
  return null;
1747
1789
  }
1748
- const decodedSrc = he2__default.default.decode(src);
1749
- if (isGifLink(decodedSrc)) {
1750
- return proxifyImageSrc(decodedSrc, 0, 0, format);
1751
- }
1752
- return proxifyImageSrc(decodedSrc, width, height, format);
1790
+ return proxifyFound(src, width, height, format);
1753
1791
  }
1754
1792
  return null;
1755
1793
  }
@@ -1762,6 +1800,20 @@ function catchPostImage(obj, width = 0, height = 0, format = "match") {
1762
1800
  cacheSet(key, res);
1763
1801
  return res;
1764
1802
  }
1803
+ var summaryRenderer = new remarkable.Remarkable({
1804
+ html: true,
1805
+ breaks: true,
1806
+ typographer: false
1807
+ });
1808
+ summaryRenderer.core.ruler.enable(["abbr"]);
1809
+ summaryRenderer.block.ruler.enable(["footnote", "deflist"]);
1810
+ summaryRenderer.inline.ruler.enable([
1811
+ "footnote_inline",
1812
+ "ins",
1813
+ "mark",
1814
+ "sub",
1815
+ "sup"
1816
+ ]);
1765
1817
  var joint = (arr, limit = 200) => {
1766
1818
  let result = "";
1767
1819
  if (arr) {
@@ -1787,25 +1839,6 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
1787
1839
  return "";
1788
1840
  }
1789
1841
  entryBody = cleanReply(entryBody);
1790
- const mdd = new remarkable.Remarkable({
1791
- html: true,
1792
- breaks: true,
1793
- typographer: false
1794
- }).use(linkify$1.linkify);
1795
- mdd.core.ruler.enable([
1796
- "abbr"
1797
- ]);
1798
- mdd.block.ruler.enable([
1799
- "footnote",
1800
- "deflist"
1801
- ]);
1802
- mdd.inline.ruler.enable([
1803
- "footnote_inline",
1804
- "ins",
1805
- "mark",
1806
- "sub",
1807
- "sup"
1808
- ]);
1809
1842
  const entities = entryBody.match(ENTITY_REGEX);
1810
1843
  const entityPlaceholders = [];
1811
1844
  if (entities && platform !== "web") {
@@ -1818,7 +1851,7 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
1818
1851
  }
1819
1852
  let text2 = "";
1820
1853
  try {
1821
- text2 = mdd.render(entryBody);
1854
+ text2 = summaryRenderer.render(entryBody);
1822
1855
  } catch (err) {
1823
1856
  console.error("[postBodySummary] Failed to render markdown:", {
1824
1857
  error: err instanceof Error ? err.message : String(err),
@@ -1838,7 +1871,7 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
1838
1871
  text2 = joint(text2.split(" "), length);
1839
1872
  }
1840
1873
  if (text2) {
1841
- text2 = he2__default.default.decode(text2);
1874
+ text2 = he__default.default.decode(text2);
1842
1875
  }
1843
1876
  return text2;
1844
1877
  }