0.6.1: the download routes actually match
The resume downloads actually match (#35)
0.6.0 announced downloads and served none of them. Every URL 404'd on the live board:
GET /candidates/<slug>/resume.md 404
GET /candidates/<slug>/resume.html 404
GET /candidates/<slug>/resume.docx 404
GET /candidates/<slug>/resume.pdf 404
Not a stale deploy: /.well-known/agenticjobs reported 0.6.0, the filter work shipped in the same release rendered correctly on the same pages, and the route was right there in the running source.
All four were registered as one route:
pages.get('/candidates/:slug/resume.:format{md|html|pdf|docx}', …)A literal prefix (resume.) in the same path segment as a regex-constrained parameter is a RegExpRouter feature. Hono's default is SmartRouter, which falls back to TrieRouter for the whole router the moment any one route is beyond RegExpRouter, and TrieRouter does not support that combination. On hono 4.13.7, asked for /candidates/ada/resume.md:
RegExpRouter -> 1 handler
TrieRouter -> 0 handlers
and on this repo's own router, with nothing mounted:
pageRoutes().router.match('GET', '/candidates/ada/resume.md') -> 0 handlers
pageRoutes().router.match('GET', '/candidates/ada') -> 1 handler
The handler was correct throughout. The URL simply reached nothing.
Four literal routes now, one per extension, delegating to one handler. The URLs are unchanged, so the buttons 0.6.0 put on the candidate page work as written.
Why it survived review, which is the part worth carrying: a small throwaway app written to reproduce this resolves to RegExpRouter and answers 200. The pattern only fails in a router large enough to have been pushed onto TrieRouter, so the obvious repro exonerates it.
test/routing.test.ts therefore asks pageRoutes().router directly rather than making a request: no database, no app, and no parent whose own router might differ. It pins the RegExpRouter/TrieRouter difference too, so if a future hono teaches TrieRouter this pattern the test says so.
Full changelog: v0.6.0...v0.6.1