Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/www/assets/typst/VENDORED.md

5.0 KiB, 1 run

created by r2519314175:1057, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1# Typst packages, carried in the bundle
2
3`#import "@preview/cetz:0.3.4"` names a package in Typst Universe. The command-line
4compiler downloads it and caches it under `~/.cache/typst/packages`; the compiler in
5this page has no network at all, so until now every document with a live cetz diagram
6was refused outright — including the author's own 281-page book, whose template opens
7with that exact line.
8
9These packs are how that is answered. Five packages ship inside the app, as sealed
10files, and `src/wasm/typst.rs` hands their sources to the compiler as ordinary files.
11
12| pack | files | bytes | why it is here |
13|---|---|---|---|
14| `preview/cetz/0.3.4.pack` | 38 | 289,319 | the book imports it |
15| `preview/oxifmt/0.2.1.pack` | 3 | 21,812 | cetz 0.3.4 and 0.3.2 both import it |
16| `preview/cetz/0.3.2.pack` | 38 | 287,832 | **cetz-plot 0.1.1 imports this version, not 0.3.4** |
17| `preview/cetz-plot/0.1.1.pack` | 27 | 184,702 | charts and plots on top of cetz |
18| `preview/fletcher/0.5.7.pack` | 13 | 143,367 | arrow diagrams; imports cetz 0.3.4 |
19
20927 KB in total, fetched only when a document actually imports one. A session that
21typesets nothing, or typesets a document with no packages in it, pays nothing.
22
23## Why not `www/vendor/`
24
25Because `www/vendor/` is gitignored, excluded from the public mirror by
26`dev/publish.mjs`, and excluded from the bundle fingerprint by `verify/lib.mjs`. A
27live view was once shipped with no renderer behind it for exactly that reason. These
28files are under `www/assets/`, which is committed, crosses to the mirror, is cached by
29the service worker as part of the shell, and **is inside `www/manifest.json` and the
30transparency chain**. What compiled the book is provably what shipped.
31
32## Why the whole closure and not the named package
33
34cetz 0.3.4's `src/deps.typ` is one line: `#import "@preview/oxifmt:0.2.1"`. Ship cetz
35without oxifmt and the import resolves, then fails — and *a package that resolves while
36its dependency does not is indistinguishable from one that never resolved*. The same
37trap caught the first run of `dev/probe_typstpkg.mjs`.
38
39So the closure is walked, not assumed:
40
41- `refresh.sh` carries the set a human chose. It is a **wish list, not a closure.**
42- `src/wasm/typst.rs` derives the closure at compile time from the package **sources
43 themselves** — it reads each pack's `.typ` files and follows every `@…` import it
44 finds, recursively. A dependency cannot be silently absent, because nothing consults
45 a hand-written list of dependencies.
46- A dependency that is not carried produces its **own** refusal, in different words
47 from an unavailable package, saying that the document is not at fault.
48
49`cetz-plot` is why this matters in practice: its `src/cetz.typ` imports
50`@preview/cetz:0.3.2`, not the 0.3.4 the book uses. cetz is therefore vendored twice.
51Nobody would have guessed that from the package's name or its version number.
52
53## The pack format
54
55One file per package, so one HTTP request loads one package and the service worker
56caches it whole.
57
58```
59DAIMOND TYPST PACK 1
60namespace preview
61name cetz
62version 0.3.4
63entrypoint src/lib.typ
64file 7651 LICENSE
65file 1953 src/aabb.typ
66…
67<one blank line>
68<the file bodies, concatenated, in the order listed>
69```
70
71ASCII header, blank line, raw bytes. Lengths rather than delimiters, so a source
72containing anything at all cannot end a file early. `packs/INDEX` lists every pack with
73its file count and its byte length, and `src/wasm/typst.rs` **`include_str!`s that
74INDEX** — so the wasm knows what this build carries without asking the network, and a
75pack that does not match its INDEX line is reported as a broken deployment rather than
76as a missing package.
77
78## Refreshing
79
80```bash
81bash www/assets/typst/refresh.sh # from ~/.cache/typst/packages
82```
83
84Nothing is downloaded: the local typst package cache is read, and a package that is not
85in it stops the script rather than producing a set with a hole in it. The script is
86served alongside what it produced, so the recipe is inside the same seal as the result.
87
88**`packs/INDEX` is compiled into the wasm.** After a refresh the wasm must be rebuilt
89and the bundle resealed, or the wasm and the served packs describe different sets.
90
91## What is taken, and what is left
92
93Sources (`*.typ`), the `typst.toml` that names the entrypoint, and the licence. Not the
94README, not the galleries, not the built PDFs — none of them is read by a compile and
95together they are most of what a package directory weighs. The licences ship because
96this is other people's LGPL and MIT work travelling inside our bundle.
97
98## The accepted cost
99
100A document that asks for a version not carried here still fails. It fails with a
101sentence that says which versions *are* carried and that the fix is to vendor another
102one — but it fails. That was the deliberate choice: the alternative is fetching from a
103registry at compile time, which would make "this compiler runs inside the page with no
104network at all" false, and would put outside the seal the one thing the whole
105verification story rests on.