@nocobase/plugin-idp-oauth 2.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/LICENSE.txt +107 -0
  2. package/README.md +14 -0
  3. package/build.config.ts +46 -0
  4. package/client.d.ts +2 -0
  5. package/client.js +1 -0
  6. package/dist/client/ErrorPage.d.ts +11 -0
  7. package/dist/client/InteractionPage.d.ts +11 -0
  8. package/dist/client/index.d.ts +9 -0
  9. package/dist/client/index.js +10 -0
  10. package/dist/client/locale.d.ts +10 -0
  11. package/dist/client/models/index.d.ts +11 -0
  12. package/dist/client/plugin.d.ts +13 -0
  13. package/dist/externalVersion.js +18 -0
  14. package/dist/index.d.ts +10 -0
  15. package/dist/index.js +48 -0
  16. package/dist/locale/en-US.json +1 -0
  17. package/dist/locale/zh-CN.json +1 -0
  18. package/dist/node_modules/eta/LICENSE +7 -0
  19. package/dist/node_modules/eta/README.md +185 -0
  20. package/dist/node_modules/eta/dist/core.d.ts +179 -0
  21. package/dist/node_modules/eta/dist/core.d.ts.map +1 -0
  22. package/dist/node_modules/eta/dist/core.js +42 -0
  23. package/dist/node_modules/eta/dist/core.js.map +1 -0
  24. package/dist/node_modules/eta/dist/index.cjs +542 -0
  25. package/dist/node_modules/eta/dist/index.cjs.map +1 -0
  26. package/dist/node_modules/eta/dist/index.d.cts +187 -0
  27. package/dist/node_modules/eta/dist/index.d.cts.map +1 -0
  28. package/dist/node_modules/eta/dist/index.d.mts +187 -0
  29. package/dist/node_modules/eta/dist/index.d.mts.map +1 -0
  30. package/dist/node_modules/eta/dist/index.mjs +512 -0
  31. package/dist/node_modules/eta/dist/index.mjs.map +1 -0
  32. package/dist/node_modules/eta/package.json +75 -0
  33. package/dist/node_modules/jose/LICENSE.md +21 -0
  34. package/dist/node_modules/jose/README.md +153 -0
  35. package/dist/node_modules/jose/dist/types/index.d.ts +55 -0
  36. package/dist/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +31 -0
  37. package/dist/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +65 -0
  38. package/dist/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +31 -0
  39. package/dist/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +83 -0
  40. package/dist/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +38 -0
  41. package/dist/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +74 -0
  42. package/dist/node_modules/jose/dist/types/jwk/embedded.d.ts +17 -0
  43. package/dist/node_modules/jose/dist/types/jwk/thumbprint.d.ts +32 -0
  44. package/dist/node_modules/jose/dist/types/jwks/local.d.ts +29 -0
  45. package/dist/node_modules/jose/dist/types/jwks/remote.d.ts +237 -0
  46. package/dist/node_modules/jose/dist/types/jws/compact/sign.d.ts +36 -0
  47. package/dist/node_modules/jose/dist/types/jws/compact/verify.d.ts +33 -0
  48. package/dist/node_modules/jose/dist/types/jws/flattened/sign.d.ts +42 -0
  49. package/dist/node_modules/jose/dist/types/jws/flattened/verify.d.ts +33 -0
  50. package/dist/node_modules/jose/dist/types/jws/general/sign.d.ts +53 -0
  51. package/dist/node_modules/jose/dist/types/jws/general/verify.d.ts +41 -0
  52. package/dist/node_modules/jose/dist/types/jwt/decrypt.d.ts +35 -0
  53. package/dist/node_modules/jose/dist/types/jwt/encrypt.d.ts +91 -0
  54. package/dist/node_modules/jose/dist/types/jwt/sign.d.ts +43 -0
  55. package/dist/node_modules/jose/dist/types/jwt/unsecured.d.ts +43 -0
  56. package/dist/node_modules/jose/dist/types/jwt/verify.d.ts +37 -0
  57. package/dist/node_modules/jose/dist/types/key/export.d.ts +33 -0
  58. package/dist/node_modules/jose/dist/types/key/generate_key_pair.d.ts +47 -0
  59. package/dist/node_modules/jose/dist/types/key/generate_secret.d.ts +35 -0
  60. package/dist/node_modules/jose/dist/types/key/import.d.ts +83 -0
  61. package/dist/node_modules/jose/dist/types/types.d.ts +852 -0
  62. package/dist/node_modules/jose/dist/types/util/base64url.d.ts +9 -0
  63. package/dist/node_modules/jose/dist/types/util/decode_jwt.d.ts +18 -0
  64. package/dist/node_modules/jose/dist/types/util/decode_protected_header.d.ts +17 -0
  65. package/dist/node_modules/jose/dist/types/util/errors.d.ts +213 -0
  66. package/dist/node_modules/jose/dist/webapi/index.js +32 -0
  67. package/dist/node_modules/jose/dist/webapi/jwe/compact/decrypt.js +27 -0
  68. package/dist/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +27 -0
  69. package/dist/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +155 -0
  70. package/dist/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +165 -0
  71. package/dist/node_modules/jose/dist/webapi/jwe/general/decrypt.js +31 -0
  72. package/dist/node_modules/jose/dist/webapi/jwe/general/encrypt.js +182 -0
  73. package/dist/node_modules/jose/dist/webapi/jwk/embedded.js +17 -0
  74. package/dist/node_modules/jose/dist/webapi/jwk/thumbprint.js +68 -0
  75. package/dist/node_modules/jose/dist/webapi/jwks/local.js +119 -0
  76. package/dist/node_modules/jose/dist/webapi/jwks/remote.js +179 -0
  77. package/dist/node_modules/jose/dist/webapi/jws/compact/sign.js +18 -0
  78. package/dist/node_modules/jose/dist/webapi/jws/compact/verify.js +21 -0
  79. package/dist/node_modules/jose/dist/webapi/jws/flattened/sign.js +89 -0
  80. package/dist/node_modules/jose/dist/webapi/jws/flattened/verify.js +110 -0
  81. package/dist/node_modules/jose/dist/webapi/jws/general/sign.js +70 -0
  82. package/dist/node_modules/jose/dist/webapi/jws/general/verify.js +24 -0
  83. package/dist/node_modules/jose/dist/webapi/jwt/decrypt.js +23 -0
  84. package/dist/node_modules/jose/dist/webapi/jwt/encrypt.js +101 -0
  85. package/dist/node_modules/jose/dist/webapi/jwt/sign.js +52 -0
  86. package/dist/node_modules/jose/dist/webapi/jwt/unsecured.js +63 -0
  87. package/dist/node_modules/jose/dist/webapi/jwt/verify.js +15 -0
  88. package/dist/node_modules/jose/dist/webapi/key/export.js +11 -0
  89. package/dist/node_modules/jose/dist/webapi/key/generate_key_pair.js +97 -0
  90. package/dist/node_modules/jose/dist/webapi/key/generate_secret.js +40 -0
  91. package/dist/node_modules/jose/dist/webapi/key/import.js +57 -0
  92. package/dist/node_modules/jose/dist/webapi/lib/aesgcmkw.js +15 -0
  93. package/dist/node_modules/jose/dist/webapi/lib/aeskw.js +25 -0
  94. package/dist/node_modules/jose/dist/webapi/lib/asn1.js +243 -0
  95. package/dist/node_modules/jose/dist/webapi/lib/base64.js +22 -0
  96. package/dist/node_modules/jose/dist/webapi/lib/buffer_utils.js +43 -0
  97. package/dist/node_modules/jose/dist/webapi/lib/check_key_type.js +122 -0
  98. package/dist/node_modules/jose/dist/webapi/lib/content_encryption.js +217 -0
  99. package/dist/node_modules/jose/dist/webapi/lib/crypto_key.js +136 -0
  100. package/dist/node_modules/jose/dist/webapi/lib/deflate.js +44 -0
  101. package/dist/node_modules/jose/dist/webapi/lib/ecdhes.js +52 -0
  102. package/dist/node_modules/jose/dist/webapi/lib/helpers.js +19 -0
  103. package/dist/node_modules/jose/dist/webapi/lib/invalid_key_input.js +27 -0
  104. package/dist/node_modules/jose/dist/webapi/lib/is_key_like.js +17 -0
  105. package/dist/node_modules/jose/dist/webapi/lib/jwk_to_key.js +107 -0
  106. package/dist/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +238 -0
  107. package/dist/node_modules/jose/dist/webapi/lib/key_management.js +186 -0
  108. package/dist/node_modules/jose/dist/webapi/lib/key_to_jwk.js +31 -0
  109. package/dist/node_modules/jose/dist/webapi/lib/normalize_key.js +166 -0
  110. package/dist/node_modules/jose/dist/webapi/lib/pbes2kw.js +39 -0
  111. package/dist/node_modules/jose/dist/webapi/lib/rsaes.js +24 -0
  112. package/dist/node_modules/jose/dist/webapi/lib/signing.js +68 -0
  113. package/dist/node_modules/jose/dist/webapi/lib/type_checks.js +40 -0
  114. package/dist/node_modules/jose/dist/webapi/lib/validate_algorithms.js +10 -0
  115. package/dist/node_modules/jose/dist/webapi/lib/validate_crit.js +33 -0
  116. package/dist/node_modules/jose/dist/webapi/util/base64url.js +30 -0
  117. package/dist/node_modules/jose/dist/webapi/util/decode_jwt.js +32 -0
  118. package/dist/node_modules/jose/dist/webapi/util/decode_protected_header.js +34 -0
  119. package/dist/node_modules/jose/dist/webapi/util/errors.js +99 -0
  120. package/dist/node_modules/jose/package.json +200 -0
  121. package/dist/node_modules/light-my-request/.gitattributes +2 -0
  122. package/dist/node_modules/light-my-request/.github/dependabot.yml +13 -0
  123. package/dist/node_modules/light-my-request/.github/stale.yml +21 -0
  124. package/dist/node_modules/light-my-request/.github/workflows/benchmark.yml +30 -0
  125. package/dist/node_modules/light-my-request/.github/workflows/ci.yml +23 -0
  126. package/dist/node_modules/light-my-request/LICENSE +32 -0
  127. package/dist/node_modules/light-my-request/benchmark/benchmark.js +164 -0
  128. package/dist/node_modules/light-my-request/build/build-validation.js +100 -0
  129. package/dist/node_modules/light-my-request/eslint.config.js +9 -0
  130. package/dist/node_modules/light-my-request/index.js +2 -0
  131. package/dist/node_modules/light-my-request/lib/config-validator.js +919 -0
  132. package/dist/node_modules/light-my-request/lib/form-data.js +79 -0
  133. package/dist/node_modules/light-my-request/lib/parse-url.js +47 -0
  134. package/dist/node_modules/light-my-request/lib/request.js +290 -0
  135. package/dist/node_modules/light-my-request/lib/response.js +240 -0
  136. package/dist/node_modules/light-my-request/node_modules/process-warning/.gitattributes +2 -0
  137. package/dist/node_modules/light-my-request/node_modules/process-warning/.github/dependabot.yml +13 -0
  138. package/dist/node_modules/light-my-request/node_modules/process-warning/.github/workflows/ci.yml +24 -0
  139. package/dist/node_modules/light-my-request/node_modules/process-warning/.taprc +2 -0
  140. package/dist/node_modules/light-my-request/node_modules/process-warning/benchmarks/warn.js +25 -0
  141. package/dist/node_modules/light-my-request/node_modules/process-warning/eslint.config.js +6 -0
  142. package/dist/node_modules/light-my-request/node_modules/process-warning/examples/example.js +11 -0
  143. package/dist/node_modules/light-my-request/node_modules/process-warning/index.js +124 -0
  144. package/dist/node_modules/light-my-request/node_modules/process-warning/package.json +73 -0
  145. package/dist/node_modules/light-my-request/node_modules/process-warning/test/emit-interpolated-string.test.js +29 -0
  146. package/dist/node_modules/light-my-request/node_modules/process-warning/test/emit-once-only.test.js +28 -0
  147. package/dist/node_modules/light-my-request/node_modules/process-warning/test/emit-reset.test.js +36 -0
  148. package/dist/node_modules/light-my-request/node_modules/process-warning/test/emit-set.test.js +30 -0
  149. package/dist/node_modules/light-my-request/node_modules/process-warning/test/emit-unlimited.test.js +37 -0
  150. package/dist/node_modules/light-my-request/node_modules/process-warning/test/index.test.js +99 -0
  151. package/dist/node_modules/light-my-request/node_modules/process-warning/test/issue-88.test.js +33 -0
  152. package/dist/node_modules/light-my-request/node_modules/process-warning/test/jest.test.js +22 -0
  153. package/dist/node_modules/light-my-request/node_modules/process-warning/test/no-warnings.test.js +80 -0
  154. package/dist/node_modules/light-my-request/node_modules/process-warning/types/index.d.ts +37 -0
  155. package/dist/node_modules/light-my-request/node_modules/process-warning/types/index.test-d.ts +36 -0
  156. package/dist/node_modules/light-my-request/package.json +1 -0
  157. package/dist/node_modules/light-my-request/test/async-await.test.js +55 -0
  158. package/dist/node_modules/light-my-request/test/index.test.js +2316 -0
  159. package/dist/node_modules/light-my-request/test/request.test.js +16 -0
  160. package/dist/node_modules/light-my-request/test/response.test.js +19 -0
  161. package/dist/node_modules/light-my-request/test/stream.test.js +359 -0
  162. package/dist/node_modules/light-my-request/types/index.d.ts +128 -0
  163. package/dist/node_modules/light-my-request/types/index.test-d.ts +149 -0
  164. package/dist/node_modules/oidc-provider/LICENSE.md +21 -0
  165. package/dist/node_modules/oidc-provider/README.md +174 -0
  166. package/dist/node_modules/oidc-provider/lib/actions/authorization/assign_claims.js +28 -0
  167. package/dist/node_modules/oidc-provider/lib/actions/authorization/assign_defaults.js +17 -0
  168. package/dist/node_modules/oidc-provider/lib/actions/authorization/authenticated_client_id.js +6 -0
  169. package/dist/node_modules/oidc-provider/lib/actions/authorization/backchannel_request_remap_errors.js +17 -0
  170. package/dist/node_modules/oidc-provider/lib/actions/authorization/backchannel_request_response.js +41 -0
  171. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_ciba_context.js +12 -0
  172. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_claims.js +68 -0
  173. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_client.js +21 -0
  174. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_client_grant_type.js +21 -0
  175. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_dpop_jkt.js +35 -0
  176. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_extra_params.js +18 -0
  177. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_id_token_hint.js +23 -0
  178. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_max_age.js +25 -0
  179. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_openid_scope.js +47 -0
  180. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_pkce.js +41 -0
  181. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_prompt.js +25 -0
  182. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_redirect_uri.js +41 -0
  183. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_requested_expiry.js +16 -0
  184. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_response_mode.js +54 -0
  185. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_response_type.js +26 -0
  186. package/dist/node_modules/oidc-provider/lib/actions/authorization/check_scope.js +53 -0
  187. package/dist/node_modules/oidc-provider/lib/actions/authorization/ciba_load_account.js +58 -0
  188. package/dist/node_modules/oidc-provider/lib/actions/authorization/ciba_required.js +13 -0
  189. package/dist/node_modules/oidc-provider/lib/actions/authorization/device_authorization_response.js +31 -0
  190. package/dist/node_modules/oidc-provider/lib/actions/authorization/device_user_flow.js +31 -0
  191. package/dist/node_modules/oidc-provider/lib/actions/authorization/device_user_flow_errors.js +37 -0
  192. package/dist/node_modules/oidc-provider/lib/actions/authorization/device_user_flow_response.js +55 -0
  193. package/dist/node_modules/oidc-provider/lib/actions/authorization/index.js +200 -0
  194. package/dist/node_modules/oidc-provider/lib/actions/authorization/interaction_emit.js +9 -0
  195. package/dist/node_modules/oidc-provider/lib/actions/authorization/interactions.js +149 -0
  196. package/dist/node_modules/oidc-provider/lib/actions/authorization/load_account.js +15 -0
  197. package/dist/node_modules/oidc-provider/lib/actions/authorization/load_grant.js +29 -0
  198. package/dist/node_modules/oidc-provider/lib/actions/authorization/load_pushed_authorization_request.js +36 -0
  199. package/dist/node_modules/oidc-provider/lib/actions/authorization/oauth_required.js +11 -0
  200. package/dist/node_modules/oidc-provider/lib/actions/authorization/oidc_required.js +27 -0
  201. package/dist/node_modules/oidc-provider/lib/actions/authorization/one_redirect_uri_clients.js +20 -0
  202. package/dist/node_modules/oidc-provider/lib/actions/authorization/process_request_object.js +214 -0
  203. package/dist/node_modules/oidc-provider/lib/actions/authorization/pushed_authorization_request_remap_errors.js +17 -0
  204. package/dist/node_modules/oidc-provider/lib/actions/authorization/pushed_authorization_request_response.js +65 -0
  205. package/dist/node_modules/oidc-provider/lib/actions/authorization/reject_registration.js +12 -0
  206. package/dist/node_modules/oidc-provider/lib/actions/authorization/reject_request_and_uri.js +12 -0
  207. package/dist/node_modules/oidc-provider/lib/actions/authorization/reject_unsupported.js +33 -0
  208. package/dist/node_modules/oidc-provider/lib/actions/authorization/respond.js +46 -0
  209. package/dist/node_modules/oidc-provider/lib/actions/authorization/resume.js +111 -0
  210. package/dist/node_modules/oidc-provider/lib/actions/authorization/strip_outside_jar_params.js +19 -0
  211. package/dist/node_modules/oidc-provider/lib/actions/authorization/unsupported_rar.js +9 -0
  212. package/dist/node_modules/oidc-provider/lib/actions/challenge.js +22 -0
  213. package/dist/node_modules/oidc-provider/lib/actions/code_verification.js +122 -0
  214. package/dist/node_modules/oidc-provider/lib/actions/discovery.js +151 -0
  215. package/dist/node_modules/oidc-provider/lib/actions/end_session.js +222 -0
  216. package/dist/node_modules/oidc-provider/lib/actions/grants/authorization_code.js +144 -0
  217. package/dist/node_modules/oidc-provider/lib/actions/grants/ciba.js +127 -0
  218. package/dist/node_modules/oidc-provider/lib/actions/grants/client_credentials.js +79 -0
  219. package/dist/node_modules/oidc-provider/lib/actions/grants/device_code.js +125 -0
  220. package/dist/node_modules/oidc-provider/lib/actions/grants/index.js +7 -0
  221. package/dist/node_modules/oidc-provider/lib/actions/grants/refresh_token.js +229 -0
  222. package/dist/node_modules/oidc-provider/lib/actions/index.js +25 -0
  223. package/dist/node_modules/oidc-provider/lib/actions/interaction.js +150 -0
  224. package/dist/node_modules/oidc-provider/lib/actions/introspection.js +164 -0
  225. package/dist/node_modules/oidc-provider/lib/actions/jwks.js +7 -0
  226. package/dist/node_modules/oidc-provider/lib/actions/registration.js +274 -0
  227. package/dist/node_modules/oidc-provider/lib/actions/revocation.js +81 -0
  228. package/dist/node_modules/oidc-provider/lib/actions/token.js +74 -0
  229. package/dist/node_modules/oidc-provider/lib/actions/userinfo.js +183 -0
  230. package/dist/node_modules/oidc-provider/lib/adapters/memory_adapter.js +95 -0
  231. package/dist/node_modules/oidc-provider/lib/consts/client_attributes.js +211 -0
  232. package/dist/node_modules/oidc-provider/lib/consts/dev_keystore.js +18 -0
  233. package/dist/node_modules/oidc-provider/lib/consts/index.js +13 -0
  234. package/dist/node_modules/oidc-provider/lib/consts/jwa.js +47 -0
  235. package/dist/node_modules/oidc-provider/lib/consts/non_rejectable_claims.js +1 -0
  236. package/dist/node_modules/oidc-provider/lib/consts/param_list.js +23 -0
  237. package/dist/node_modules/oidc-provider/lib/helpers/_/camel_case.js +1 -0
  238. package/dist/node_modules/oidc-provider/lib/helpers/_/defaults.js +28 -0
  239. package/dist/node_modules/oidc-provider/lib/helpers/_/difference.js +1 -0
  240. package/dist/node_modules/oidc-provider/lib/helpers/_/is_plain_object.js +1 -0
  241. package/dist/node_modules/oidc-provider/lib/helpers/_/map_keys.js +9 -0
  242. package/dist/node_modules/oidc-provider/lib/helpers/_/merge.js +25 -0
  243. package/dist/node_modules/oidc-provider/lib/helpers/_/omit_by.js +11 -0
  244. package/dist/node_modules/oidc-provider/lib/helpers/_/pick.js +10 -0
  245. package/dist/node_modules/oidc-provider/lib/helpers/_/pick_by.js +10 -0
  246. package/dist/node_modules/oidc-provider/lib/helpers/_/remove.js +9 -0
  247. package/dist/node_modules/oidc-provider/lib/helpers/_/set.js +18 -0
  248. package/dist/node_modules/oidc-provider/lib/helpers/_/snake_case.js +1 -0
  249. package/dist/node_modules/oidc-provider/lib/helpers/_/upper_first.js +1 -0
  250. package/dist/node_modules/oidc-provider/lib/helpers/account_claims.js +6 -0
  251. package/dist/node_modules/oidc-provider/lib/helpers/add_client.js +14 -0
  252. package/dist/node_modules/oidc-provider/lib/helpers/als.js +3 -0
  253. package/dist/node_modules/oidc-provider/lib/helpers/append_www_authenticate.js +9 -0
  254. package/dist/node_modules/oidc-provider/lib/helpers/attention.js +23 -0
  255. package/dist/node_modules/oidc-provider/lib/helpers/base64url.js +11 -0
  256. package/dist/node_modules/oidc-provider/lib/helpers/certificate_thumbprint.js +15 -0
  257. package/dist/node_modules/oidc-provider/lib/helpers/challenge.js +111 -0
  258. package/dist/node_modules/oidc-provider/lib/helpers/check_attest_binding.js +10 -0
  259. package/dist/node_modules/oidc-provider/lib/helpers/claims.js +79 -0
  260. package/dist/node_modules/oidc-provider/lib/helpers/client_id_metadata_document.js +198 -0
  261. package/dist/node_modules/oidc-provider/lib/helpers/client_schema.js +700 -0
  262. package/dist/node_modules/oidc-provider/lib/helpers/combined_scope.js +17 -0
  263. package/dist/node_modules/oidc-provider/lib/helpers/configuration.js +544 -0
  264. package/dist/node_modules/oidc-provider/lib/helpers/constant_equals.js +20 -0
  265. package/dist/node_modules/oidc-provider/lib/helpers/defaults.js +3510 -0
  266. package/dist/node_modules/oidc-provider/lib/helpers/epoch_time.js +1 -0
  267. package/dist/node_modules/oidc-provider/lib/helpers/err_out.js +17 -0
  268. package/dist/node_modules/oidc-provider/lib/helpers/errors.js +161 -0
  269. package/dist/node_modules/oidc-provider/lib/helpers/features.js +51 -0
  270. package/dist/node_modules/oidc-provider/lib/helpers/fetch_body_check.js +25 -0
  271. package/dist/node_modules/oidc-provider/lib/helpers/fetch_request.js +221 -0
  272. package/dist/node_modules/oidc-provider/lib/helpers/filter_claims.js +16 -0
  273. package/dist/node_modules/oidc-provider/lib/helpers/formatters.js +24 -0
  274. package/dist/node_modules/oidc-provider/lib/helpers/grant_common.js +214 -0
  275. package/dist/node_modules/oidc-provider/lib/helpers/html_safe.js +19 -0
  276. package/dist/node_modules/oidc-provider/lib/helpers/initialize_adapter.js +24 -0
  277. package/dist/node_modules/oidc-provider/lib/helpers/initialize_app.js +243 -0
  278. package/dist/node_modules/oidc-provider/lib/helpers/initialize_clients.js +24 -0
  279. package/dist/node_modules/oidc-provider/lib/helpers/initialize_keystore.js +310 -0
  280. package/dist/node_modules/oidc-provider/lib/helpers/interaction_policy/check.js +21 -0
  281. package/dist/node_modules/oidc-provider/lib/helpers/interaction_policy/index.js +43 -0
  282. package/dist/node_modules/oidc-provider/lib/helpers/interaction_policy/prompt.js +95 -0
  283. package/dist/node_modules/oidc-provider/lib/helpers/interaction_policy/prompts/consent.js +105 -0
  284. package/dist/node_modules/oidc-provider/lib/helpers/interaction_policy/prompts/login.js +162 -0
  285. package/dist/node_modules/oidc-provider/lib/helpers/jwt.js +211 -0
  286. package/dist/node_modules/oidc-provider/lib/helpers/keystore.js +301 -0
  287. package/dist/node_modules/oidc-provider/lib/helpers/nanoid.js +5 -0
  288. package/dist/node_modules/oidc-provider/lib/helpers/oidc_context.js +284 -0
  289. package/dist/node_modules/oidc-provider/lib/helpers/params.js +27 -0
  290. package/dist/node_modules/oidc-provider/lib/helpers/pkce.js +30 -0
  291. package/dist/node_modules/oidc-provider/lib/helpers/pkce_format.js +17 -0
  292. package/dist/node_modules/oidc-provider/lib/helpers/process_response_types.js +202 -0
  293. package/dist/node_modules/oidc-provider/lib/helpers/re_render_errors.js +39 -0
  294. package/dist/node_modules/oidc-provider/lib/helpers/redirect_uri.js +16 -0
  295. package/dist/node_modules/oidc-provider/lib/helpers/resolve_resource.js +33 -0
  296. package/dist/node_modules/oidc-provider/lib/helpers/resolve_response_mode.js +7 -0
  297. package/dist/node_modules/oidc-provider/lib/helpers/resource_server.js +20 -0
  298. package/dist/node_modules/oidc-provider/lib/helpers/revoke.js +27 -0
  299. package/dist/node_modules/oidc-provider/lib/helpers/script_src_sha.js +21 -0
  300. package/dist/node_modules/oidc-provider/lib/helpers/sector_identifier.js +19 -0
  301. package/dist/node_modules/oidc-provider/lib/helpers/sector_validate.js +55 -0
  302. package/dist/node_modules/oidc-provider/lib/helpers/set_rt_bindings.js +21 -0
  303. package/dist/node_modules/oidc-provider/lib/helpers/token_find.js +51 -0
  304. package/dist/node_modules/oidc-provider/lib/helpers/type_validators.js +8 -0
  305. package/dist/node_modules/oidc-provider/lib/helpers/user_code_form.js +19 -0
  306. package/dist/node_modules/oidc-provider/lib/helpers/user_codes.js +38 -0
  307. package/dist/node_modules/oidc-provider/lib/helpers/valid_url.js +8 -0
  308. package/dist/node_modules/oidc-provider/lib/helpers/validate_dpop.js +129 -0
  309. package/dist/node_modules/oidc-provider/lib/helpers/validate_presence.js +17 -0
  310. package/dist/node_modules/oidc-provider/lib/helpers/weak_cache.js +11 -0
  311. package/dist/node_modules/oidc-provider/lib/index.js +21 -0
  312. package/dist/node_modules/oidc-provider/lib/models/access_token.js +31 -0
  313. package/dist/node_modules/oidc-provider/lib/models/authorization_code.js +27 -0
  314. package/dist/node_modules/oidc-provider/lib/models/backchannel_authentication_request.js +26 -0
  315. package/dist/node_modules/oidc-provider/lib/models/base_model.js +141 -0
  316. package/dist/node_modules/oidc-provider/lib/models/base_token.js +86 -0
  317. package/dist/node_modules/oidc-provider/lib/models/client.js +593 -0
  318. package/dist/node_modules/oidc-provider/lib/models/client_credentials.js +19 -0
  319. package/dist/node_modules/oidc-provider/lib/models/device_code.js +44 -0
  320. package/dist/node_modules/oidc-provider/lib/models/formats/dynamic.js +21 -0
  321. package/dist/node_modules/oidc-provider/lib/models/formats/index.js +14 -0
  322. package/dist/node_modules/oidc-provider/lib/models/formats/jwt.js +198 -0
  323. package/dist/node_modules/oidc-provider/lib/models/formats/opaque.js +58 -0
  324. package/dist/node_modules/oidc-provider/lib/models/grant.js +243 -0
  325. package/dist/node_modules/oidc-provider/lib/models/id_token.js +271 -0
  326. package/dist/node_modules/oidc-provider/lib/models/index.js +37 -0
  327. package/dist/node_modules/oidc-provider/lib/models/initial_access_token.js +12 -0
  328. package/dist/node_modules/oidc-provider/lib/models/interaction.js +73 -0
  329. package/dist/node_modules/oidc-provider/lib/models/mixins/apply.js +4 -0
  330. package/dist/node_modules/oidc-provider/lib/models/mixins/consumable.js +17 -0
  331. package/dist/node_modules/oidc-provider/lib/models/mixins/has_format.js +46 -0
  332. package/dist/node_modules/oidc-provider/lib/models/mixins/has_grant_id.js +12 -0
  333. package/dist/node_modules/oidc-provider/lib/models/mixins/has_grant_type.js +8 -0
  334. package/dist/node_modules/oidc-provider/lib/models/mixins/has_policies.js +38 -0
  335. package/dist/node_modules/oidc-provider/lib/models/mixins/is_attestation_constrained.js +15 -0
  336. package/dist/node_modules/oidc-provider/lib/models/mixins/is_sender_constrained.js +50 -0
  337. package/dist/node_modules/oidc-provider/lib/models/mixins/is_session_bound.js +38 -0
  338. package/dist/node_modules/oidc-provider/lib/models/mixins/set_audience.js +21 -0
  339. package/dist/node_modules/oidc-provider/lib/models/mixins/stores_auth.js +16 -0
  340. package/dist/node_modules/oidc-provider/lib/models/mixins/stores_pkce.js +9 -0
  341. package/dist/node_modules/oidc-provider/lib/models/pushed_authorization_request.js +21 -0
  342. package/dist/node_modules/oidc-provider/lib/models/refresh_token.js +47 -0
  343. package/dist/node_modules/oidc-provider/lib/models/registration_access_token.js +8 -0
  344. package/dist/node_modules/oidc-provider/lib/models/replay_detection.js +31 -0
  345. package/dist/node_modules/oidc-provider/lib/models/session.js +192 -0
  346. package/dist/node_modules/oidc-provider/lib/provider.js +453 -0
  347. package/dist/node_modules/oidc-provider/lib/response_modes/form_post.js +36 -0
  348. package/dist/node_modules/oidc-provider/lib/response_modes/fragment.js +7 -0
  349. package/dist/node_modules/oidc-provider/lib/response_modes/index.js +15 -0
  350. package/dist/node_modules/oidc-provider/lib/response_modes/jwt.js +43 -0
  351. package/dist/node_modules/oidc-provider/lib/response_modes/query.js +7 -0
  352. package/dist/node_modules/oidc-provider/lib/response_modes/web_message.js +55 -0
  353. package/dist/node_modules/oidc-provider/lib/shared/assemble_params.js +7 -0
  354. package/dist/node_modules/oidc-provider/lib/shared/attest_client_auth.js +111 -0
  355. package/dist/node_modules/oidc-provider/lib/shared/authorization_error_handler.js +104 -0
  356. package/dist/node_modules/oidc-provider/lib/shared/check_rar.js +75 -0
  357. package/dist/node_modules/oidc-provider/lib/shared/check_resource.js +77 -0
  358. package/dist/node_modules/oidc-provider/lib/shared/client_auth.js +263 -0
  359. package/dist/node_modules/oidc-provider/lib/shared/conditional_body.js +9 -0
  360. package/dist/node_modules/oidc-provider/lib/shared/cors.js +49 -0
  361. package/dist/node_modules/oidc-provider/lib/shared/error_handler.js +59 -0
  362. package/dist/node_modules/oidc-provider/lib/shared/jwt_client_auth.js +79 -0
  363. package/dist/node_modules/oidc-provider/lib/shared/no_cache.js +4 -0
  364. package/dist/node_modules/oidc-provider/lib/shared/reject_dupes.js +45 -0
  365. package/dist/node_modules/oidc-provider/lib/shared/reject_structured_tokens.js +18 -0
  366. package/dist/node_modules/oidc-provider/lib/shared/selective_body.js +60 -0
  367. package/dist/node_modules/oidc-provider/lib/shared/session.js +68 -0
  368. package/dist/node_modules/oidc-provider/lib/shared/set_www_authenticate_header.js +52 -0
  369. package/dist/node_modules/oidc-provider/lib/views/index.js +22 -0
  370. package/dist/node_modules/oidc-provider/lib/views/interaction.js +171 -0
  371. package/dist/node_modules/oidc-provider/lib/views/layout.js +237 -0
  372. package/dist/node_modules/oidc-provider/lib/views/login.js +43 -0
  373. package/dist/node_modules/oidc-provider/node_modules/@koa/router/LICENSE +21 -0
  374. package/dist/node_modules/oidc-provider/node_modules/@koa/router/README.md +1370 -0
  375. package/dist/node_modules/oidc-provider/node_modules/@koa/router/dist/index.d.mts +1003 -0
  376. package/dist/node_modules/oidc-provider/node_modules/@koa/router/dist/index.d.ts +1003 -0
  377. package/dist/node_modules/oidc-provider/node_modules/@koa/router/dist/index.js +1616 -0
  378. package/dist/node_modules/oidc-provider/node_modules/@koa/router/dist/index.mjs +1573 -0
  379. package/dist/node_modules/oidc-provider/node_modules/@koa/router/package.json +122 -0
  380. package/dist/node_modules/oidc-provider/node_modules/debug/LICENSE +20 -0
  381. package/dist/node_modules/oidc-provider/node_modules/debug/README.md +481 -0
  382. package/dist/node_modules/oidc-provider/node_modules/debug/package.json +64 -0
  383. package/dist/node_modules/oidc-provider/node_modules/debug/src/browser.js +272 -0
  384. package/dist/node_modules/oidc-provider/node_modules/debug/src/common.js +292 -0
  385. package/dist/node_modules/oidc-provider/node_modules/debug/src/index.js +10 -0
  386. package/dist/node_modules/oidc-provider/node_modules/debug/src/node.js +263 -0
  387. package/dist/node_modules/oidc-provider/node_modules/http-errors/HISTORY.md +186 -0
  388. package/dist/node_modules/oidc-provider/node_modules/http-errors/LICENSE +23 -0
  389. package/dist/node_modules/oidc-provider/node_modules/http-errors/README.md +169 -0
  390. package/dist/node_modules/oidc-provider/node_modules/http-errors/index.js +290 -0
  391. package/dist/node_modules/oidc-provider/node_modules/http-errors/package.json +54 -0
  392. package/dist/node_modules/oidc-provider/node_modules/jsesc/LICENSE-MIT.txt +20 -0
  393. package/dist/node_modules/oidc-provider/node_modules/jsesc/README.md +422 -0
  394. package/dist/node_modules/oidc-provider/node_modules/jsesc/bin/jsesc +148 -0
  395. package/dist/node_modules/oidc-provider/node_modules/jsesc/jsesc.js +337 -0
  396. package/dist/node_modules/oidc-provider/node_modules/jsesc/man/jsesc.1 +94 -0
  397. package/dist/node_modules/oidc-provider/node_modules/jsesc/package.json +56 -0
  398. package/dist/node_modules/oidc-provider/node_modules/nanoid/LICENSE +20 -0
  399. package/dist/node_modules/oidc-provider/node_modules/nanoid/README.md +38 -0
  400. package/dist/node_modules/oidc-provider/node_modules/nanoid/bin/nanoid.js +55 -0
  401. package/dist/node_modules/oidc-provider/node_modules/nanoid/index.browser.js +29 -0
  402. package/dist/node_modules/oidc-provider/node_modules/nanoid/index.d.ts +106 -0
  403. package/dist/node_modules/oidc-provider/node_modules/nanoid/index.js +47 -0
  404. package/dist/node_modules/oidc-provider/node_modules/nanoid/nanoid.js +1 -0
  405. package/dist/node_modules/oidc-provider/node_modules/nanoid/non-secure/index.d.ts +48 -0
  406. package/dist/node_modules/oidc-provider/node_modules/nanoid/non-secure/index.js +21 -0
  407. package/dist/node_modules/oidc-provider/node_modules/nanoid/package.json +46 -0
  408. package/dist/node_modules/oidc-provider/node_modules/nanoid/url-alphabet/index.js +2 -0
  409. package/dist/node_modules/oidc-provider/node_modules/path-to-regexp/LICENSE +21 -0
  410. package/dist/node_modules/oidc-provider/node_modules/path-to-regexp/Readme.md +224 -0
  411. package/dist/node_modules/oidc-provider/node_modules/path-to-regexp/dist/index.d.ts +144 -0
  412. package/dist/node_modules/oidc-provider/node_modules/path-to-regexp/dist/index.js +409 -0
  413. package/dist/node_modules/oidc-provider/node_modules/path-to-regexp/dist/index.js.map +1 -0
  414. package/dist/node_modules/oidc-provider/node_modules/path-to-regexp/package.json +64 -0
  415. package/dist/node_modules/oidc-provider/node_modules/statuses/HISTORY.md +87 -0
  416. package/dist/node_modules/oidc-provider/node_modules/statuses/LICENSE +23 -0
  417. package/dist/node_modules/oidc-provider/node_modules/statuses/README.md +139 -0
  418. package/dist/node_modules/oidc-provider/node_modules/statuses/codes.json +65 -0
  419. package/dist/node_modules/oidc-provider/node_modules/statuses/index.js +146 -0
  420. package/dist/node_modules/oidc-provider/node_modules/statuses/package.json +49 -0
  421. package/dist/node_modules/oidc-provider/package.json +95 -0
  422. package/dist/node_modules/quick-lru/index.d.ts +178 -0
  423. package/dist/node_modules/quick-lru/index.js +329 -0
  424. package/dist/node_modules/quick-lru/license +9 -0
  425. package/dist/node_modules/quick-lru/package.json +54 -0
  426. package/dist/node_modules/quick-lru/readme.md +236 -0
  427. package/dist/node_modules/statuses/HISTORY.md +65 -0
  428. package/dist/node_modules/statuses/LICENSE +23 -0
  429. package/dist/node_modules/statuses/README.md +127 -0
  430. package/dist/node_modules/statuses/codes.json +66 -0
  431. package/dist/node_modules/statuses/index.js +113 -0
  432. package/dist/node_modules/statuses/package.json +48 -0
  433. package/dist/server/cache-adapter.d.ts +33 -0
  434. package/dist/server/cache-adapter.js +159 -0
  435. package/dist/server/index.d.ts +10 -0
  436. package/dist/server/index.js +48 -0
  437. package/dist/server/interaction.d.ts +26 -0
  438. package/dist/server/interaction.js +172 -0
  439. package/dist/server/paths.d.ts +19 -0
  440. package/dist/server/paths.js +64 -0
  441. package/dist/server/plugin.d.ts +16 -0
  442. package/dist/server/plugin.js +108 -0
  443. package/dist/server/provider-dispatch.d.ts +32 -0
  444. package/dist/server/provider-dispatch.js +252 -0
  445. package/dist/server/service.d.ts +63 -0
  446. package/dist/server/service.js +540 -0
  447. package/dist/server/utils.d.ts +12 -0
  448. package/dist/server/utils.js +58 -0
  449. package/package.json +24 -0
  450. package/server.d.ts +2 -0
  451. package/server.js +1 -0
