typst: a block of it in markdown is typeset on the server

A ```typst (or ```typ) block is compiled by the typst crate into SVG and
shown as an image where it stands, so math, tables and figures can be
written in typst beside the markdown around them. It shows its source while
it is set, and the error typst gives, with the block's line, when it cannot
be.

Each block is a document of its own: its source is the only file in its
world and the fonts are typst-assets', inside the binary, so nothing is read
from disk or fetched — packages and images are refused. The page fits what
is on it, is transparent, and carries the theme's text colour. Answers are
cached by source, two blocks are laid out at a time off the async threads,
and comemo's memo is evicted after each compile.

A share page asks POST /api/share/{token}/typst, which takes the reader's
cookie and typesets only a block the shared document holds.

typst brings a palette crate whose AsRef impls on arrays made four
`kek.as_ref().into()` in the vault ambiguous; they deref instead.
This commit is contained in:
nvrl committed 2026-10-21 15:41:45 +02:00
1 parent 73ac961751
commit 0245402ead
34 files changed
+2295 -18

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

+2
View File
@@ -47,6 +47,7 @@ sealed or not.
| `POST` | `/api/backup/login/totp`, `/api/backup/login/captcha` | the two-factor code `{"code"}`, or the solved human check `{"token"}`, a waiting login asked for |
| `GET`/`POST` | `/api/media` | list / upload (multipart) |
| `GET`/`DELETE` | `/api/media/{id}` | serve (with `Range`) / delete a file nothing in the tree owns |
| `POST` | `/api/typst` | `{source}` of a ` ```typst ` block → `{svg}`, or `{error}` as typst words it |
| `GET` | `/api/spaces/overview` | every space with what was last written in it |
| `POST` | `/api/nodes/{id}/files` | upload files into this folder as file nodes (`?encrypt=true` seals them) |
| `POST` | `/api/nodes/{id}/inspect` | what a certificate, key or keystore file holds (`{password}` opens a protected one) |
@@ -57,3 +58,4 @@ sealed or not.
| `DELETE` | `/api/ssh-keys/{id}` | remove a key, which ends its mounts |
| `POST` | `/api/share/{token}` | public: read a shared document, body `{"key"}`; sets the share's media cookie |
| `GET` | `/api/share/{token}/media/{id}` | public: media inside a shared document, with that cookie |
| `POST` | `/api/share/{token}/typst` | public: a typst block the shared document holds, with that cookie |
+17
View File
@@ -59,6 +59,23 @@ Math is set by KaTeX:
![Math in a document](../images/math.png)
### Typst
A ` ```typst ` block (or ` ```typ `) is set by [Typst](https://typst.app) on
the server and shows as an image where it stands: math, tables, figures,
anything typst lays out. It shows its source while it is being set, and the
error typst gives, with the line of the block, when it cannot be.
- The page fits what is on it and is transparent, and the text is the
theme's. `#set page(width: 15cm)` makes a block of prose wrap, and any other
`#set` changes what it says.
- A block is typeset with nothing but itself and the fonts built into the
binary: `#import "@preview/…"` and `#image("…")` are refused.
- On a share page the blocks are set too, for the reader holding the key, and
only blocks the shared document holds.
![A typst block in a document](../images/typst.png)
## Links
A document links to another in two ways: