Route Registry#
The route registry is the mechanism that maps route modules in lib/routes/ into a live Hono application. It has three environment-specific modes, a shared helper layer, and a build-time serialization step.
Core Files#
| File | Role |
|---|---|
lib/registry.ts | Entry point — selects the right loading strategy and mounts all routes onto the Hono app |
lib/registry-helpers.ts | Shared logic: NamespacesType, applyModulesToNamespaces, registerRssRoutes, registerApiRoutes, sortRoutes |
lib/registry-dev.ts | Dev-only lazy loader using a per-top-directory sub-app strategy |
scripts/workflow/build-routes.ts | Build-time script that serializes all namespaces to assets/build/routes.js |
Environment Modes#
registry.ts branches on NODE_ENV / VERCEL_ENV :
production/config.isPackage— eagerly imports the pre-builtassets/build/routes.js. Route handlers are stubs; the real handler is loaded lazily on first request via amodule()thunk injected at build time .test— importsassets/build/routes.json(JSON, no thunks). Missing handlers are re-imported directly by path at request time .default(dev) — creates aDevRegistryviacreateDevRegistry()instead of pre-loading all routes .
Dev Registry (registry-dev.ts)#
Dev mode cannot register all routes upfront because Hono freezes its router after the first matched request ("matcher is already built") . The solution:
- On startup,
readdirSyncthelib/routes/directory once to enumerate top-level directories . - Each top-level directory gets its own isolated
Honosub-app, built on first request for that namespace vialoadTopDirectory(). Sub-apps are memoized in aMap<string, Promise<Hono>>. loadTopDirectorycallsdirectoryImportto bulk-import all.ts/.tsxfiles in that directory, then callsapplyModulesToNamespaces+registerRssRoutes+registerApiRoutes.- The outer middleware inspects the first path segment to pick the right sub-app and bridges context variables between the outer and inner Hono instances .
ensureAllLoaded()is exported so the build script can force-load every directory before serialization .
Namespace and Route Resolution (registry-helpers.ts)#
Route modules are organized into namespaces. A directory under lib/routes/ is a namespace root when it contains a namespace.ts file . Each module is assigned to its longest matching namespace root; modules with no matching root fall back to their first path segment .
applyModulesToNamespaces merges imported modules into the NamespacesType record. A module may export { route }, { apiRoute }, or { namespace } .
Route registration order matters. sortRoutes prioritizes literal path segments over parameter segments (:param), and regex-constrained parameters over plain ones . Namespaces are registered deepest-first so parent param-routes cannot shadow nested namespaces .
Build-Time Serialization (scripts/workflow/build-routes.ts)#
Run via pnpm build:routes (cross-env NODE_ENV=dev tsx scripts/workflow/build-routes.ts) .
The script :
- Calls
ensureAllLoaded()to fully populatenamespacesvia the dev registry. - Injects a
modulethunk string (() => import('@/routes/<ns>/<location>')) onto each route/apiRoute . These string literals are embedded verbatim in the output JS using a regex replacement, so they become real dynamicimport()calls in production. - Writes output to
assets/build/:routes.js— default export with module thunks (production)routes.json— plain JSON without thunks (test/tooling)radar-rules.json/radar-rules.js— browser-extension radar rulesmaintainers.json— maintainer indexroute-paths.ts— auto-generated TypeScript union typeRoutePath
A Worker-specific variant (WORKER_BUILD=true) writes routes-worker.js instead .
CI: Build Assets Workflow#
The build-assets.yml workflow triggers on every push to master that touches lib/**/*.ts(x). It runs pnpm build (which runs build:routes then tsdown), commits the assets/ output to the gh-pages branch, and then syncs docs artifacts to the RSSNext/rsshub-docs repository.
NSFW Filtering#
After namespaces are loaded (in non-dev modes), registry.ts applies safeNamespaces() if config.feature.disable_nsfw is set, stripping any namespace where every route carries features.nsfw .