embed-resources cannot be enabled from the CLI: Quarto only honours it when
nested under the format, and a document's own format block fully overrides
project/CLI metadata (confirmed in Quarto docs). So --metadata embed-resources
was silently ignored and the 'standalone' HTML was the ordinary non-embedded
deck referencing a sibling _files/ dir — unstyled, no math, no images once
downloaded on its own.
For the html-standalone export, render a temporary copy of the root .qmd with
embed-resources/self-contained-math enabled and chalkboard disabled inside its
revealjs block (replacing an existing chalkboard key rather than duplicating
it), then clean the temp file up. Falls back to the original file if the deck
isn't an editable nested-revealjs document, so the export is never worse than
before.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The slide-PDF export failed because the CLSI runtime user has no writable
HOME, so Chromium's crashpad couldn't create its database and the browser
died on launch ('chrome_crashpad_handler: --database is required'). Give
decktape's Chromium a fresh writable temp dir via HOME/XDG_*/--user-data-dir
(plus --disable-gpu).
The standalone-HTML export kept returning the old non-embedded file partly
because the GET response had no cache headers, so the browser served its
cached copy; add Cache-Control: no-store to both export responses. Also
switch the embed-resources flags to the long '--metadata KEY:VALUE' form
(the documented Quarto syntax) to remove any ambiguity vs the '-M' alias.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The standalone-HTML export produced a non-self-contained file (no slide
CSS/JS, math or images when opened away from the server) because Quarto's
--metadata/-M flag uses KEY:VALUE (colon), not KEY=VALUE. '-M
embed-resources=true' silently registered a bogus key and left
embed-resources unset. Switch to colon syntax and also embed MathJax
(self-contained-math:true) so equations render offline.
For the slide PDF, add --disable-dev-shm-usage (the usual cause of
Chromium crashing inside a container with a small /dev/shm), and have the
export controller return the compile log as text/plain on failure so a
failed PDF export shows the real decktape/Chromium error instead of an
HTML page the browser saves as 'pdf.htm'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In RevealJS mode the download button becomes a 2-choice menu:
- Standalone HTML: a one-off compile with embed-resources (chalkboard and other
runtime-only plugins are dropped, since they don't survive self-containment),
yielding a single portable .html.
- Slide PDF: render the deck, then print it with decktape (headless Chromium)
to a faithful one-slide-per-page PDF.
Implementation:
- Dockerfile-base: install decktape + headless Chromium (open-source; deps via
playwright install-deps for Ubuntu-Noble correctness). Base-only change.
- QuartoRunner honours options.exportMode ('html-standalone' | 'pdf-slides');
exportMode is threaded web ClsiManager -> CLSI RequestParser -> CompileManager
-> runner.
- New GET /project/:id/presentation-export/:format compiles in the matching
export mode and streams the result as a download (PresentationExportController,
reusing ClsiManager.getOutputFileStream).
- pdf-hybrid-download-button shows the dropdown when the output is output.html;
PDF/LaTeX projects keep the single download button.
- i18n: download_as_standalone_html / download_as_pdf_slides (en + fr +
extracted-translations.json).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OutputFileFinder excluded all incoming project resources from the output set,
and OutputCacheManager only copies outputs into the served build dir. For PDF
that's fine (media is embedded), but for HTML/RevealJS the browser fetches
images/videos/fonts from the output path at runtime — so a deck's referenced
image (a project input file) was never served and rendered broken in the
preview.
When the compile produced output.html, keep media inputs (img/video/audio/font
extensions) in the output set so they're served alongside the deck. PDF/LaTeX
compiles are unaffected. This also makes referenced media land in output.zip,
which the upcoming presentation-publishing feature relies on.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Since we dropped --embed-resources (so RevealJS plugins like chalkboard work),
pandoc no longer tries to fetch referenced media for HTML output, so a missing
image or video produces no compile-time warning — it only renders broken in the
browser. PDF/Typst output is unaffected because Typst hard-errors on a missing
image.
After an HTML render, QuartoRunner now scans output.html for local media
references (img/video/audio/iframe src, poster, RevealJS data-background-*) and
appends a `[WARNING] Missing resource: …` line to output.log for any that don't
exist on disk. External URLs, data URIs, anchors and Quarto's own generated
<basename>_files assets are ignored. The [WARNING] prefix is recognised by the
Quarto/Typst log parser, so these show up in the Warnings tab.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Project.compiler defaults to settings.defaultLatexCompiler ('quarto' in this
fork), so every .tex project carried compiler='quarto'. Since the CLSI runner
is chosen by file extension, a .tex root still goes to LatexRunner, whose
_buildLatexCommand threw `unknown compiler: quarto` — surfacing as an opaque
HTTP 500 with no compile log.
- LatexRunner: fall back to pdfLaTeX when the compiler isn't a known TeX engine
instead of throwing. Universal safety net (covers existing projects, uploads
and GitHub imports already saved with compiler='quarto').
- ProjectCreationHandler: store a sensible compiler per flavour at creation via
a shared _flavourConfig helper — blank/example LaTeX → 'pdflatex',
Typst → 'typst', Quarto → 'quarto' — so the compiler dropdown reflects the
engine and LatexRunner receives a valid one directly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A project whose root file is a .typ file now compiles straight to PDF with
Typst, as a third engine beside Quarto (.qmd) and latexmk (.tex). Dispatch
stays purely extension-based.
CLSI:
- New TypstRunner.js: runs `quarto typst compile <main>.typ output.pdf` (reuses
the Typst bundled in Quarto, so no extra binary / Docker change). stderr is
merged into output.log.
- CompileManager: _isTypstFile + a TypstRunner branch in _getRunner, and
TypstRunner added to the isRunning check and stopCompile kill list.
- RequestParser: 'typst' added to VALID_COMPILERS.
web:
- settings.defaults: 'typ' added to validRootDocExtensions and the text
extensions (so .typ opens in the editor); 'typst' added to safeCompilers.
- output-files: the Quarto/Typst log parser (which already understands Typst
`error:`/`warning:` + `┌─ file:line:col` diagnostics) now also handles .typ
compiles, so their errors/warnings populate the log tabs.
Polish:
- New-project menu: "Blank Typst project" + "Example Typst project" in both the
main and welcome dropdowns, backed by createBasicProject/createExampleProject
flavour 'typst', a new mainbasic.typ template and an example-project-typst
presentation (math, an image, a table, lists).
- Compiler dropdown gains a "Typst" option (cosmetic; dispatch is by extension).
README updated: three compilers side by side, with a Writing-a-Typst-document
section.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two HTML/RevealJS preview fixes:
1. Stop passing --embed-resources to quarto render. A self-contained
single-file HTML breaks reveal.js plugins that load/store resources at
runtime (chalkboard, multiplex) and is slow to transfer. Quarto now
emits the HTML plus a sibling "<basename>_files/" asset dir referenced
by relative paths; both are served from the same .../output/ path
(nginx output/(.+) and web :file(.*) both capture slashes), so the
relative links resolve. The renamed output.html still points at the
unchanged "<basename>_files" dir. This also fixes the slow-load issue,
since assets now load on demand instead of one giant inlined file.
2. On a failed compile that follows a successful one, the previous deck
stayed in the iframe, making the failure look like a success. We now
clear pdfFile when a non-success status carries a stale output.html.
The last-good-PDF-beside-the-error behaviour is preserved for PDF
output (only output.html is dropped).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verso now compiles both .tex (latexmk) and .qmd (Quarto) projects,
dispatching by the root file's extension rather than replacing one with
the other. LaTeX and Quarto projects can coexist on the same server.
CompileManager: re-import LatexRunner and add a _getRunner() dispatcher
that returns a uniform {run, isRunning, kill} interface. .qmd/.md/.Rmd
→ QuartoRunner; everything else (.tex/.ltx/.Rtex/.Rnw) → LatexRunner.
stopCompile now checks/kills both runners since it has no root path.
compiler-setting.tsx: restore the LaTeX engine choices (pdfLaTeX, LaTeX,
XeLaTeX, LuaLaTeX) alongside Quarto. The dropdown still controls which
TeX engine latexmk uses; actual engine dispatch is by file extension.
Dockerfile-base: reinstall TeX Live alongside Quarto (texlive-full minus
-doc/-lang- packages, plus xetex/luatex/biber/latexmk/texcount/chktex/
synctex). Restore TEXMFVAR for a writable LuaTeX cache. This brings back
a large image, which is the accepted cost of full LaTeX+Quarto support.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dockerfile-base: after Quarto is installed, run 'quarto add --no-prompt'
for a curated set of extensions into /opt/quarto-extensions/. Quarto
writes _extensions/<author>/<name>/ in the working dir, giving us a
clean shared store. Extensions included:
- igorlima/charged-ieee — IEEE paper format (Typst)
- quarto-ext/fontawesome — Font Awesome icons
- quarto-ext/attribution — attribution footer on RevealJS slides
- quarto-ext/pointer — laser pointer for presentations
- quarto-ext/drop — drop-down overlay for RevealJS
Adding more: one extra '&& quarto add --no-prompt <author>/<repo>' line.
QuartoRunner: before quarto render, merge /opt/quarto-extensions/_extensions/
into the compile dir's _extensions/ with 'cp -rn' (no-clobber). This
makes all pre-installed extensions available to every project without
any user action. Project-uploaded _extensions/ files take precedence
since cp -n never overwrites existing files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
collectOutputPdfSize() only calls stat() and sets .size on output.pdf.
All other output files (including output.html) keep size: undefined.
The previous check required file.size > 0 for both PDF and HTML, so
undefined > 0 always evaluated false for output.html, making every
RevealJS compile report 'failure' even when the file was produced.
Fix: require size > 0 only for output.pdf; accept output.html
regardless of size (it is always non-empty if Quarto succeeded).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LocalCommandRunner.replace() uses String.replace() which only substitutes
the FIRST occurrence of '$COMPILE_DIR' in the shell script string. The mv
commands had two more occurrences that stayed as literal '$COMPILE_DIR',
which the shell expanded to '', making 'mv /main.pdf /output.pdf' fail
silently. The file was produced (Quarto logged 'Output created: main.pdf')
but never renamed to output.pdf, so the pipeline reported failure.
Fix: mv uses relative filenames since the shell CWD is already the compile
directory (set by LocalCommandRunner via the spawnCwd option).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
clsi-nginx.conf: the types{} block was overriding all nginx defaults,
leaving HTML/CSS/JS/fonts as application/octet-stream. Add the full
set of web MIME types so RevealJS assets are served correctly. Also
needed for X-Content-Type-Options: nosniff to pass.
CompileController.js: success was hardcoded to require output.pdf.
Also accept output.html so a RevealJS compile is reported as
'success' rather than 'failure'.
QuartoRunner.js: remove hardcoded --to typst --output output.pdf.
Instead run `quarto render` without --to/--output so the YAML
frontmatter decides the format (typst → PDF, revealjs → HTML, etc.).
Pass --embed-resources so HTML output is self-contained (flag is
silently ignored by the typst backend). After render, rename
main.pdf → output.pdf or main.html → output.html so the pipeline
finds the standard canonical filename.
output-files.ts: handleOutputFiles now falls back to output.html when
output.pdf is absent. Download URL uses outputFile.path instead of
the hardcoded 'output.pdf' string.
pdf-viewer.tsx: when pdfUrl contains output.html, bypass PDF.js
entirely and render a sandboxed iframe (allow-scripts for RevealJS
interactivity, allow-presentation for fullscreen).
Usage: set `format: revealjs` in the .qmd YAML frontmatter to get
an HTML presentation preview; set `format: typst` for PDF.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous compile logs confirm Quarto handles --to typst --output
output.pdf correctly: pandoc produces main.typ, typst compiles it to
main.pdf, then Quarto renames to output.pdf. The mv-based approach was
unnecessary and incorrect.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--to typst combined with --output output.pdf caused Quarto to write a
Typst source file (.typ content) named output.pdf instead of invoking
the typst compiler, producing a text file that the PDF viewer could not
render (hence 'markdown not rendered' — it was literally showing the raw
.typ markup). Fix: let Quarto name the PDF after the input file
(main.qmd → main.pdf) and rename to output.pdf with mv afterwards.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LocalCommandRunner: attach captured stdout to the error object when
exit code is 1, so callers can read Quarto's output even on failure.
QuartoRunner: stop propagating plain 'exited' errors from Quarto up
to CompileManager. A Quarto exit-code-1 is a compile failure, not a
server error — CLSI already detects failure by the absence of
output.pdf and returns status='failure' (HTTP 200). Previously it
fell through to the generic error handler (HTTP 500), which caused
the frontend to show "Server Error" instead of the log panel.
Only true process-level errors (terminated, timedout) are propagated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dockerfile-base: remove TeX Live (no longer needed), install Quarto
1.6.39 which bundles Typst for PDF output. This was the root cause
of all compile failures — the server-ce monolith never had Quarto.
QuartoRunner: run quarto via /bin/sh so stderr is merged into stdout
with 2>&1; write combined output to output.log (not output.stdout)
so the PDF-preview log panel picks it up and shows raw output.
Also write the log on error so failures are always visible.
CompileManager: guard DraftModeManager behind an isLatexFile check —
injecting LaTeX preamble commands into a .qmd file corrupts it and
causes a guaranteed compile failure when draft mode is requested.
ProjectCreationHandler + mainbasic.qmd: new projects now create
main.qmd with a minimal Quarto/Typst frontmatter instead of the
LaTeX main.tex; _createRootDoc names the file main.qmd accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add QuartoRunner.js: runs `quarto render --to typst --output output.pdf`,
using Typst (bundled with Quarto >= 1.4) so no separate LaTeX install needed
- Swap LatexRunner for QuartoRunner in CompileManager; remove latexmk-specific
stats, fdb metrics, and performance sampling that no longer apply
- Add 'quarto' to VALID_COMPILERS in RequestParser and set it as the default;
change default rootResourcePath from main.tex to main.qmd
- Add 'quarto' to safeCompilers and set it as the default in web settings
- Replace with-texlive Dockerfile stage with with-quarto (Quarto deb install);
add Quarto to the default final stage as well
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* [clsi] add request flag for isCompileFromHistory
* [clsi] derive cacheKey for history snapshot from compile dir
* [clsi] migrate convert project to document to compile from history
* [clsi] address review feedback
* [web] determine root doc at the time of converting the project
* [web] wait for flush before starting document conversion
* [saas-e2e] add tests for root doc override when converting project
GitOrigin-RevId: 71c578030949b89f3a74e7f7ab882dfa9c98c17a
* [clsi] Forward pandoc errors to web
* [clsi] Remove unused import
* [clsi] Align warning logs
* [clsi] Update HTTP response for errors
* [clsi] Update acceptance test with 422
* [clsi] Always return json body on 422
* [clsi] Include stderr in logs for non user facing errors
GitOrigin-RevId: 4284c8d4e8b7b45eac4997cd9e52ca4894b20412
* [monorepo] avoid corepack network requests
- Download yarn via corepack as the first step in all the docker files
- Turn off networking in corepack
- Do not run things in the upstream node image
Instead, use the monorepo image, or base layer in all the services.
- Always build the base layer when running tests (uses cache)
* [monorepo] install corepack in shared place
* [clsi-lb] remove unrelated changes
* [web] add missing DC_RUN_FLAGS
* [monorepo] only rebuild test images locally
Also remove spurious build config in docker-compose.ci.yml.
* [server-ce] test: make yarn files available to host-admin and e2e
* [monorepo] put the corepack install snippet in a few more places
GitOrigin-RevId: 38005016ae5a708e12295e246269d6c18fece937
Migrates the Overleaf monorepo package manager from npm (v11) to Yarn 4 (v4.9.1) using node-modules linker mode.
GitOrigin-RevId: 50d32ab01955c15e29679eff9e9e9cfb897fab2d
* using CLSI logic for fetching the project contents and skip the .zip export
* Use unique conversion directory for project-to-docx export to avoid corrupting the shared compile
directory when a compile runs concurrently
* Remove X-Accel-Buffering header — not needed as CLSI does not run behind nginx
* moving log before sending the data
* Return CLSI stream directly instead of buffering to disk on web
Previously convertProjectToDocx wrote the CLSI response to a temp file
on disk, then the controller read it back to stream to the client.
Now the stream is returned directly and piped to the response,
avoiding unnecessary disk I/O on the web server.
* Use href redirect for docx export instead of fetching blob into memory
* making functions and files more generic so they can be used in future for other documents exports as well
* adding export-docx split test
* adding unit tests
* adding cypress E2E test
* format:fix
* renaming the route to download from convert
* adding new icon for export docx button
* format:fix
* remove unused showExportDocumentErrorToast export and adding guard against invalid Content-Length header from CLSI
* format:fix
* refactor(clsi): move promisify(parse) into RequestParser
* refactor: generic conversion endpoint with type as route
param
* refactor: use type→extension map for validated conversion types
* refactor(clsi): remove --standalone flag and fix rejection test
* fixing the href in cypress test
* renaming function
* adding type to Metrics.inc
* fix: rename exportProjectDocument, add WithLock wrapper and metrics type label
* format:fix
* fix: hide docx export from anonymous users and add WithLock wrapper
* format fix
* remove redundant Content-Length validation from DocumentConversionManager
* format:fix
* removing trailing icon
GitOrigin-RevId: e9764fefac2c4b625d23be9e942ea4a8b283c70d
* [clsi] handle draft mode and tikzexternalize as part of sync phase
* [clsi] emit empty string from SafeReader on ENOENT
* [clsi] persist history state after clearing dirty state without changes
GitOrigin-RevId: d9dcd2e6887017f7935b5e95bdbdc6e11a3b18f5
* [clsi] remove locking from docker actions
Start:
- We have an in-memory lock on the compile request
Destroy:
- as part of run: see above
- as part of cleanup: we check the last access time now, so it cannot
happen concurrent to compiling anymore.
Co-authored-by: Anna Claire Fields <anna.fields@overleaf.com>
* [clsi] update comment
---------
Co-authored-by: Anna Claire Fields <anna.fields@overleaf.com>
GitOrigin-RevId: a58df45416ae31c0b38d5efec7f9371d747303df
* [clsi] avoid server error when clearing cache while compiling
* [clsi] tweak API around releasing locks
Co-authored-by: Eric Mc Sween <eric.mcsween@overleaf.com>
---------
Co-authored-by: Eric Mc Sween <eric.mcsween@overleaf.com>
GitOrigin-RevId: d3f171467d3bc26941758dd333f30049b37a05c8
* [k8s] clsi-cache: double the number of shards
* [monorepo] add missing clsi-cache env vars to dev-env
* [clsi] flip direction of clsi-cache shard migration
* [clsi] remove upper bound from clsi-cache shard migration
GitOrigin-RevId: a325a11c3ac9e22a12ad2d8ea802b91d2e175e24
* handle old versions of latexmk in run count extraction
the log lines for the run number change from stderr to stdout in TL2022
* extend SimpleLatexFileTest to include TL2017
* reset metrics for each scenario in SimpleLatexFileTests
* fix buildscript merge conflict
GitOrigin-RevId: fb74f2025d21ddf43be6a3b90ac6f7df4d975db6