Skip to content

fix(inbox): open relative Markdown links in attachments - #2363

Merged
backnotprop merged 7 commits into
backnotprop:mainfrom
utpalsinghdev:fix/inbox-relative-markdown-links
Oct 31, 2026
Merged

backnotprop merged 7 commits into
backnotprop:mainfrom
utpalsinghdev:fix/inbox-relative-markdown-links

Conversation

@utpalsinghdev

@utpalsinghdev utpalsinghdev commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Relative Markdown links in Inbox attachments currently navigate to the server root instead of opening the linked file.

This change routes .md and .mdx links through the existing linked-document viewer. Links resolve relative to the current document, and unattached documents open read-only within the original attachment's folder. Nested links, fragments, Back, Escape and reload keep the thread open.

The server retains folder containment, hidden-file refusals, symlink checks, the 2 MB document limit and cross-origin guards. Images in linked Markdown resolve from that document's directory and must be referenced in its content. Existing HTML navigation remains unchanged.

Closes #2230.

Verification

  • bun test ./packages/server/inbox-attachments.test.ts ./packages/server/inbox-linked-page.test.ts ./packages/inbox/htmlLinks.test.ts
    • 17 passed.
  • DOM_TESTS=1 bun test ./packages/inbox/htmlLinks.test.tsx
    • 10 passed.
  • bun test ./packages/server/inbox-tailscale.test.ts
    • 24 passed.
  • bunx tsc --noEmit -p packages/inbox/tsconfig.json
  • bunx tsc --noEmit -p packages/server/tsconfig.json
  • bun run --cwd apps/inbox build
  • Real Mac Brave checks against the built Inbox UI: sibling and nested documents, fragments, linked images, Back/Escape, reload, full screen, missing files and out-of-folder refusals.

Docs

Updated the Inbox document-navigation guide and attachment API documentation.


Maintainer follow-up

Thanks @utpalsinghdev for this fix. Your commit is kept as you wrote it. On top of it:

  • Merged main in. There was one conflict, in AttachmentPane.tsx: the Contents gutter attribute from main and your ib-covered/inert sit on the same element now.
  • Linked Markdown images go through the existing markdown-image resolver (inboxMarkdownImageBase(id, version, document)), so the URL is written by inboxUrl like every other Inbox URL (tests/inbox-url-helper.test.ts).
  • The link resolvers passed to the Viewer stay the same across renders. Before, every pane render redrew each raw HTML block in the document (an open <details> closed). packages/inbox/markdownLinks.test.tsx guards this for the attached file and for a linked document.
  • A linked document is checked by where it leads as well as by its name. A link named alias.md that leads to data.json is refused (415), for /linked-page and for markdown-image?document=.
  • In a Markdown file, the note for a link that does not open no longer says images open from a link. They don't: a Markdown file has no asset route.
  • The attached file's Contents rail and button hide while a linked document covers it.
  • Each linked document opens at its own top. The attached file's remembered scroll position stays its own.
  • A fragment on the attached Markdown file scrolls once the file has been drawn.
  • New e2e test, tests/e2e/inbox-markdown-links.spec.ts. It covers:
    • a sibling and a nested doc opening, with the fragment and the linked image;
    • out-of-folder and hidden links being refused;
    • reload, and Back one document at a time, with the thread kept.

Not covered: linked machines and paired phones. /linked-page and markdown-image are not on the device door, as on main, so a relative Markdown link opens only for a thread on this machine, in the window. The message of commit c52ff4d says "(linked machines)". That is about how the URL is written, not about the feature working there.

utpalsinghdev and others added 7 commits October 30, 2026 06:21
# Conflicts:
#	packages/inbox/components/AttachmentPane.tsx
…under a linked doc, e2e

- LinkedMarkdown reads its images through the attachment's markdown-image
  route via inboxMarkdownImageBase(..., document), so the URL goes through
  inboxUrl (linked machines; tests/inbox-url-helper.test.ts).
- The attached file's Contents rail and button hide while a linked
  document covers it.
- A fragment on an attached Markdown file scrolls once the file is drawn.
- e2e: a relative .md link opens the linked doc; nested, out-of-folder,
  hidden, fragment, reload and Back.
… remembered scroll is its own

Review follow-ups: key LinkedMarkdown per stack entry as HtmlViewer is,
and scrollerOf skips the linked document's scroller.
…ecked by where it leads

- AttachmentPane and LinkedMarkdown pass a stable resolveLocalLink (and
  onOpenLink), so ui's HtmlBlock no longer redraws raw HTML blocks on every
  pane render. DOM test markdownLinks.test.tsx guards both documents.
- readInboxLinkedPage checks the realpath's extension too: alias.md leading
  to data.json is refused (415), for /linked-page and markdown-image.
- A Markdown file's refusal note no longer says images open from a link.
- server-and-storage.md: the markdown-image row keeps main's text first;
  document= ignores version.
@backnotprop backnotprop added the ci:full Run the heavy CI tier on this PR (added by the merge script) label Oct 31, 2026
@backnotprop
backnotprop merged commit fe98b1a into backnotprop:main Oct 31, 2026
91 of 93 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Run the heavy CI tier on this PR (added by the merge script)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Inbox: relative .md links in attachments navigate to the server root instead of opening the document

2 participants