Repository navigation
feat!: restana 7.0 – trie router, consistent errors, typed params, 100% coverage - #128
Merged
Merged
Conversation
- res.send(undefined, code) and promises resolving to undefined keep the explicit status code - non-numeric error codes (e.g. 'ENOENT') no longer mask a valid err.statusCode - APM instrumentation names multi-path routes per path - expose runtime Protocol/Method objects matching the TypeScript enums - type variadic use() middlewares; drop the unsupported prefix-less use(router) - add .nvmrc Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2wFkaGAAWQhBw9VtCu7qe
- add router option ('trie' default, 'sequential' opt-out)
- add caseSensitive and ignoreTrailingSlash options for the trie router
- benchmark both routers in CI and route-scale suites
- document intentional trie vs sequential matching differences
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2wFkaGAAWQhBw9VtCu7qe
BREAKING CHANGES: - the default errorHandler responds like res.send(err): standard status texts, debugErrors support, safe wrapping of non-Error values - res.send(number) only treats integers from 100 to 999 as status codes; other numbers are serialized as JSON - package exports map restricts imports to the public entry points - TypeScript: chaining returns the receiver, readonly config snapshot and errorHandler, required Router.id - trie router default (from the previous commit) Also adds APM type declarations, a 6.x to 7.0 migration guide, and updates the changelog, docs, README and landing page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2wFkaGAAWQhBw9VtCu7qe
- load the sequential router on demand (about 40% faster require, about 0.5MB less heap) - avoid a per-response 'finish' listener in res.send() when no callback is given - resolve security header options once per service - infer req.params from route paths and expose RouteParams<Path> - document TypeScript usage and the performance changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2wFkaGAAWQhBw9VtCu7qe
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2wFkaGAAWQhBw9VtCu7qe
- cover lifecycle failures, stream error paths, promise depth cap, security header edge cases and configuration snapshot cloning - fix res.send() with functions, symbols and bigints: respond with 500 instead of treating a function as the res.end() callback (empty 200) - enforce 99% statements, branches, functions and lines in npm test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2wFkaGAAWQhBw9VtCu7qe
Add release cards for typed route params, faster startup and response fixes, and drop stale sequential-router and dependency-count claims. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Major release (7.0.0). It contains breaking changes, and
MIGRATION.mdexplains how to upgrade from 6.x. In short:res.send(err).req.paramsis typed from the route path.Breaking changes
caseSensitive: false, orrouter: 'sequential'routerCacheSizeonly applies to the sequential router.router: 'sequential'errorHandlerresponds likeres.send(err): a 404 saysNot Foundinstead ofInternal Server Error, anddebugErrorsnow applies to it. Values that aren'tErrorobjects are wrapped so they can't leak.errorHandler(snippet in MIGRATION.md)res.send(number): only whole numbers from 100 to 999 are status codes. Other numbers are sent as JSON instead of being dropped.res.send()with a function, symbol or bigint responds with a 500. A function used to be treated as theres.end()callback, which sent an empty 200.exportsmap limits imports torestana,restana/libs/elastic-apm,restana/libs/newrelic-apmandrestana/package.json.get/post/…/use()return the object they were called on.getConfigOptions()returns a read-only object anderrorHandleris read-only.use(router)without a prefix is rejected because it already threw at runtime.Fixes
res.send(undefined, 201)andres.send(Promise.resolve(), 204)keep the status code that was passed in. Before, it was replaced with 200.'ENOENT'no longer hides a validerr.statusCode. Before, those errors came back as 500 instead of 404.restana.Protocolandrestana.Methodnow exist at runtime. The type definitions declared them, but they wereundefined.GET /a,/b.Added
router('trie'by default, or'sequential'), pluscaseSensitiveandignoreTrailingSlash.req.paramsis typed from the route path:'/users/:id'givesreq.params.id. A newrestana.RouteParams<Path>type covers handlers declared separately. Other keys are still typed asstring, so existing code compiles unchanged.use()accepts several middlewares in one call..nvmrcset to Node 26, the latest stable release. The minimum stays Node 24 LTS.Performance
I profiled first. Under load, restana's own code is only about 2–3% of CPU, and Node's I/O takes most of the rest, so these changes target what the profile showed:
router: 'sequential'is chosen.require('restana')drops from about 16 ms to 9 ms, the heap starts about 0.5 MB smaller, and a default install loads no third-party packages.res.send(): it no longer adds afinishlistener to every response when no callback is given.Benchmarks: the server was pinned to 1 core and autocannon to the other 3, with 100 connections. Numbers are medians in requests per second; run-to-run noise is about ±8%.
/hi6.1 → 7.0 (alternating rounds)The trie router is about 2.5× faster than the cached sequential router when timing route lookups alone, and it doesn't need a cache. The CI benchmark now checks both routers against plain 0http. Node 26 is the fastest runtime measured.
Tests
npm testnow fails below 99%. Before this PR the threshold was 95% of lines only.specs/edge-cases.test.jscoversstart()/close()failures, stream errors, the promise depth limit, security header edge cases and config cloning.specs/release-7.0.test.jscovers the new 7.0 behavior.specs/router-selection.test.jscovers choosing between the two routers.specs/bugfixes.test.jscovers the fixes listed above.npm audit --omit=devreports 0 vulnerabilities.200at the end of that tick even thoughres.headersSentstill readsfalse. A stream that fails later therefore can't turn into a connection reset on Bun. The two affected tests check restana's own behavior (the response is destroyed) on every runtime and only check for the connection reset on Node.Docs
MIGRATION.md: new upgrade guide from 6.x to 7.0.CHANGELOG.md: new 7.0.0 entry.docs/README.md:README.md: 7.0 highlights.CONTRIBUTING.md: the coverage requirement.docs/index.html: v7.0 labels, new release cards, and the new router options in the configuration table.Not included
prioRequestsProcessingstill defaults totrue, which measured faster thanfalsein every round.package.jsonversion is 7.0.0. Nothing has been published to npm or tagged.Generated by Claude Code