Discovery

Use the seo() helper from @torpor/build/discovery to build the head for a page from its zones: a title, a description and a link to the page:

import { seo } from "@torpor/build/discovery";

export default {
	component,
	head: (event) => seo({
		title: post.title,
		description: post.excerpt,
		image: post.coverImage,
		url: event.url.href,
	}),
} satisfies PageEndPoint;

When an image is set, Open Graph and Twitter meta tags are included, so links to the page unfurl nicely in social media. Values are escaped, and rendered into the document <head> along with any @head markup in the component, which wins when both provide a <title>, and beats any static <title> in the site template.

Plain @head markup is fine too, and you can use it (or a link rel="canonical" tag, or JSON-LD in a script tag) for anything seo() doesn't cover:

@head {
	<title>My page</title>
	<link rel="canonical" href="https://example.com/posts/1" />
	<script type="application/ld+json">
		{JSON.stringify({"@type": "BlogPosting", headline: post.title})}
	</script>
}

A sitemap

Setting site.sitemap writes a sitemap.xml listing the prerendered pages at build time, and needs site.origin for the urls:

// site.config.ts
site.origin = "https://example.com";
site.sitemap = true; // or e.g. "/blog/sitemap.xml"

The pages listed are exactly the prerendered ones (the set that serves statically) so a dynamic route (e.g. blog posts under [slug]) needs params entries (see Prerendering) to be included.

A runtime sitemap

When the sitemap must keep up with the database — for content that isn't prerendered (e.g. blog posts under [slug]) — pass a config instead, and the xml generates live on each request:

// site.config.ts
site.sitemap = {
	get: async () => {
		const posts = await db.posts.list();
		return posts.map((p) => `/posts/${p.slug}`);
	},
};

The urls returned are base-free paths (like prerender params) with the site origin added. Use path to serve it from somewhere other than /sitemap.xml.

robots.txt

Add a robots.txt file to src/public, where a Sitemap: line can point at the sitemap:

User-agent: *
Allow: /

Sitemap: https://example.com/sitemap.xml