Summary
Two issues in the static-asset serving path, both in serve.ts:
- Static asset guard shadows dynamic routes containing a dot.
isAssetPath (src/serve.ts:39-41) is extname(pathname) !== "". When assets.root is configured, any GET/HEAD path containing a . is intercepted before application routing (serve.ts:100-158), and a missing file returns a 404 "without falling through to application routing" (confirmed at serve.ts:136-144, matches README:104-106). A route like /files/{name}.json or any dynamic segment that happens to contain a dot becomes permanently unreachable the moment static assets are enabled — with no per-route opt-out. The README documents the 404-without-fallthrough behavior but never mentions this collision with dynamic routing.
- Content-type sniffing is duplicated and can diverge.
serve.ts:81-96 hand-rolls a regex (/^text\/html(?:;|$)/iu) to decide whether to inject cache-control: no-cache, instead of using askr-server's existing contentType/accepts helpers (@askrjs/server's src/http/media-types.ts). Two independently-maintained content-type parsers increase the chance of divergent edge-case handling (parameters, casing) between the two packages.
Requirements
- Provide a way to exclude specific paths/patterns from the static-asset intercept (e.g. an
assets.exclude option, or check application routes for a match before falling back to the 404-and-stop behavior).
- Document the dot-path collision explicitly in the README until/unless the opt-out exists.
- Replace the hand-rolled content-type regex with
@askrjs/server's existing content-type parsing utility.
Acceptance Criteria
Steps to Reproduce
- Configure
assets.root pointing at a static directory.
- Define an application route
GET /files/:name.json (or any path with a literal dot).
- Request
/files/report.json.
- Observe: intercepted by the asset guard, 404s (file not found under
assets.root), application handler is never reached.
Summary
Two issues in the static-asset serving path, both in
serve.ts:isAssetPath(src/serve.ts:39-41) isextname(pathname) !== "". Whenassets.rootis configured, anyGET/HEADpath containing a.is intercepted before application routing (serve.ts:100-158), and a missing file returns a404"without falling through to application routing" (confirmed atserve.ts:136-144, matches README:104-106). A route like/files/{name}.jsonor any dynamic segment that happens to contain a dot becomes permanently unreachable the moment static assets are enabled — with no per-route opt-out. The README documents the 404-without-fallthrough behavior but never mentions this collision with dynamic routing.serve.ts:81-96hand-rolls a regex (/^text\/html(?:;|$)/iu) to decide whether to injectcache-control: no-cache, instead of usingaskr-server's existingcontentType/acceptshelpers (@askrjs/server'ssrc/http/media-types.ts). Two independently-maintained content-type parsers increase the chance of divergent edge-case handling (parameters, casing) between the two packages.Requirements
assets.excludeoption, or check application routes for a match before falling back to the 404-and-stop behavior).@askrjs/server's existing content-type parsing utility.Acceptance Criteria
/files/:name.json) is reachable even whenassets.rootis configured, either via an exclude option or via falling through to app routing on a static 404.assets.rootwon't be surprised.serve.ts's content-type check for the no-cache header uses the shared@askrjs/serverparser instead of a local regex.Steps to Reproduce
assets.rootpointing at a static directory.GET /files/:name.json(or any path with a literal dot)./files/report.json.assets.root), application handler is never reached.