ework-web 0.10.121 → 0.10.122

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/fileview.ts +21 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ework-web",
3
- "version": "0.10.121",
3
+ "version": "0.10.122",
4
4
  "type": "module",
5
5
  "description": "ework-web — standalone multi-project issue tracker. Local SQLite-backed, no external API dependency. Bun + TypeScript + SSR HTML.",
6
6
  "license": "MIT",
package/src/fileview.ts CHANGED
@@ -472,17 +472,29 @@ function buildDownloadView(cfg: Config, rp: string): { html: string } {
472
472
  return { html };
473
473
  }
474
474
 
475
- export // Repo-relative refs (figures/x.png) in /file-rendered markdown 404 against /file;
476
- // rewritten targets re-pass the allowlist+denylist gate at request time.
477
- const REL_REF_RE = /(\s(?:src|href)=")([^"]+)(")/g;
475
+ export // Repo-relative refs (figures/x.png) in /file-rendered markdown 404 against /file
476
+ // (and DOMPurify strips relative src entirely); rewriting at markdown-source level
477
+ // yields rooted /file URLs that survive sanitization and re-pass the gate at request time.
478
+ const MD_REF_RE = /(\]\()([^)\s]+)([)\s])/g;
478
479
  const SKIP_REF_RE = /^(?:[a-z][a-z0-9+.-]*:|\/|#)/i;
479
480
 
480
- export function rewriteRelativeRefs(html: string, dir: string): string {
481
- return html.replace(REL_REF_RE, (full: string, pre: string, ref: string, post: string) => {
482
- if (SKIP_REF_RE.test(ref)) return full;
481
+ export function rewriteRelativeMdRefs(md: string, dir: string): string {
482
+ let out = "";
483
+ let last = 0;
484
+ for (const m of md.matchAll(/^(```|~~~)[^\n]*\n[\s\S]*?^\1[^\n]*$/gm)) {
485
+ out += rewriteRefs(md.slice(last, m.index!), dir) + m[0];
486
+ last = m.index! + m[0].length;
487
+ }
488
+ return out + rewriteRefs(md.slice(last), dir);
489
+ }
490
+
491
+ function rewriteRefs(text: string, dir: string): string {
492
+ return text.replace(MD_REF_RE, (full: string, pre: string, ref: string, post: string) => {
493
+ if (SKIP_REF_RE.test(ref) || ref.startsWith("/file")) return full;
483
494
  const abs = resolve(dir, ref);
484
- const q = encodeURIComponent(abs);
485
- return pre + (pre.includes("src") ? `/file/raw?path=${q}` : `/file?path=${q}`) + post;
495
+ const media = /\.(?:png|jpe?g|gif|webp|bmp|svg|mp3|mp4|webm|ogg|wav|pdf)$/i.test(abs);
496
+ const url = `${media ? "/file/raw" : "/file"}?path=${encodeURIComponent(abs)}`;
497
+ return `${pre}${url}${post}`;
486
498
  });
487
499
  }
488
500
 
@@ -521,7 +533,7 @@ export function buildFileView(
521
533
  const fullText = chunk.rows.map((r) => r.t).join("\n");
522
534
  const dir = dirname(rawPath);
523
535
  const body = mdRender
524
- ? `<div class="md-render">${rewriteRelativeRefs(renderMarkdown(fullText, dir), dir)}</div>`
536
+ ? `<div class="md-render">${renderMarkdown(rewriteRelativeMdRefs(fullText, dir), dir)}</div>`
525
537
  : lang && shownBytes <= 100000
526
538
  ? renderHighlighted(chunk, lang)
527
539
  : `<pre><code>${chunk.rows.map((r) => lineRow(r.t, r.n)).join("")}</code></pre>`;