Chapter 18: web/src, one page and the little it takes to serve it
Seven files. Read them in this order and you have the whole site.
content.rs is what the page says, as data. The title and
the description a link preview carries. The addresses it links to. The
hook, twelve pixels by twelve, that sits in every title bar. And the four
pictures, each a Shot: the file, a title, a sentence or two, the words
for someone who cannot see it, and its real width and height. There is no
markup in this file, on purpose: you can change what the site says without
touching how it is drawn.
hooks.rs is the map of hook points. Claude Code raises
thirty-three kinds of event a plugin can answer, and the page lists every
one with what jevhooks does there: judged, heard, an idea, or nothing yet.
The list is not typed out a second time. It is the plugin's own
(jevhooks_events::HookEvent, chapter 8), the very code the mod and the
daemon are compiled from, and "judged" and "heard" are read from its
role. So the page cannot claim an event the plugin does not handle. What
this file adds is where an event sits in a session, a sentence on what
happens there, and the ideas somebody has written down.
rules.rs is the rules, drawn. Chapter 12's rules are
compiled into three small networks, and the page shows each one as a
picture. Not a picture of them, drawn by hand beside the code, which
would be wrong by the second change: rete-draw draws the very network
the daemon runs, compiled into this Worker from the same crate. What this
file adds is ten worked cases (cargo test, a force push, a turn that
stopped early, ...). Each is an answer Jev could give, read through the
plugin's own thresholds and run through the network, and how it ended is
whatever the network said. Nobody typed "allow" next to cargo test.
view.rs draws it. page(origin) is a pure function: an
address in, a string of HTML out. It fetches nothing, reads no clock and
knows no visitor. That is what makes the page testable without a browser
or a Cloudflare account: the tests call page, and read the string.
lib.rs is the Worker. Every request passes through fetch,
which does four things in order:
flowchart TD
R["a request"] --> G{"came to the canonical address,<br/>or a local one?"}
G -- "no, and it is a GET or HEAD" --> M["308 to the same path<br/>on hooks.lmjtfy.fun"]
G -- yes --> C{"the preview card?"}
C -- yes --> A["from the static assets"]
C -- no --> P["the router:<br/>the page, the icon, robots.txt,<br/>a picture, a shared file, or 404"]
M --> H["security headers on every answer"]
A --> H
P --> H
H --> L["one log line: route, method, status, time"]
log.rs is what gets written down, and mostly what does not.
A path is turned into one of nine Routes before anything is logged, so
the log can say GET shot -> 200 in 1 ms and has nowhere to put an
address, a query or a header. A path nobody serves is the one word
other, never its own text.
bin/card.rs draws the link preview's card (chapter 17's second aside) and prints it.
Aside: a policy with no holes to forget. Every answer carries a Content Security Policy, the header that tells a browser what a page may load. This site's says: its own files, and nothing else. No script from anywhere else, no script written into the page, none built from a string. It comes from
aldebaran-headers, where a policy starts at "nothing" and each allowance is a method you have to call by name (this site calls two:with_inline_styles, for the stylesheet the shell puts in the head, andwith_data_images, because the dotted background is a picture the shared script draws in your browser and hands to the page as data; the first deploy left that one out, and the dots were simply not there). A test builds the page and fails if an inline<script>ever appears, because the browser would drop it without a word.
Try it.
mise run test:web, then break something: give aShotthe wrongheightincontent.rsandeach_picture_declares_its_real_sizereads the real one out of the SVG and says so; put a secondloading="eager"picture in andevery_feature_has_its_picturenotices.
For the people who maintain it
| Path | What |
|---|---|
| content.rs | NAME, TITLE, DESCRIPTION, the links, TRY_IT, the install lines (VERSION, install, release_key, which reads tools/release.pub), the card's path and size, HOOK, Shot and the four of them (SHOTS), and FILES, the bundle the pictures are served from. |
| hooks.rs | Phase, State, Hook, hook(event) (an exhaustive match: a new event does not compile until it is placed), all, count, BEYOND (the two mod events used for model choice), and tests that hold "built" to the plugin's own roles. |
| rules.rs | run (a network run to its end, with the rules that decided), judgments (the three, each with its cases as <details>, drawn by rete_draw::rete), and tests that hold each case's ending to the network's. |
| view.rs | page, favicon, the link preview (jev_ui::preview::Preview), and the page's tests. |
| page.css | The site's own few rules, after the shared sheet: the lede, the picture's frame, the promise, the steps, the map's chips, a case, and the look of a drawn network (.rete; rete-draw writes classes and no styles). Tokens only. |
| lib.rs | fetch, gate, card, the router, policy, origin (from SITE_ORIGIN), and the gate's and policy's tests. |
| log.rs | Route and its names; the note a missing card writes (mise run web:build). |
| bin/card.rs | The card as SVG on stdout: jev_ui::card::Chrome at twice its base size, 1200 by 630, three lines in the window. |
← Previous: Chapter 17, web/ · Up: web · Next: nothing; you have read it all. Back to the start →