Skip to main content

Module route_table

Module route_table 

Source
Expand description

The compiled route table (R898-F1 / W348 §2.2) — ONE ordered artifact per domain, rendered to both front doors.

§What this is, and what it replaces

DomainConfig.routes is the declaration; this module is the compilation of that declaration into the thing a door can execute: {path, mode, resolved origin, headers, auth} per entry, in manifest order. It is the widening of R746/R749-F3’s route_headers_json, which compiled the same table down to its header column and is live on yah.dev today (x-route-header-probe).

One producer, two renderers is the whole point. A per-path capability built into one door has to be built a second time the moment the domain flips front_door, and it does not merely cost twice — it evaporates, as /api/releases did when yah.dev went grey and MESOFACT_BACKEND_ORIGIN stopped executing with nothing anywhere reporting it (W348 §0.3, §2.3).

§The resolved origin is the only genuinely new datum

Everything else an entry carries is already in the manifest. The origin is not, and it is placement-time:

moderesolves toby
staticthe component’s asset origin (<cdn_base>/<service>/<env>)CdnPlacement::asset_origin
static + bucketthe bucket’s Worker R2 binding name — no placementr2_binding_name
backendthe deployed unit’s address, keyed by its mesh identityinner_door::component_workload_ident
redirectnothing — it carries its own target + status—

The declared origin field on RouteMode::Backend is deliberately NOT the answer: it is the Worker arm’s fetch() target and nothing reads it under passway (.yah/domains/api-noisetable-com.toml says so in its own words, in the noisetable camp). A table that echoed it would be wrong on the door that actually serves production.

So placement arrives as a RoutePlacement — the same shape InnerDoorPlan::routes_file already uses for upstream addresses, for the same reason: which node a unit landed on is not config. An unresolved origin is refused, never skipped — a dropped entry does not 503, it falls through to a shorter match (the catch-all, usually) and serves the wrong thing with a 200.

§Ordering and matching are pinned, not chosen here

Manifest order, first match wins, no merging across rules — R746 pinned it in TS (applyRouteHeaders, oss/mesofact/packages/mesofact-edge/src/router.ts) and R749-F3 carried it into Rust (mesofact::route_headers). One path has one entry, decided where the route was decided. The manifests already document it as their contract: noisetable-com.toml puts /app/* above /* precisely because of it.

matches_route_pattern is segment-aware for the same reason both of those are: a bare starts_with routes /application to the /app entry. It is a third copy of a two-sided wire format rather than a call into either — the Worker is TypeScript and mesofact is a separately-released crate in another workspace that cloud does not depend on — and it is handled the way this repo already handles that risk for passway’s path_route::mount_from_component: one producer, and a test pinning the shared cases.

§Why the header projection is still the wire value

RouteTable::headers_json is the header column of this same table, byte- identical to what DomainConfig::route_headers_json emits — and that string, not the full table, is still what ROUTE_HEADERS / MESOFACT_ROUTE_HEADERS carry. Widening those bindings is R898-F2 (passway) and R898-F3 (Worker). Shipping the wide table into them here would change deployed behaviour before either consumer can read it: every headerless route becomes a table entry, so app.yah.dev, chat.yah.dev and scrabcake.net.yah.dev — each a single route declaring no headers, each "[]" today — would start setting MESOFACT_ROUTE_HEADERS on their deploys.

§A backend entry carries its prefix rewrite (R898-F3)

The two backend seams that exist today are not identity proxies: /api/issues/42 reaches the issue tracker as /issues/42, and /api/releases/v1.2.3 reaches the almanac as /releases/v1.2.3. Those rewrites lived inside the Worker’s two hardcoded if blocks (R455-T4), which is precisely what R898-F3 deleted — so an origin-only entry would have silently started proxying /api/issues to <origin>/api/issues and changed the upstream contract with no diff naming it.

So ResolvedRouteMode::Backend carries an optional RouteRewrite: {from, to}, the public prefix the matched path carries and what it becomes at the origin. It is route DATA, declared as origin_path on RouteMode::Backend — not an escape hatch, and not a per-door special case. The alternative was restating the two routes so the public path equals the origin path, which this repo cannot do: it does not own either upstream’s path layout, and both are live contracts.

§R560-F13 folds in here

“One Worker domain fronting several R2 buckets” is this table restricted to static entries whose sources differ. Same artifact, narrower slice — W279 Gap C predicted the fold (“path-prefix -> bucket is just a route list”).

A bucket route does NOT resolve to an HTTP origin, and that is the one deliberate asymmetry: the buckets it exists for (noisetable-releases) have no public hostname to fetch, and a bucket root is not a placement fact anyway — the manifest names it outright. So RouteMode::StaticBucket compiles to ResolvedRouteMode::StaticBucket, carrying the Worker binding it reads through (r2_binding_name), and the Worker’s binding set gains one R2 bucket binding per distinct bucket (r2_bucket_bindings), derived from the same entries the table ships so the two cannot name different bindings. The key is the request path minus its leading slash, unchanged: xlb derives a blob’s key from the URL path it serves at.

Structs§

CdnPlacement
The origin resolution that exists today: the CDN prefix for static routes, and a mesh-identity-keyed address map for backend ones.
RouteRewrite
The prefix swap a backend route performs on its way to the origin.
RouteTable
A domain’s routes, compiled and resolved, in manifest order.
RouteTableEntry
One entry of the compiled table.
WorkerPlacement
The Worker arm’s placement (R898-F3).

Enums§

ResolvedRouteMode
A compiled entry’s body — the declared RouteMode with its origin resolved.
RouteAuth
Whether a path reaching this entry has to carry a bearer.
WorkerAssets
How the Worker arm resolves a static route’s origin (R898-T4).

Traits§

RoutePlacement
The placement-time facts a declared route cannot answer about itself.

Functions§

matches_route_pattern
true when path is served by pattern.
r2_binding_name
The Worker binding name a bucket route reads its bucket through: noisetable-releases → R2_NOISETABLE_RELEASES.
r2_bucket_bindings
One R2 bucket binding per DISTINCT bucket the entries read, in first-use (manifest) order: (binding name, bucket name).
route_table_for_service
The route-driven domain routing service, compiled against placement.