@ecency/render-helper 2.4.30 → 2.4.31

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.
@@ -54,6 +54,11 @@ declare function setProxyBase(p: string): void;
54
54
  * @param _format - @deprecated Ignored. Always uses 'match' — format is handled server-side via Accept header.
55
55
  */
56
56
  declare function proxifyImageSrc(url?: string, width?: number, height?: number, _format?: string): string;
57
+ /**
58
+ * Builds a srcset string with multiple width variants for responsive images.
59
+ * Uses the image proxy's width parameter to serve appropriately sized images.
60
+ */
61
+ declare function buildSrcSet(url?: string): string;
57
62
 
58
63
  declare function setCacheSize(size: number): void;
59
64
 
@@ -71,4 +76,4 @@ declare function isValidPermlink(permlink: string): boolean;
71
76
  */
72
77
  declare function simpleMarkdownToHTML(input: string): string;
73
78
 
74
- export { type Entry, type RenderOptions, SECTION_LIST, type SeoContext, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
79
+ export { type Entry, type RenderOptions, SECTION_LIST, type SeoContext, buildSrcSet, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
@@ -123,6 +123,8 @@ var ALLOWED_ATTRIBUTES = {
123
123
  ],
124
124
  "img": [
125
125
  "src",
126
+ "srcset",
127
+ "sizes",
126
128
  "alt",
127
129
  "class",
128
130
  "loading",
@@ -278,6 +280,10 @@ function sanitizeHtml(html) {
278
280
  const decodedLower = decoded.toLowerCase();
279
281
  if (name.startsWith("on")) return "";
280
282
  if (tag === "img" && name === "src" && (!/^https?:\/\//.test(decodedLower) || decodedLower.startsWith("javascript:"))) return "";
283
+ if (tag === "img" && name === "srcset") {
284
+ const candidates = decoded.split(",").map((c) => c.trim().split(/\s+/)[0]);
285
+ if (candidates.some((url) => !/^https?:\/\//.test(url))) return "";
286
+ }
281
287
  if (tag === "video" && ["src", "poster"].includes(name) && (!/^https?:\/\//.test(decodedLower) || decodedLower.startsWith("javascript:"))) return "";
282
288
  if (tag === "img" && ["dynsrc", "lowsrc"].includes(name)) return "";
283
289
  if (tag === "span" && name === "class" && decoded.toLowerCase().trim() === "wr") return "";
@@ -292,6 +298,9 @@ var proxyBase = "https://images.ecency.com";
292
298
  function setProxyBase(p2) {
293
299
  proxyBase = p2;
294
300
  }
301
+ function getProxyBase() {
302
+ return proxyBase;
303
+ }
295
304
  function extractPHash(url) {
296
305
  if (url.startsWith(`${proxyBase}/p/`)) {
297
306
  const [hash] = url.split("/p/")[1].split("?");
@@ -339,8 +348,24 @@ function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
339
348
  const b58url = multihash.toB58String(Buffer.from(realUrl.toString()));
340
349
  return `${proxyBase}/p/${b58url}?${qs}`;
341
350
  }
351
+ var SRCSET_WIDTHS = [320, 600, 800, 1024, 1280];
352
+ function buildSrcSet(url) {
353
+ if (!url || typeof url !== "string") return "";
354
+ const escapedBase = proxyBase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
355
+ const proxyPattern = new RegExp(`^${escapedBase}/p/([^?]+)`);
356
+ const match = url.match(proxyPattern);
357
+ if (match) {
358
+ const phash = extractPHash(url) || match[1];
359
+ return SRCSET_WIDTHS.map((w) => `${proxyBase}/p/${phash}?format=match&mode=fit&width=${w} ${w}w`).join(", ");
360
+ }
361
+ return SRCSET_WIDTHS.map((w) => {
362
+ const proxied = proxifyImageSrc(url, w);
363
+ return proxied ? `${proxied} ${w}w` : "";
364
+ }).filter(Boolean).join(", ");
365
+ }
342
366
 
343
367
  // src/methods/img.method.ts
368
+ var IMAGE_SIZES = "(max-width: 768px) 100vw, 700px";
344
369
  function img(el, state) {
345
370
  const src = el.getAttribute("src") || "";
346
371
  const decodedSrc = decodeURIComponent(
@@ -350,11 +375,15 @@ function img(el, state) {
350
375
  const isInvalid = !src || decodedSrc.startsWith("javascript") || decodedSrc.startsWith("vbscript") || decodedSrc === "x";
351
376
  if (isInvalid) {
352
377
  el.removeAttribute("src");
378
+ el.removeAttribute("srcset");
379
+ el.removeAttribute("sizes");
353
380
  return;
354
381
  }
355
382
  const isRelative = !/^https?:\/\//i.test(decodedSrc) && !decodedSrc.startsWith("/");
356
383
  if (isRelative) {
357
384
  el.removeAttribute("src");
385
+ el.removeAttribute("srcset");
386
+ el.removeAttribute("sizes");
358
387
  return;
359
388
  }
360
389
  el.setAttribute("itemprop", "image");
@@ -369,22 +398,41 @@ function img(el, state) {
369
398
  }
370
399
  const cls = el.getAttribute("class") || "";
371
400
  const shouldReplace = !cls.includes("no-replace");
372
- const hasAlreadyProxied = src.startsWith("https://images.ecency.com/p/") || src.startsWith("https://images.ecency.com/u/") || /^https:\/\/images\.ecency\.com\/\d+x\d+\//.test(src);
401
+ const base = getProxyBase().replace(/\/+$/, "");
402
+ const hasAlreadyProxied = src.startsWith(`${base}/p/`) || src.startsWith(`${base}/u/`) || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/\\d+x\\d+/`).test(src);
373
403
  if (shouldReplace && !hasAlreadyProxied) {
374
404
  const proxified = proxifyImageSrc(decodedSrc);
375
405
  if (proxified) {
376
406
  el.setAttribute("src", proxified);
407
+ const srcset = buildSrcSet(decodedSrc);
408
+ if (srcset) {
409
+ el.setAttribute("srcset", srcset);
410
+ el.setAttribute("sizes", IMAGE_SIZES);
411
+ }
412
+ }
413
+ } else if (shouldReplace && hasAlreadyProxied) {
414
+ if (src.startsWith(`${base}/p/`)) {
415
+ const srcset = buildSrcSet(src);
416
+ if (srcset) {
417
+ el.setAttribute("srcset", srcset);
418
+ el.setAttribute("sizes", IMAGE_SIZES);
419
+ }
377
420
  }
378
421
  }
379
422
  }
380
423
  function createImageHTML(src, isLCP) {
381
424
  const proxified = proxifyImageSrc(src);
382
425
  if (!proxified) return "";
426
+ const base = getProxyBase().replace(/\/+$/, "");
427
+ const isAlreadyProxied = src.startsWith(`${base}/u/`) || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/\\d+x\\d+/`).test(src);
428
+ const srcset = isAlreadyProxied ? "" : buildSrcSet(src);
383
429
  const loading = isLCP ? "eager" : "lazy";
384
430
  const fetch = isLCP ? 'fetchpriority="high"' : 'decoding="async"';
431
+ const srcsetAttr = srcset ? `srcset="${srcset}" sizes="${IMAGE_SIZES}"` : "";
385
432
  return `<img
386
433
  class="markdown-img-link"
387
434
  src="${proxified}"
435
+ ${srcsetAttr}
388
436
  loading="${loading}"
389
437
  ${fetch}
390
438
  itemprop="image"
@@ -1777,6 +1825,6 @@ function getPostBodySummary(obj, length, platform) {
1777
1825
  return res;
1778
1826
  }
1779
1827
 
1780
- export { SECTION_LIST, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
1828
+ export { SECTION_LIST, buildSrcSet, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
1781
1829
  //# sourceMappingURL=index.js.map
1782
1830
  //# sourceMappingURL=index.js.map