Skip to content
internal/address
On this page

The single addressing authority for built pages: the output key, the stable version-free URL, the pinned archive path and the hops back to each root.

#internal/address

#internal/address

Package address is the single addressing authority for built pages.

One function -- [NewPageAddress] -- decides, for a page and the locale, project and version it belongs to, all four things the rest of the build needs:

- OutputKey: where the page file lands under the output root ("guide/index.html" for the current version, "v/1.0.0/guide/index.html" for a superseded one). - Stable: the version-free URL path for the page ("guide/"). This is where the CURRENT version of every page lives, and it is what every version of the page declares canonical. - Pinned: the version-pinned URL path ("v/1.0.0/guide/"). A superseded version is emitted there; the current version's pinned address is the address it will occupy once a newer version supersedes it. - Depth: how many directory levels the output key sits below the output root, and from it the two relative hops every page needs -- [PageAddress.ToSiteRoot] back to the output root, where the shared assets live, and [PageAddress.ToMountRoot] back to this page's own mount, where its sibling pages live.

#The scheme

The current version of every page lives at a stable, unversioned address:

///

Superseded versions live beside it under the archive prefix "v":

//v///

The locale segment is dropped entirely while a site has one locale -- [LocaleSegment] is the one place that decides it -- and the project segment exists only on a unified site. A single-locale standalone site therefore mounts its current version at the output root: "guide/".

"v" is reserved. A top-level page named "v" would collide with the archive tree, so [NewPageAddress] refuses it.

#Why its own package rather than urls

The urls package turns a path into an absolute URL against a configured base (base_url, or a docs base plus a slug). That is a deployment concern -- it answers "what does the world call this page". Addressing answers "where does this page sit in the output tree, and how does it reach its neighbours", which has to be correct with no base URL at all and identical under every mount point. Mixing the two is what produced the depth defect this package replaces: a site's own asset links must never depend on where the site is served from, so they are always document-relative and always derived here.

#ArchivePrefix

Go go
const ArchivePrefix = "v"

ArchivePrefix is the URL segment every archived (superseded) version is emitted under.

#PostsPrefix

Go go
const PostsPrefix = "blog"

PostsPrefix is the site-level URL segment every post is emitted under: "blog//". Fixed, and the same in a standalone build and on the unified site.

#PageAddress

Go go
type PageAddress struct

PageAddress is every address a single built page has.

It is a value type with no pointer fields, so a copy is independent of its original: that is what stands in for the frozen dataclass this replaces. Nothing in the package mutates one after [NewPageAddress] returns it, and a caller should not either -- the addresses are consistent with each other only as constructed.

#Coordinates

Go go
type Coordinates struct

Coordinates are the mount coordinates a page is built under. The zero value is a single-locale standalone site's unversioned page, which is what the Python's keyword defaults expressed.

#IsSiteLevel

Go go
func IsSiteLevel(path string) bool

IsSiteLevel reports whether path addresses the site level rather than a project mount.

Posts are site citizens: they carry no locale, project or version segment, and on an assembled site they are served from the site root at "blog//" while the project that wrote them is served under its own slug. Every surface that has to tell the two apart -- the URL builder deciding whether to write the slug, the sidebar deciding which hop reaches an item -- asks here.

It accepts either form the build speaks: an output path ("blog/hello/index.html") or a URL path ("blog/hello/", "blog/").

Go go
func RootPageLink(mdFilename string) string

RootPageLink is the link written on one root-level docs page to another root-level page.

Every root-level page except index.md is emitted at "/index.html", so a page writing a link is itself inside a directory and a sibling is one level up: "..//". Writing the bare "/" -- correct back when pages were flat ".html" files -- now resolves inside the writing page's own directory and names nothing.

The generated index pages (the API reference and the CLI reference) are the callers: both are always at the docs root, which is what makes the single hop the right one.

#NewPageAddress

Go go
func NewPageAddress(pagePath string, coords Coordinates) (PageAddress, error)

NewPageAddress maps a page and its mount coordinates to every address it has.

pagePath is the mount-relative HTML path, e.g. "guide/index.html". It must be relative, non-empty, and must not start with the reserved archive segment "v/".

#PageAddress.URL

Go go
func (a PageAddress) URL() string

URL is the URL path this page is actually emitted at.

#PageAddress.StableMount

Go go
func (a PageAddress) StableMount() string

StableMount is the version-free mount: where the current version's pages sit.

#PageAddress.ArchiveMount

Go go
func (a PageAddress) ArchiveMount() string

ArchiveMount is the mount superseded copies of this page's version sit under.

#PageAddress.ToSiteRoot

Go go
func (a PageAddress) ToSiteRoot() string

ToSiteRoot is the relative hop from this page's directory to the output root.

#PageAddress.ToMountRoot

Go go
func (a PageAddress) ToMountRoot() string

ToMountRoot is the relative hop from this page's directory to its own mount root.

#PageAddress.ToStableMountRoot

Go go
func (a PageAddress) ToStableMountRoot() string

ToStableMountRoot is the relative hop from this page's directory to the version-free mount.

On a page emitted at the stable address this is the same hop as [PageAddress.ToMountRoot]. On an archive page it climbs two levels further, over "v//".

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search