Pages and PageMeta
The page signature, and every field of the metadata record.
proc page(ctx: Context, ref meta: PageMeta): stringmeta is passed by ref because the page is expected to fill it in. The document shell reads it after the layout has run, so both the page and its layout can contribute.
Every field
| Field | Type | Effect |
|---|---|---|
title | string | <title> |
description | string | <meta name="description"> |
lang | string | <html lang>, default "en" |
canonical | string | <link rel="canonical"> when set |
icon | string | <link rel="icon"> when set |
bodyClass | string | class on <body> |
stylesheets | list(string) | One <link rel="stylesheet"> each |
scripts | list(string) | One <script type="module"> each |
needsClientRuntime | bool | Set by island |
status | int | The response status, default 200 |
Status is what makes an error page honest
A page that renders "not found" should say so in the status line, not just in the heading:
if !PostStore.find(id, post) {
meta.status = 404;
meta.title = "Post not found";
h.el("h1", "Post not found");
return h.done();
}Search engines, monitoring and caches all read the status line. A 200 that says "not found" in body text is a lie the whole stack believes.
Throwing pages
A page or layout declared throws is wrapped by the generated handler: an escaped error is logged and becomes a 500 rather than unwinding the connection task.
What the context carries
| Member | Returns |
|---|---|
pathParam(name, fallback = "") | A captured route segment |
paramInt(name, fallback) | The same, parsed as an integer |
queryParam(name, fallback = "") | A query-string value |
setLocal(name, value) / getLocal(name, fallback) | Per-request scratch state |
method() / path() | The request method and normalised path |
requestId | ip:port#n, also used by the access log |
request | The parsed request |
ctx.request carries header(name), contentType(), bodyText(), accepts(mime), clientIp(), query, headers, peerIp and peerPort.
clientIp()readsX-Forwarded-Forand is spoofable unless a trusted proxy overwrites it. Never use it for authorization.