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, and with_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 a Shot the wrong height in content.rs and each_picture_declares_its_real_size reads the real one out of the SVG and says so; put a second loading="eager" picture in and every_feature_has_its_picture notices.

For the people who maintain it

PathWhat
content.rsNAME, 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.rsPhase, 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.rsrun (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.rspage, favicon, the link preview (jev_ui::preview::Preview), and the page's tests.
page.cssThe 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.rsfetch, gate, card, the router, policy, origin (from SITE_ORIGIN), and the gate's and policy's tests.
log.rsRoute and its names; the note a missing card writes (mise run web:build).
bin/card.rsThe 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 →