Migrate lib from koa-router to @koa/router for Koa 3 support - #17
Open
ch-asimakopoulos wants to merge 1 commit into
Open
Migrate lib from koa-router to @koa/router for Koa 3 support#17ch-asimakopoulos wants to merge 1 commit into
ch-asimakopoulos wants to merge 1 commit into
Conversation
koa-router has been deprecated since v9 ("Please use @koa/router instead")
and its 7.x line predates Koa 3, declaring no support for it. @koa/router
15.7.0 supports koa ^2.0.0 || ^3.0.0, so this unblocks consumers upgrading
to Koa 3 while remaining compatible with Koa 2.
All six router APIs apicco uses are unchanged between the two packages:
new Router(), router.use(), .post(), .get(), .routes() and
.allowedMethods({ throw, notImplemented, methodNotAllowed }). The only
production change is the require in build.js.
Also in this commit:
- engines.node was "~8.11.4", which is wrong on its own terms and below
@koa/router 15's ">= 20" floor. Set to ">=20".
- Added a koa peer range ("^2.0.0 || ^3.0.0"). apicco declared no koa peer
at all, so npm had no way to warn a consumer that the library only
supported Koa 2 — which is how this incompatibility stayed invisible.
- Fixed notImplemented: it called Boom.notImplemented() and discarded the
result, so the callback returned undefined and allowedMethods({throw:true})
threw undefined instead of a 501. Verified: an unimplemented method now
returns 501 rather than an opaque 500.
Verified against a live Koa 3 server: dotted action paths
(/api/v1/conversations.send) still route correctly under path-to-regexp 8,
ctx.router and ctx._matchedRoute are still set, and ctx.throw(406, ...) in
the accepts guard still works. Method-mismatch behaviour is unchanged (405
via a Boom-aware error handler).
The build.test.js snapshot captures the router's private structure, so it
was regenerated: the class is now RouterImplementation and the Layer fields
reshaped under path-to-regexp 8. Test suite: 9/9 passing.
Note on diff size: lib/package-lock.json was regenerated and migrated from
lockfileVersion 1 to 3, since it had not been rebuilt with a modern npm.
Happy to drop it from this PR if you would rather regenerate it yourselves.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nikoklis
approved these changes
Aug 11, 2026
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.
Why
koa-routerhas carried a deprecation notice since v9 — "Please use @koa/router instead" — and its7.xline predates Koa 3 entirely, declaring no support for it.@koa/router@15.7.0declareskoa: ^2.0.0 || ^3.0.0.This blocks consumers from upgrading Koa. Concretely: ravasaki is upgrading
@workablehr/orkafrom 4.4.0 to 5.2.2, which moves Koa 2 → 3 transitively. Every/api/v1route in ravasaki is mounted through apicco, so nothing in that upgrade can land until apicco runs on a Koa-3-compatible router.What changed
lib/build.jsrequire('koa-router')→require('@koa/router'), plus thenotImplementedfix belowlib/package.jsonkoa-router@^7.4.0→@koa/router@^15.7.0;engines.node~8.11.4→>=20; addedkoapeer rangelib/build.test.jstoBeInstanceOfassertion)lib/__snapshots__/build.test.js.snapAll six router APIs apicco uses are unchanged between the two packages:
new Router(),router.use(),.post(),.get(),.routes(), and.allowedMethods({ throw, notImplemented, methodNotAllowed }). The only production change is therequire.Two extras worth calling out explicitly:
engines.nodewas~8.11.4— wrong on its own terms today, and below@koa/router15's>= 20floor.koapeer range is now declared. apicco previously declared no koa peer at all, so npm had no way to warn a consumer that the library only supported Koa 2. That is how this incompatibility stayed invisible until someone tried the upgrade.Bug fixed along the way
allowedMethods.notImplementedwas written as:@koa/routertypes this as() => Error, so withthrow: trueit threwundefined. Dropping the braces fixes it. Measured against a live Koa 3 server with a Boom-aware error handler in front:POSTa known actionGETa POST-only actionPROPFIND(unimplemented method)Accept: text/plainThis bug is pre-existing and reproduces on
koa@2+koa-router@7too — it is not fallout from the router swap.Verification
Beyond the unit suite, I exercised the parts most likely to break on this jump against a real Koa 3 server:
@koa/router15 bringspath-to-regexp@8with its overhauled path syntax. apicco registers only literal paths (/api/v1/conversations.send,/api/v1/discovery) with no:paramsor wildcards, and dots are literal in v8.POST /api/v1/conversations.send→ 200, unknown action → 404.ctx.routerandctx._matchedRouteare still set — which is why three of the four passing behavioural tests needed no edits.ctx.throw(406, 'json only')in theacceptsguard still works under Koa 3's tightenedctx.throw(status, error, properties)signature.middleware.router = routerstill attaches.npm testinlib/: 9/9 passing. Before regenerating the snapshot it was 8/9, the only failure being the snapshot itself.Reviewer notes
lib/build.test.js:55snapshots the router's private structure, so the class name (Router→RouterImplementation) and everyLayerfield reshaped by path-to-regexp 8 show up. Worth considering separately: that test guarantees a failure on every future router bump while asserting nothing apicco actually promises — narrowing it to registered paths and methods would make the next upgrade a no-op.lib/package-lock.jsoninflates this diff. It was migrated fromlockfileVersion1 → 3, since it had not been rebuilt with a modern npm. Happy to drop it from this PR if you would rather regenerate it on your own npm version — notescripts/install.shusesnpm install(notnpm ci) and the publish workflow installs nothing, so it is not load-bearing either way.npm versionitself onmaster. Suggest minor (→1.5.0) when publishing, since this swaps a dependency major and raises the engines floor even though apicco's own API is untouched.🤖 Generated with Claude Code