hostable
@johnhenry/hostable describes an API gateway as JSX — routing across
multiple domains and backend services by Host header, on top of
servable’s single-app (Request) => Response dispatcher.
hostable is the third package in the fileable -> servable -> hostable
lineage: fileable compiles JSX into filesystem artifacts,
servable compiles JSX into one app’s dispatcher, and hostable is the
layer above that — routing across a fleet of apps and backends,
addressed by domain as well as path. It has a real npm dependency on
@johnhenry/servable, not just a thematic relationship: Group/Host/
Route/Use/ErrorBoundary/NotFound/Redirect/Response are all
re-exported from servable directly, unchanged.
The governing rule
Section titled “The governing rule”A gateway matches by domain (
Host) before path (Group/Route) —Hostcompiles into the sameURLPatternhostnamecomponent thatGroup’s prefix already uses forpathname, soHost/Group/Routetogether are one flat, first-match-wins dispatch table, not a two-phase lookup. A leaf either handles the request itself (Route, reused verbatim from servable) or forwards it elsewhere (Upstream, hostable’s one new leaf) — forwarding is always a leaf, never a wrapper, exactly likeRouteis always a leaf.
Install
Section titled “Install”npm install @johnhenry/hostableQuick example
Section titled “Quick example”/** @jsxImportSource @johnhenry/hostable */import { Gateway, Host, Route, Upstream, compile } from "@johnhenry/hostable";
const gateway = ( <Gateway> <Host name="a.example.com"> <Route path="/health" method="GET">{{ ok: true }}</Route> <Upstream path="/*" url="https://backend-a:3000" /> </Host> <Host name="b.example.com"> <Upstream path="/*" url="https://backend-b:3000" /> </Host> </Gateway>);
const compiled = await compile(gateway);Primitives
Section titled “Primitives”Mostly reused, not reimplemented — @johnhenry/servable is a real
dependency, and everything except Gateway/Upstream is a direct
re-export from it. Host — the domain-axis scope this package is named
after — used to be implemented here as a hostable-only pre-transform; it’s
a genuine servable primitive now (see servable’s own API
and Adding a new primitive for the full
writeup, including the real cross-Host leak bug that move fixed).
One genuinely new primitive, Upstream — “forward it there” — with three
mutually exclusive forwarding modes (url=, app=, handler=) and its
own ipfs:// upstream support. See API for the full
reference.
The pages here
Section titled “The pages here”- API —
Upstream’s forwarding modes,ipfs://upstreams, ecosystem integration (dialback, browsermesh), adapters, non-goals - Literal cross-package JSX — writing fileable, servable, and hostable’s tags in one nested JSX expression
- Adding a new primitive — why this
package almost never needs a new tag, and the
ipfs://worked example
License
Section titled “License”MIT