@@ -0,0 +1,1370 @@
1
+ # [@koa/router](https://github.com/koajs/router)
2
+
3
+ > Modern TypeScript Router middleware for [Koa](https://github.com/koajs/koa). Maintained by [Forward Email][forward-email] and [Lad][].
4
+
5
+ [![build status](https://github.com/koajs/router/actions/workflows/ci.yml/badge.svg)](https://github.com/koajs/router/actions/workflows/ci.yml)
6
+ [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
7
+ [![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)
8
+ [![license](https://img.shields.io/github/license/koajs/router.svg)](LICENSE)
9
+
10
+ ## Table of Contents
11
+
12
+ - [Features](#features)
13
+ - [Installation](#installation)
14
+ - [TypeScript Support](#typescript-support)
15
+ - [Quick Start](#quick-start)
16
+ - [API Documentation](#api-documentation)
17
+ - [Advanced Features](#advanced-features)
18
+ - [Best Practices](#best-practices)
19
+ - [Recipes](#recipes)
20
+ - [Performance](#performance)
21
+ - [Testing](#testing)
22
+ - [Migration Guides](#migration-guides)
23
+ - [Contributing](#contributing)
24
+ - [License](#license)
25
+ - [Contributors](#contributors)
26
+
27
+ ## Features
28
+
29
+ - ✅ **Full TypeScript Support** - Written in TypeScript with comprehensive type definitions
30
+ - ✅ **Express-Style Routing** - Familiar `app.get`, `app.post`, `app.put`, etc.
31
+ - ✅ **Named URL Parameters** - Extract parameters from URLs
32
+ - ✅ **Named Routes** - Generate URLs from route names
33
+ - ✅ **Host Matching** - Match routes based on hostname
34
+ - ✅ **HEAD Request Support** - Automatic HEAD support for GET routes
35
+ - ✅ **Multiple Middleware** - Chain multiple middleware functions
36
+ - ✅ **Nested Routers** - Mount routers within routers
37
+ - ✅ **RegExp Paths** - Use regular expressions for flexible path matching
38
+ - ✅ **Parameter Middleware** - Run middleware for specific URL parameters
39
+ - ✅ **Path-to-RegExp v8** - Modern, predictable path matching
40
+ - ✅ **405 Method Not Allowed** - Automatic method validation
41
+ - ✅ **501 Not Implemented** - Proper HTTP status codes
42
+ - ✅ **Async/Await** - Full promise-based middleware support
43
+
44
+ ## Installation
45
+
46
+ **npm:**
47
+
48
+ ```bash
49
+ npm install @koa/router
50
+ ```
51
+
52
+ **yarn:**
53
+
54
+ ```bash
55
+ yarn add @koa/router
56
+ ```
57
+
58
+ **Requirements:**
59
+
60
+ - Node.js >= 20 (tested on v20, v22, v24, v25)
61
+ - Koa >= 2.0.0
62
+
63
+ ## TypeScript Support
64
+
65
+ @koa/router is written in TypeScript and includes comprehensive type definitions out of the box. No need for `@types/*` packages!
66
+
67
+ ### Basic Usage
68
+
69
+ Types are **automatically inferred** - no explicit type annotations needed:
70
+
71
+ ```typescript
72
+ import Router from '@koa/router';
73
+
74
+ const router = new Router();
75
+
76
+ // ctx and next are automatically inferred!
77
+ router.get('/:id', (ctx, next) => {
78
+ const id = ctx.params.id; // ✅ Inferred as string
79
+ ctx.request.params.id; // ✅ Also available
80
+ ctx.body = { id }; // ✅ Works
81
+ return next(); // ✅ Works
82
+ });
83
+
84
+ // Also works for router.use()
85
+ router.use((ctx, next) => {
86
+ ctx.state.startTime = Date.now();
87
+ return next();
88
+ });
89
+ ```
90
+
91
+ ### Explicit Types (Optional)
92
+
93
+ For cases where you need explicit types:
94
+
95
+ ```typescript
96
+ import Router, { RouterContext } from '@koa/router';
97
+ import type { Next } from 'koa';
98
+
99
+ router.get('/:id', (ctx: RouterContext, next: Next) => {
100
+ const id = ctx.params.id;
101
+ ctx.body = { id };
102
+ });
103
+ ```
104
+
105
+ ### Generic Types
106
+
107
+ The router supports generic type parameters for full type safety with custom state and context types:
108
+
109
+ ```typescript
110
+ import Router, { RouterContext } from '@koa/router';
111
+ import type { Next } from 'koa';
112
+
113
+ // Define your application state
114
+ interface AppState {
115
+ user?: {
116
+ id: string;
117
+ email: string;
118
+ };
119
+ }
120
+
121
+ // Define your custom context
122
+ interface AppContext {
123
+ requestId: string;
124
+ }
125
+
126
+ // Create router with generics
127
+ const router = new Router<AppState, AppContext>();
128
+
129
+ // Type-safe route handlers
130
+ router.get(
131
+ '/profile',
132
+ (ctx: RouterContext<AppState, AppContext>, next: Next) => {
133
+ // ctx.state.user is fully typed
134
+ if (ctx.state.user) {
135
+ ctx.body = {
136
+ user: ctx.state.user,
137
+ requestId: ctx.requestId // Custom context property
138
+ };
139
+ }
140
+ }
141
+ );
142
+ ```
143
+
144
+ ### Extending Types in Route Handlers
145
+
146
+ HTTP methods support generic type parameters to extend state and context types:
147
+
148
+ ```typescript
149
+ interface UserState {
150
+ user: { id: string; name: string };
151
+ }
152
+
153
+ interface UserContext {
154
+ permissions: string[];
155
+ }
156
+
157
+ // Extend types for specific routes
158
+ router.get<UserState, UserContext>(
159
+ '/users/:id',
160
+ async (ctx: RouterContext<UserState, UserContext>) => {
161
+ // ctx.state.user is fully typed
162
+ // ctx.permissions is fully typed
163
+ ctx.body = {
164
+ user: ctx.state.user,
165
+ permissions: ctx.permissions
166
+ };
167
+ }
168
+ );
169
+ ```
170
+
171
+ ### Parameter Middleware Types
172
+
173
+ ```typescript
174
+ import type { RouterParameterMiddleware } from '@koa/router';
175
+ import type { Next } from 'koa';
176
+
177
+ // Type-safe parameter middleware
178
+ router.param('id', ((value: string, ctx: RouterContext, next: Next) => {
179
+ if (!/^\d+$/.test(value)) {
180
+ ctx.throw(400, 'Invalid ID format');
181
+ }
182
+ return next();
183
+ }) as RouterParameterMiddleware);
184
+ ```
185
+
186
+ ### Available Types
187
+
188
+ ```typescript
189
+ import {
190
+ Router,
191
+ RouterContext,
192
+ RouterOptions,
193
+ RouterMiddleware,
194
+ RouterParameterMiddleware,
195
+ AllowedMethodsOptions,
196
+ UrlOptions,
197
+ HttpMethod,
198
+ MatchResult,
199
+ LayerOptions,
200
+ Layer,
201
+ RouterEvent,
202
+ RouterEventSelector,
203
+ RouterEvents
204
+ } from '@koa/router';
205
+ import type { Next } from 'koa';
206
+
207
+ // Router with generics
208
+ type MyRouter = Router<AppState, AppContext>;
209
+
210
+ // Context with generics
211
+ type MyContext = RouterContext<AppState, AppContext, BodyType>;
212
+
213
+ // Middleware with generics
214
+ type MyMiddleware = RouterMiddleware<AppState, AppContext, BodyType>;
215
+
216
+ // Parameter middleware with generics
217
+ type MyParamMiddleware = RouterParameterMiddleware<
218
+ AppState,
219
+ AppContext,
220
+ BodyType
221
+ >;
222
+ ```
223
+
224
+ ### Type Safety Features
225
+
226
+ - ✅ **Full type inference** - `ctx` and `next` are inferred automatically in route handlers
227
+ - ✅ **Full generic support** - `Router<StateT, ContextT>` for custom state and context types
228
+ - ✅ **Type-safe parameters** - `ctx.params` is fully typed and always defined
229
+ - ✅ **Type-safe state** - `ctx.state` respects your state type
230
+ - ✅ **Type-safe middleware** - Middleware functions are fully typed
231
+ - ✅ **Type-safe HTTP methods** - Methods support generic type extensions
232
+ - ✅ **Custom HTTP method inference** - Use `as const` with `methods` option for typed custom methods
233
+ - ✅ **Compatible with @types/koa-router** - Matches official type structure
234
+
235
+ ## Quick Start
236
+
237
+ ```javascript
238
+ import Koa from 'koa';
239
+ import Router from '@koa/router';
240
+
241
+ const app = new Koa();
242
+ const router = new Router();
243
+
244
+ // Define routes
245
+ router.get('/', (ctx, next) => {
246
+ ctx.body = 'Hello World!';
247
+ });
248
+
249
+ router.get('/users/:id', (ctx, next) => {
250
+ ctx.body = { id: ctx.params.id };
251
+ });
252
+
253
+ // Apply router middleware
254
+ app.use(router.routes()).use(router.allowedMethods());
255
+
256
+ app.listen(3000);
257
+ ```
258
+
259
+ ## API Documentation
260
+
261
+ ### Router Constructor
262
+
263
+ **`new Router([options])`**
264
+
265
+ Create a new router instance.
266
+
267
+ **Options:**
268
+
269
+ | Option | Type | Description |
270
+ | ----------- | ------------------------------ | ----------------------------------------- |
271
+ | `prefix` | `string` | Prefix all routes with this path |
272
+ | `exclusive` | `boolean` | Only run the most specific matching route |
273
+ | `host` | `string \| string[] \| RegExp` | Match routes only for this hostname(s) |
274
+ | `methods` | `string[]` | Custom HTTP methods to support |
275
+ | `sensitive` | `boolean` | Enable case-sensitive routing |
276
+ | `strict` | `boolean` | Require trailing slashes |
277
+
278
+ **Example:**
279
+
280
+ ```javascript
281
+ const router = new Router({
282
+ prefix: '/api',
283
+ exclusive: true,
284
+ host: 'example.com'
285
+ });
286
+ ```
287
+
288
+ ### HTTP Methods
289
+
290
+ Router provides methods for all standard HTTP verbs:
291
+
292
+ - `router.get(path, ...middleware)`
293
+ - `router.post(path, ...middleware)`
294
+ - `router.put(path, ...middleware)`
295
+ - `router.patch(path, ...middleware)`
296
+ - `router.delete(path, ...middleware)` or `router.del(path, ...middleware)`
297
+ - `router.head(path, ...middleware)`
298
+ - `router.options(path, ...middleware)`
299
+ - `router.connect(path, ...middleware)` - CONNECT method
300
+ - `router.trace(path, ...middleware)` - TRACE method
301
+ - `router.all(path, ...middleware)` - Match any HTTP method
302
+
303
+ **Note:** All standard HTTP methods (as defined by Node.js `http.METHODS`) are automatically available as router methods. The `methods` option in the constructor can be used to limit which methods the router responds to, but you cannot use truly custom HTTP methods beyond the standard set.
304
+
305
+ **Basic Example:**
306
+
307
+ ```javascript
308
+ router
309
+ .get('/users', getUsers)
310
+ .post('/users', createUser)
311
+ .put('/users/:id', updateUser)
312
+ .delete('/users/:id', deleteUser)
313
+ .all('/users/:id', logAccess); // Runs for any method
314
+ ```
315
+
316
+ **Using Less Common HTTP Methods:**
317
+
318
+ All standard HTTP methods from Node.js are automatically available. Here's an example using `PATCH` and `PURGE`:
319
+
320
+ ```javascript
321
+ const router = new Router();
322
+
323
+ // PATCH method (standard HTTP method for partial updates)
324
+ router.patch('/users/:id', async (ctx) => {
325
+ // Partial update
326
+ ctx.body = { message: 'User partially updated' };
327
+ });
328
+
329
+ // PURGE method (standard HTTP method, commonly used for cache invalidation)
330
+ router.purge('/cache/:key', async (ctx) => {
331
+ // Clear cache
332
+ await clearCache(ctx.params.key);
333
+ ctx.body = { message: 'Cache cleared' };
334
+ });
335
+
336
+ // COPY method (standard HTTP method)
337
+ router.copy('/files/:source', async (ctx) => {
338
+ await copyFile(ctx.params.source, ctx.request.body.destination);
339
+ ctx.body = { message: 'File copied' };
340
+ });
341
+
342
+ // Limiting which methods the router responds to
343
+ const apiRouter = new Router({
344
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] // Only these methods
345
+ });
346
+
347
+ apiRouter.get('/users', getUsers);
348
+ apiRouter.post('/users', createUser);
349
+ // router.purge() won't work here because PURGE is not in the methods array
350
+ ```
351
+
352
+ **Note:** HEAD requests are automatically supported for all GET routes. When you define a GET route, HEAD requests will execute the same handler and return the same headers but with an empty body.
353
+
354
+ ### Named Routes
355
+
356
+ Routes can be named for URL generation:
357
+
358
+ ```javascript
359
+ router.get('user', '/users/:id', (ctx) => {
360
+ ctx.body = { id: ctx.params.id };
361
+ });
362
+
363
+ // Generate URL
364
+ router.url('user', 3);
365
+ // => "/users/3"
366
+
367
+ router.url('user', { id: 3 });
368
+ // => "/users/3"
369
+
370
+ // With query parameters
371
+ router.url('user', { id: 3 }, { query: { limit: 10 } });
372
+ // => "/users/3?limit=10"
373
+
374
+ // In middleware
375
+ router.use((ctx, next) => {
376
+ ctx.redirect(ctx.router.url('user', 1));
377
+ });
378
+ ```
379
+
380
+ ### Multiple Middleware
381
+
382
+ Chain multiple middleware functions for a single route:
383
+
384
+ ```javascript
385
+ router.get(
386
+ '/users/:id',
387
+ async (ctx, next) => {
388
+ // Load user from database
389
+ ctx.state.user = await User.findById(ctx.params.id);
390
+ return next();
391
+ },
392
+ async (ctx, next) => {
393
+ // Check permissions
394
+ if (!ctx.state.user) {
395
+ ctx.throw(404, 'User not found');
396
+ }
397
+ return next();
398
+ },
399
+ (ctx) => {
400
+ // Send response
401
+ ctx.body = ctx.state.user;
402
+ }
403
+ );
404
+ ```
405
+
406
+ ### Nested Routers
407
+
408
+ Mount routers within routers:
409
+
410
+ ```javascript
411
+ const usersRouter = new Router();
412
+ usersRouter.get('/', getUsers);
413
+ usersRouter.get('/:id', getUser);
414
+
415
+ const postsRouter = new Router();
416
+ postsRouter.get('/', getPosts);
417
+ postsRouter.get('/:id', getPost);
418
+
419
+ const apiRouter = new Router({ prefix: '/api' });
420
+ apiRouter.use('/users', usersRouter.routes());
421
+ apiRouter.use('/posts', postsRouter.routes());
422
+
423
+ app.use(apiRouter.routes());
424
+ ```
425
+
426
+ **Note:** Parameters from parent routes are properly propagated to nested router middleware and handlers.
427
+
428
+ ### Router Prefixes
429
+
430
+ Set a prefix for all routes in a router:
431
+
432
+ **Option 1: In constructor**
433
+
434
+ ```javascript
435
+ const router = new Router({ prefix: '/api' });
436
+ router.get('/users', handler); // Responds to /api/users
437
+ ```
438
+
439
+ **Option 2: Using .prefix()**
440
+
441
+ ```javascript
442
+ const router = new Router();
443
+ router.prefix('/api');
444
+ router.get('/users', handler); // Responds to /api/users
445
+ ```
446
+
447
+ **With parameters:**
448
+
449
+ ```javascript
450
+ const router = new Router({ prefix: '/api/v:version' });
451
+ router.get('/users', (ctx) => {
452
+ ctx.body = {
453
+ version: ctx.params.version,
454
+ users: []
455
+ };
456
+ });
457
+ // Responds to /api/v1/users, /api/v2/users, etc.
458
+ ```
459
+
460
+ **Note:** Middleware now correctly executes when the prefix contains parameters.
461
+
462
+ ### URL Parameters
463
+
464
+ Named parameters are captured and available at `ctx.params`:
465
+
466
+ ```javascript
467
+ router.get('/:category/:title', (ctx) => {
468
+ console.log(ctx.params);
469
+ // => { category: 'programming', title: 'how-to-node' }
470
+
471
+ ctx.body = {
472
+ category: ctx.params.category,
473
+ title: ctx.params.title
474
+ };
475
+ });
476
+ ```
477
+
478
+ **Optional parameters:**
479
+
480
+ ```javascript
481
+ router.get('/user{/:id}', (ctx) => {
482
+ // Matches both /user and /user/123
483
+ ctx.body = { id: ctx.params.id || 'all' };
484
+ });
485
+ ```
486
+
487
+ **Wildcard parameters:**
488
+
489
+ ```javascript
490
+ router.get('/files/{/*path}', (ctx) => {
491
+ // Matches /files/a/b/c.txt
492
+ ctx.body = { path: ctx.params.path }; // => a/b/c.txt
493
+ });
494
+ ```
495
+
496
+ **Note:** Custom regex patterns in parameters (`:param(regex)`) are **no longer supported** in v14+ due to path-to-regexp v8. Use validation in handlers or middleware instead.
497
+
498
+ **Helper for parameter validation (v14+)** <small>(Added on v15.2)</small>
499
+
500
+ If you want to keep regex-style validation, register a param middleware instead:
501
+
502
+ ```javascript
503
+ import Router, { createParameterValidationMiddleware } from '@koa/router';
504
+
505
+ const uuid =
506
+ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
507
+
508
+ const validateId = createParameterValidationMiddleware('id', uuid);
509
+
510
+ router.param('id', validateId).get('/role/:id', middleware);
511
+ ```
512
+
513
+ Or validate inline on a specific route:
514
+
515
+ ```javascript
516
+ import Router, { createParameterValidationMiddleware } from '@koa/router';
517
+
518
+ const uuid =
519
+ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
520
+
521
+ router.get(
522
+ '/role/:id',
523
+ createParameterValidationMiddleware('id', uuid),
524
+ middleware
525
+ );
526
+ ```
527
+
528
+ ### router.routes()
529
+
530
+ Returns router middleware which dispatches matched routes.
531
+
532
+ ```javascript
533
+ app.use(router.routes());
534
+ ```
535
+
536
+ ### router.use()
537
+
538
+ Use middleware, **if and only if**, a route is matched.
539
+
540
+ **Signature:**
541
+
542
+ ```javascript
543
+ router.use([path], ...middleware);
544
+ ```
545
+
546
+ **Examples:**
547
+
548
+ ```javascript
549
+ // Run for all matched routes
550
+ router.use(session());
551
+
552
+ // Run only for specific path
553
+ router.use('/admin', requireAuth());
554
+
555
+ // Run for multiple paths
556
+ router.use(['/admin', '/dashboard'], requireAuth());
557
+
558
+ // Run for RegExp paths
559
+ router.use(/^\/api\//, apiAuth());
560
+
561
+ // Mount nested routers
562
+ const nestedRouter = new Router();
563
+ router.use('/nested', nestedRouter.routes());
564
+ ```
565
+
566
+ **Note:** Middleware path boundaries are correctly enforced. Middleware scoped to `/api` will only run for routes matching `/api/*`, not for unrelated routes.
567
+
568
+ ### router.prefix()
569
+
570
+ Set the path prefix for a Router instance after initialization.
571
+
572
+ ```javascript
573
+ const router = new Router();
574
+ router.get('/', handler); // Responds to /
575
+
576
+ router.prefix('/api');
577
+ router.get('/', handler); // Now responds to /api
578
+ ```
579
+
580
+ ### router.allowedMethods()
581
+
582
+ Returns middleware for responding to `OPTIONS` requests with allowed methods,
583
+ and `405 Method Not Allowed` / `501 Not Implemented` responses.
584
+
585
+ **Options:**
586
+
587
+ | Option | Type | Description |
588
+ | ------------------ | ---------- | ---------------------------------------- |
589
+ | `throw` | `boolean` | Throw errors instead of setting response |
590
+ | `notImplemented` | `function` | Custom function for 501 errors |
591
+ | `methodNotAllowed` | `function` | Custom function for 405 errors |
592
+
593
+ **Example:**
594
+
595
+ ```javascript
596
+ app.use(router.routes());
597
+ app.use(router.allowedMethods());
598
+ ```
599
+
600
+ **With custom error handling:**
601
+
602
+ ```javascript
603
+ app.use(
604
+ router.allowedMethods({
605
+ throw: true,
606
+ notImplemented: () => new Error('Not Implemented'),
607
+ methodNotAllowed: () => new Error('Method Not Allowed')
608
+ })
609
+ );
610
+ ```
611
+
612
+ ### router.redirect()
613
+
614
+ Redirect `source` to `destination` URL with optional status code.
615
+
616
+ ```javascript
617
+ router.redirect('/login', 'sign-in', 301);
618
+ router.redirect('/old-path', '/new-path');
619
+
620
+ // Redirect to named route
621
+ router.get('home', '/', handler);
622
+ router.redirect('/index', 'home');
623
+ ```
624
+
625
+ ### router.route()
626
+
627
+ Lookup a route by name.
628
+
629
+ ```javascript
630
+ const layer = router.route('user');
631
+ if (layer) {
632
+ console.log(layer.path); // => /users/:id
633
+ }
634
+ ```
635
+
636
+ ### router.url()
637
+
638
+ Generate URL from route name and parameters.
639
+
640
+ ```javascript
641
+ router.get('user', '/users/:id', handler);
642
+
643
+ router.url('user', 3);
644
+ // => "/users/3"
645
+
646
+ router.url('user', { id: 3 });
647
+ // => "/users/3"
648
+
649
+ router.url('user', { id: 3 }, { query: { limit: 1 } });
650
+ // => "/users/3?limit=1"
651
+
652
+ router.url('user', { id: 3 }, { query: 'limit=1' });
653
+ // => "/users/3?limit=1"
654
+ ```
655
+
656
+ **In middleware:**
657
+
658
+ ```javascript
659
+ router.use((ctx, next) => {
660
+ // Access router instance via ctx.router
661
+ const userUrl = ctx.router.url('user', ctx.state.userId);
662
+ ctx.redirect(userUrl);
663
+ return next();
664
+ });
665
+ ```
666
+
667
+ ### router.param()
668
+
669
+ Run middleware for named route parameters.
670
+
671
+ **Signature:**
672
+
673
+ ```typescript
674
+ router.param(param: string, middleware: RouterParameterMiddleware): Router
675
+ ```
676
+
677
+ **TypeScript Example:**
678
+
679
+ ```typescript
680
+ import type { RouterParameterMiddleware } from '@koa/router';
681
+ import type { Next } from 'koa';
682
+
683
+ router.param('user', (async (id: string, ctx: RouterContext, next: Next) => {
684
+ ctx.state.user = await User.findById(id);
685
+ if (!ctx.state.user) {
686
+ ctx.throw(404, 'User not found');
687
+ }
688
+ return next();
689
+ }) as RouterParameterMiddleware);
690
+
691
+ router.get('/users/:user', (ctx: RouterContext) => {
692
+ // ctx.state.user is already loaded and typed
693
+ ctx.body = ctx.state.user;
694
+ });
695
+
696
+ router.get('/users/:user/friends', (ctx: RouterContext) => {
697
+ // ctx.state.user is available here too
698
+ return ctx.state.user.getFriends();
699
+ });
700
+ ```
701
+
702
+ **JavaScript Example:**
703
+
704
+ ```javascript
705
+ router
706
+ .param('user', async (id, ctx, next) => {
707
+ ctx.state.user = await User.findById(id);
708
+ if (!ctx.state.user) {
709
+ ctx.throw(404, 'User not found');
710
+ }
711
+ return next();
712
+ })
713
+ .get('/users/:user', (ctx) => {
714
+ // ctx.state.user is already loaded
715
+ ctx.body = ctx.state.user;
716
+ })
717
+ .get('/users/:user/friends', (ctx) => {
718
+ // ctx.state.user is available here too
719
+ return ctx.state.user.getFriends();
720
+ });
721
+ ```
722
+
723
+ **Multiple param handlers:**
724
+
725
+ You can register multiple param handlers for the same parameter. All handlers will be called in order, and each handler is executed exactly once per request (even if multiple routes match):
726
+
727
+ ```javascript
728
+ router
729
+ .param('id', validateIdFormat)
730
+ .param('id', checkIdExists)
731
+ .param('id', checkPermissions)
732
+ .get('/resource/:id', handler);
733
+ // All three param handlers run once per request
734
+ ```
735
+
736
+ ### Router.url() (static)
737
+
738
+ Generate URL from path pattern and parameters (static method).
739
+
740
+ ```javascript
741
+ const url = Router.url('/users/:id', { id: 1 });
742
+ // => "/users/1"
743
+
744
+ const url = Router.url('/users/:id', { id: 1, name: 'John' });
745
+ // => "/users/1"
746
+ ```
747
+
748
+ ### router.on() (experimental)
749
+
750
+ Register an event handler on the router for lifecycle events.
751
+
752
+ **Signature:**
753
+
754
+ ```typescript
755
+ router.on(event: RouterEventSelector, handler: RouterMiddleware): Router
756
+ ```
757
+
758
+ **Parameters:**
759
+
760
+ | Parameter | Type | Description |
761
+ | --------- | --------------------- | ---------------------------------------------------------------- |
762
+ | `event` | `RouterEventSelector` | Event name string, `RouterEvents` constant, or selector function |
763
+ | `handler` | `RouterMiddleware` | Middleware function `(ctx, next) => {}` |
764
+
765
+ **Returns:** Router instance for chaining.
766
+
767
+ **Active events:**
768
+
769
+ | Event | Constant | Description |
770
+ | ------------- | ----------------------- | ----------------------------------------- |
771
+ | `'not-found'` | `RouterEvents.NotFound` | Fires when no route matched path + method |
772
+
773
+ **Example:**
774
+
775
+ ```javascript
776
+ import { RouterEvents } from '@koa/router';
777
+
778
+ // All three forms are equivalent:
779
+ router.on(RouterEvents.NotFound, handler); // constant (recommended)
780
+ router.on((events) => events.NotFound, handler); // selector function
781
+ router.on('not-found', handler); // raw string
782
+
783
+ // Handlers can be chained:
784
+ router
785
+ .on(RouterEvents.NotFound, async (ctx, next) => {
786
+ console.log('no route matched:', ctx.path);
787
+ await next();
788
+ })
789
+ .on(RouterEvents.NotFound, (ctx) => {
790
+ ctx.status = 404;
791
+ ctx.body = { error: 'Not Found' };
792
+ });
793
+ ```
794
+
795
+ > **Note:** This API is experimental and may change in future versions. See the
796
+ > [Not Found Event](#not-found-event-experimental) section in Advanced Features for details.
797
+
798
+ ## Advanced Features
799
+
800
+ ### Host Matching
801
+
802
+ Match routes only for specific hostnames:
803
+
804
+ ```javascript
805
+ // Exact match with single host
806
+ const routerA = new Router({
807
+ host: 'example.com'
808
+ });
809
+
810
+ // Match multiple hosts with array
811
+ const routerB = new Router({
812
+ host: ['some-domain.com', 'www.some-domain.com', 'some.other-domain.com']
813
+ });
814
+
815
+ // Match patterns with RegExp
816
+ const routerC = new Router({
817
+ host: /^(.*\.)?example\.com$/ // Match all subdomains
818
+ });
819
+ ```
820
+
821
+ **Host Matching Options:**
822
+
823
+ - `string` - Exact match (case-sensitive)
824
+ - `string[]` - Matches if the request host equals any string in the array
825
+ - `RegExp` - Pattern match using regular expression
826
+ - `undefined` - Matches all hosts (default)
827
+
828
+ ### Regular Expressions
829
+
830
+ Use RegExp for flexible path matching:
831
+
832
+ **Full RegExp routes:**
833
+
834
+ ```javascript
835
+ router.get(/^\/users\/(\d+)$/, (ctx) => {
836
+ const id = ctx.params[0]; // First capture group
837
+ ctx.body = { id };
838
+ });
839
+ ```
840
+
841
+ **RegExp in router.use():**
842
+
843
+ ```javascript
844
+ router.use(/^\/api\//, apiMiddleware);
845
+ router.use(/^\/admin\//, adminAuth);
846
+ ```
847
+
848
+ ### Parameter Validation
849
+
850
+ Validate parameters using middleware or handlers:
851
+
852
+ **Option 1: In Handler**
853
+
854
+ ```javascript
855
+ router.get('/user/:id', (ctx) => {
856
+ if (!/^\d+$/.test(ctx.params.id)) {
857
+ ctx.throw(400, 'Invalid ID format');
858
+ }
859
+
860
+ ctx.body = { id: parseInt(ctx.params.id, 10) };
861
+ });
862
+ ```
863
+
864
+ **Option 2: Middleware**
865
+
866
+ ```javascript
867
+ function validateUUID(paramName) {
868
+ const uuidRegex =
869
+ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
870
+
871
+ return async (ctx, next) => {
872
+ if (!uuidRegex.test(ctx.params[paramName])) {
873
+ ctx.throw(400, `Invalid ${paramName} format`);
874
+ }
875
+ await next();
876
+ };
877
+ }
878
+
879
+ router.get('/user/:id', validateUUID('id'), handler);
880
+ ```
881
+
882
+ **Option 3: router.param()**
883
+
884
+ ```javascript
885
+ router.param('id', (value, ctx, next) => {
886
+ if (!/^\d+$/.test(value)) {
887
+ ctx.throw(400, 'Invalid ID');
888
+ }
889
+ ctx.params.id = parseInt(value, 10); // Convert to number
890
+ return next();
891
+ });
892
+
893
+ router.get('/user/:id', handler);
894
+ router.get('/post/:id', handler);
895
+ // Both routes validate :id parameter
896
+ ```
897
+
898
+ ### Catch-All Routes
899
+
900
+ Create a catch-all route that runs when no specific route handler has set a response.
901
+ Check `!ctx.body` to determine whether a previous handler already responded:
902
+
903
+ ```javascript
904
+ router.get('/users', handler1);
905
+ router.get('/posts', handler2);
906
+
907
+ // Catch-all for unmatched routes
908
+ router.all('{/*rest}', (ctx) => {
909
+ if (!ctx.body) {
910
+ ctx.status = 404;
911
+ ctx.body = { error: 'Not Found' };
912
+ }
913
+ });
914
+ ```
915
+
916
+ > **Note:** `ctx.matched.length === 0` will never be true inside a catch-all handler.
917
+ > The router populates `ctx.matched` **before** the handler body runs, so the catch-all
918
+ > layer (`{/*rest}`) is already included in the array by the time your code executes.
919
+ >
920
+ > **Recommended:** Use `!ctx.body` as shown above — it is the simplest and most reliable
921
+ > condition inside a catch-all route.
922
+ >
923
+ > **Workaround:** If you specifically need `ctx.matched`-based logic inside a catch-all,
924
+ > filter out the catch-all layer first and check the remaining array:
925
+ >
926
+ > ```javascript
927
+ > router.all('{/*rest}', (ctx) => {
928
+ > const realMatches = ctx.matched.filter(
929
+ > (layer) => layer.path !== '{/*rest}'
930
+ > );
931
+ > if (realMatches.length === 0) {
932
+ > ctx.status = 404;
933
+ > ctx.body = { error: 'Not Found' };
934
+ > }
935
+ > });
936
+ > ```
937
+ >
938
+ > For cleaner and more precise 404 detection, prefer app-level middleware with
939
+ > `ctx.routeMatched` — see the [404 Handling](#404-handling) section.
940
+
941
+ ### Array of Paths
942
+
943
+ Register multiple paths with the same middleware:
944
+
945
+ ```javascript
946
+ router.get(['/users', '/people'], handler);
947
+ // Responds to both /users and /people
948
+ ```
949
+
950
+ ### 404 Handling
951
+
952
+ Implement custom 404 handling using app-level middleware after the router.
953
+
954
+ **Using `ctx.routeMatched` (recommended):**
955
+
956
+ ```javascript
957
+ app.use(router.routes());
958
+
959
+ // ctx.routeMatched is set by the router before handlers run
960
+ app.use((ctx) => {
961
+ if (!ctx.routeMatched) {
962
+ ctx.status = 404;
963
+ ctx.body = {
964
+ error: 'Not Found',
965
+ path: ctx.path
966
+ };
967
+ }
968
+ });
969
+ ```
970
+
971
+ **Using `ctx.matched`:**
972
+
973
+ ```javascript
974
+ app.use(router.routes());
975
+
976
+ app.use((ctx) => {
977
+ if (!ctx.matched || ctx.matched.length === 0) {
978
+ ctx.status = 404;
979
+ ctx.body = {
980
+ error: 'Not Found',
981
+ path: ctx.path
982
+ };
983
+ }
984
+ });
985
+ ```
986
+
987
+ > For a router-scoped alternative that doesn't require app-level middleware,
988
+ > see the [Not Found Event](#not-found-event-experimental) section below.
989
+
990
+ ### Not Found Event (Experimental)
991
+
992
+ > **Note:** This API is experimental and may change in future versions.
993
+
994
+ Use `router.on()` for a clean, dedicated 404 handler that runs only when no route
995
+ matched — without needing a catch-all route. Three equivalent forms are supported:
996
+
997
+ ```javascript
998
+ import { RouterEvents } from '@koa/router';
999
+
1000
+ // Named constant (recommended — autocomplete + refactor safe)
1001
+ router.on(RouterEvents.NotFound, handler);
1002
+
1003
+ // Selector function (fluent style)
1004
+ router.on((events) => events.NotFound, handler);
1005
+
1006
+ // Raw string (still accepted)
1007
+ router.on('not-found', handler);
1008
+ ```
1009
+
1010
+ Full example:
1011
+
1012
+ ```javascript
1013
+ import { RouterEvents } from '@koa/router';
1014
+
1015
+ router.get('/users', handler1);
1016
+ router.get('/posts', handler2);
1017
+
1018
+ router.on(RouterEvents.NotFound, (ctx) => {
1019
+ ctx.status = 404;
1020
+ ctx.body = {
1021
+ error: 'Not Found',
1022
+ path: ctx.path,
1023
+ method: ctx.method
1024
+ };
1025
+ });
1026
+
1027
+ app.use(router.routes());
1028
+ ```
1029
+
1030
+ Multiple handlers are supported and compose in registration order:
1031
+
1032
+ ```javascript
1033
+ router.on(RouterEvents.NotFound, async (ctx, next) => {
1034
+ console.log('no route matched:', ctx.path);
1035
+ await next();
1036
+ });
1037
+
1038
+ router.on(RouterEvents.NotFound, (ctx) => {
1039
+ ctx.status = 404;
1040
+ ctx.body = { error: 'Not Found' };
1041
+ });
1042
+ ```
1043
+
1044
+ Benefits over catch-all routes:
1045
+
1046
+ - Does not appear in `ctx.matched`
1047
+ - Only fires when no route matched — no need to check `ctx.routeMatched` or `ctx.body`
1048
+ - Handlers compose naturally with `next()`
1049
+
1050
+ ## Best Practices
1051
+
1052
+ ### 1. Use Middleware Composition
1053
+
1054
+ ```javascript
1055
+ // ✅ Good: Compose reusable middleware
1056
+ const requireAuth = () => async (ctx, next) => {
1057
+ if (!ctx.state.user) ctx.throw(401);
1058
+ await next();
1059
+ };
1060
+
1061
+ const requireAdmin = () => async (ctx, next) => {
1062
+ if (!ctx.state.user.isAdmin) ctx.throw(403);
1063
+ await next();
1064
+ };
1065
+
1066
+ router.get('/admin', requireAuth(), requireAdmin(), adminHandler);
1067
+ ```
1068
+
1069
+ ### 2. Organize Routes by Resource
1070
+
1071
+ ```javascript
1072
+ // ✅ Good: Group related routes
1073
+ const usersRouter = new Router({ prefix: '/users' });
1074
+ usersRouter.get('/', listUsers);
1075
+ usersRouter.post('/', createUser);
1076
+ usersRouter.get('/:id', getUser);
1077
+ usersRouter.put('/:id', updateUser);
1078
+ usersRouter.delete('/:id', deleteUser);
1079
+
1080
+ app.use(usersRouter.routes());
1081
+ ```
1082
+
1083
+ ### 3. Use Named Routes
1084
+
1085
+ ```javascript
1086
+ // ✅ Good: Name important routes
1087
+ router.get('home', '/', homeHandler);
1088
+ router.get('user-profile', '/users/:id', profileHandler);
1089
+
1090
+ // Easy to generate URLs
1091
+ ctx.redirect(ctx.router.url('home'));
1092
+ ctx.redirect(ctx.router.url('user-profile', ctx.state.user.id));
1093
+ ```
1094
+
1095
+ ### 4. Validate Early
1096
+
1097
+ ```javascript
1098
+ // ✅ Good: Validate at the route level
1099
+ router
1100
+ .param('id', validateId)
1101
+ .get('/users/:id', getUser)
1102
+ .put('/users/:id', updateUser)
1103
+ .delete('/users/:id', deleteUser);
1104
+ // Validation runs once for all routes
1105
+ ```
1106
+
1107
+ ### 5. Handle Errors Consistently
1108
+
1109
+ ```javascript
1110
+ // ✅ Good: Centralized error handling
1111
+ app.use(async (ctx, next) => {
1112
+ try {
1113
+ await next();
1114
+ } catch (err) {
1115
+ ctx.status = err.status || 500;
1116
+ ctx.body = {
1117
+ error: err.message,
1118
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
1119
+ };
1120
+ }
1121
+ });
1122
+
1123
+ app.use(router.routes());
1124
+ app.use(router.allowedMethods({ throw: true }));
1125
+ ```
1126
+
1127
+ ### 6. Access Router Context Properties
1128
+
1129
+ The router adds useful properties to the Koa context:
1130
+
1131
+ ```typescript
1132
+ router.get('/users/:id', (ctx: RouterContext) => {
1133
+ // URL parameters (fully typed)
1134
+ const id = ctx.params.id; // string
1135
+
1136
+ // Router instance
1137
+ const router = ctx.router;
1138
+
1139
+ // Matched route path
1140
+ const routePath = ctx.routerPath; // => '/users/:id'
1141
+
1142
+ // Matched route name (if named)
1143
+ const routeName = ctx.routerName; // => 'user' (if named)
1144
+
1145
+ // All matched layers
1146
+ const matched = ctx.matched; // Array of Layer objects
1147
+
1148
+ // Whether any route (with HTTP methods) was matched
1149
+ const wasMatched = ctx.routeMatched; // boolean | undefined
1150
+
1151
+ // Captured values from RegExp routes
1152
+ const captures = ctx.captures; // string[] | undefined
1153
+
1154
+ // Generate URLs
1155
+ const url = ctx.router.url('user', id);
1156
+
1157
+ ctx.body = { id, routePath, routeName, url };
1158
+ });
1159
+ ```
1160
+
1161
+ ### 7. Type-Safe Context Extensions
1162
+
1163
+ Extend the router context with custom properties:
1164
+
1165
+ ```typescript
1166
+ import Router, { RouterContext } from '@koa/router';
1167
+ import type { Next } from 'koa';
1168
+
1169
+ interface UserState {
1170
+ user?: { id: string; email: string };
1171
+ }
1172
+
1173
+ interface CustomContext {
1174
+ requestId: string;
1175
+ startTime: number;
1176
+ }
1177
+
1178
+ const router = new Router<UserState, CustomContext>();
1179
+
1180
+ // Middleware that adds to context
1181
+ router.use(async (ctx: RouterContext<UserState, CustomContext>, next: Next) => {
1182
+ ctx.requestId = crypto.randomUUID();
1183
+ ctx.startTime = Date.now();
1184
+ await next();
1185
+ });
1186
+
1187
+ router.get(
1188
+ '/users/:id',
1189
+ async (ctx: RouterContext<UserState, CustomContext>) => {
1190
+ // All properties are fully typed
1191
+ ctx.body = {
1192
+ user: ctx.state.user,
1193
+ requestId: ctx.requestId,
1194
+ duration: Date.now() - ctx.startTime
1195
+ };
1196
+ }
1197
+ );
1198
+ ```
1199
+
1200
+ ## Recipes
1201
+
1202
+ Common patterns and recipes for building real-world applications with @koa/router.
1203
+
1204
+ See the [recipes directory](./recipes/) for complete TypeScript examples:
1205
+
1206
+ - **[Nested Routes](./recipes/nested-routes/)** - Production-ready nested router patterns with multiple levels (3-4 levels deep), parameter propagation, and real-world examples
1207
+ - **[RESTful API Structure](./recipes/restful-api-structure/)** - Organize your API with nested routers
1208
+ - **[Authentication & Authorization](./recipes/authentication-authorization/)** - JWT-based authentication with middleware
1209
+ - **[Request Validation](./recipes/request-validation/)** - Validate request data with middleware
1210
+ - **[Parameter Validation](./recipes/parameter-validation/)** - Validate and transform parameters using router.param()
1211
+ - **[Regex Parameter Validation](./recipes/regex-parameter-validation/)** - Validate URL parameters with regex (replacement for `:param(regex)` in v14+)
1212
+ - **[API Versioning](./recipes/api-versioning/)** - Implement API versioning with multiple routers
1213
+ - **[Error Handling](./recipes/error-handling/)** - Centralized error handling with custom error classes
1214
+ - **[Pagination](./recipes/pagination/)** - Implement pagination for list endpoints
1215
+ - **[Health Checks](./recipes/health-checks/)** - Add health check endpoints for monitoring
1216
+ - **[TypeScript Recipe](./recipes/typescript-recipe/)** - Full TypeScript example with types and type safety
1217
+ - **[Not Found Handling](./recipes/not-found-handling/)** - All approaches to handling unmatched routes: `ctx.routeMatched`, events, catch-all
1218
+
1219
+ Each recipe file contains complete, runnable TypeScript code that you can copy and adapt to your needs.
1220
+
1221
+ ## Performance
1222
+
1223
+ @koa/router is designed for high performance:
1224
+
1225
+ - **Fast path matching** with path-to-regexp v8
1226
+ - **Efficient RegExp compilation** and caching
1227
+ - **Minimal overhead** - zero runtime type checking
1228
+ - **Optimized middleware execution** with koa-compose
1229
+
1230
+ **Benchmarks:**
1231
+
1232
+ ```bash
1233
+ # Run benchmarks
1234
+ yarn benchmark
1235
+
1236
+ # Run all benchmark scenarios
1237
+ yarn benchmark:all
1238
+ ```
1239
+
1240
+ ## Testing
1241
+
1242
+ @koa/router uses Node.js native test runner:
1243
+
1244
+ ```bash
1245
+ # Run all tests (core + recipes)
1246
+ yarn test:all
1247
+
1248
+ # Run core tests only
1249
+ yarn test:core
1250
+
1251
+ # Run recipe tests only
1252
+ yarn test:recipes
1253
+
1254
+ # Run tests with coverage
1255
+ yarn test:coverage
1256
+
1257
+ # Type check
1258
+ yarn ts:check
1259
+
1260
+ # Format code with Prettier
1261
+ yarn format
1262
+
1263
+ # Check code formatting
1264
+ yarn format:check
1265
+
1266
+ # Lint code
1267
+ yarn lint
1268
+ ```
1269
+
1270
+ **Example test:**
1271
+
1272
+ ```javascript
1273
+ import { describe, it } from 'node:test';
1274
+ import assert from 'node:assert';
1275
+ import Koa from 'koa';
1276
+ import Router from '@koa/router';
1277
+ import request from 'supertest';
1278
+
1279
+ describe('Router', () => {
1280
+ it('should route GET requests', async () => {
1281
+ const app = new Koa();
1282
+ const router = new Router();
1283
+
1284
+ router.get('/users', (ctx) => {
1285
+ ctx.body = { users: [] };
1286
+ });
1287
+
1288
+ app.use(router.routes());
1289
+
1290
+ const res = await request(app.callback()).get('/users').expect(200);
1291
+
1292
+ assert.deepStrictEqual(res.body, { users: [] });
1293
+ });
1294
+ });
1295
+ ```
1296
+
1297
+ ## Migration Guides
1298
+
1299
+ For detailed migration information, see **[FULL_MIGRATION_TO_V15+.md](./FULL_MIGRATION_TO_V15+.md)**.
1300
+
1301
+ **Breaking Changes:**
1302
+
1303
+ - Custom regex patterns in parameters (`:param(regex)`) are **no longer supported** due to path-to-regexp v8. Use validation in handlers or middleware instead.
1304
+ - Node.js >= 20 is required.
1305
+ - TypeScript types are now included in the package (no need for `@types/@koa/router`).
1306
+
1307
+ **Upgrading:**
1308
+
1309
+ 1. Update Node.js to >= 20
1310
+ 2. Replace custom regex parameters with validation middleware
1311
+ 3. Remove `@types/@koa/router` if installed (types are now included)
1312
+ 4. Update any code using deprecated features
1313
+
1314
+ **Backward Compatibility:**
1315
+
1316
+ The code is mostly backward compatible. If you notice any issues when upgrading, please don't hesitate to [open an issue](https://github.com/koajs/router/issues) and let us know!
1317
+
1318
+ ## Contributing
1319
+
1320
+ Contributions are welcome!
1321
+
1322
+ ### Development Setup
1323
+
1324
+ ```bash
1325
+ # Clone repository
1326
+ git clone https://github.com/koajs/router.git
1327
+ cd router
1328
+
1329
+ # Install dependencies (using yarn)
1330
+ yarn install
1331
+
1332
+ # Run tests
1333
+ yarn test:all
1334
+
1335
+ # Run tests with coverage
1336
+ yarn test:coverage
1337
+
1338
+ # Format code
1339
+ yarn format
1340
+
1341
+ # Check formatting
1342
+ yarn format:check
1343
+
1344
+ # Lint code
1345
+ yarn lint
1346
+
1347
+ # Build TypeScript
1348
+ yarn build
1349
+
1350
+ # Type check
1351
+ yarn ts:check
1352
+ ```
1353
+
1354
+ ## Contributors
1355
+
1356
+ | Name |
1357
+ | ---------------- |
1358
+ | **Alex Mingoia** |
1359
+ | **@koajs** |
1360
+ | **Imed Jaberi** |
1361
+
1362
+ ## License
1363
+
1364
+ [MIT](LICENSE) © Koa.js
1365
+
1366
+ ---
1367
+
1368
+ [forward-email]: https://forwardemail.net
1369
+ [lad]: https://lad.js.org
1370
+ [npm]: https://www.npmjs.com