Skip to content

Support MySTRA Viewer embedding in article and book themes - #16

Merged
EiffL merged 5 commits into
mainfrom
feat/mystra-embedding
Sep 10, 2026
Merged

EiffL merged 5 commits into
mainfrom
feat/mystra-embedding

Conversation

@EiffL

@EiffL EiffL commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

ASTRA article and book applications assume root asset URLs and a directly reachable MyST reload port, which prevents faithful embedding behind Jupyter authentication. This adds optional mystra-viewer.v1 support so Lightcone can display the actual selected theme under a per-project URL prefix. It is the theme half of LightconeResearch/jupyterlab-lightcone#11; the companion viewer is LightconeResearch/jupyterlab-lightcone#19.

The host sets MYSTRA_BASE_URL, MYSTRA_CONTENT_URL and MYSTRA_RELOAD_URL together and starts the normal myst start. Without them nothing changes.

What the production server does under a prefix (themes/*/server.js, byte-identical):

  • Mounts the prefix as the literal root route in the server and browser Remix manifests, decoded for the router and raw for Express. Route loaders see site-relative URLs; their redirects get the prefix back.
  • Prefixes stylesheet links from links() and the font/image URLs inside compiled CSS as they are served, so the files on disk stay reusable by standalone sessions. Stylesheets keep their links() order and remain on the root error page.
  • Serves the prefixed browser manifest and answers GET <prefix>/mystra-capabilities for the host's readiness probe.

What the application does (root.tsx, loaders.server.ts, packages/astra):

  • Emits an import map so compiled module imports resolve under the prefix, connects MyST's reload protocol through the host WebSocket path, and stores appearance preferences locally instead of the stock root-only cookie API (one small addition to the existing @myst-theme/site patch).
  • Rewrites content links to the public content URL and prefixes ASTRA navigation links.

The README specifies the host contract, including that the proxy must relay X-Remix-* response headers (fixed on the viewer side in the companion PR), and notes the one known limitation: Remix 1 navigates same-origin redirects in-app, so client-side navigation to a non-page file MyST did not mark static still lands on the content URL without a route.

Validation:

  • 137 tests across 14 files; article and book type checks; both production builds.
  • Built article server against the DESI fixture under /user/j%C3%B6rg@x/site: home and pages render with every asset, stylesheet, ASTRA and nav link prefixed; ?_data requests return data, index redirects carry prefixed Location/X-Remix-Redirect, static files redirect to the public content URL, and the root error page keeps its stylesheets. Standalone start is unchanged and no longer exposes the capabilities endpoint.
  • Rejected configurations fail at startup: a trailing slash, characters Express would treat as pattern syntax, or a partial set of the three variables.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VbuPkemydX136SpURMmW1S

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Lightcone previews: Paper · Playground — inventory, viewers, dialogs and glyphs

1a0fbcc · @astra-spec/ui 0.0.5 from 9c940eb · Lightcone brand 0.0.3 · astra-theme 1a0fbcc · content 3735fcc · MySTRA https://github.com/LightconeResearch/MySTRA/releases/download/v0.0.8/mystra.mjs

EiffL and others added 2 commits September 10, 2026 08:53
Import maps redirect JavaScript module imports to the public prefix, but
font and image URLs inside the compiled CSS bundles are still root-relative
and 404 behind the viewer prefix. Serve those CSS files through a small
rewrite route that prepends the prefix, leaving the compiled files on disk
untouched so standalone sessions keep working.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbuPkemydX136SpURMmW1S
Resolves conflicts with the shared-UI rendering work from PR #17:

- root.tsx: keep the bundled stylesheets in <head> so embedded sessions can
  prefix them, while adopting main's brand class and theme attributes and
  dropping the Google Fonts links now that the brand package bundles them.
- AstraOutput: wrap the prefixed decision link in main's InlineReference.
- @myst-theme/site patch: regenerated against the pristine 1.3.1 sources so
  it carries both the useLocalStorage option and main's themeAttributes.
- README: keep both the embedding contract and the shared-rendering notes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbuPkemydX136SpURMmW1S
@EiffL
EiffL marked this pull request as ready for review September 10, 2026 13:01
EiffL and others added 2 commits September 10, 2026 09:51
- Validate MYSTRA_BASE_URL as JupyterHub emits it: percent-encoded, '@' and
  '~' literal, no trailing slash, regex-safe for Express paths; require the
  three MYSTRA_* variables together so the server and page agree.
- Compile the Remix root route from the decoded prefix, since the router
  matches decoded pathnames while Express matches raw ones.
- Keep the bundled stylesheets in links() and prefix them as they are served,
  so the root error page stays styled and the cascade order matches main.
- Cache the rewritten stylesheets with immutable headers; register the
  capabilities endpoint only in prefix mode.
- Reduce previewHref to a single guard and PreviewReload to MyST's reload
  message with backed-off reconnects; no reload on reopen.
- Derive the @myst-theme/site patch from main's with only the local-storage
  hunks added.
- Document that hosts must relay X-Remix-* response headers, and the known
  limitation for client-side navigation to non-page files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbuPkemydX136SpURMmW1S

@EiffL EiffL left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@EiffL
EiffL merged commit 48b818b into main Sep 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant