@koa/router 15.3.2 → 15.4.0
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.
- package/README.md +173 -6
- package/dist/index.d.mts +112 -1
- package/dist/index.d.ts +112 -1
- package/dist/index.js +124 -3
- package/dist/index.mjs +123 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -192,10 +192,15 @@ import {
|
|
|
192
192
|
RouterOptions,
|
|
193
193
|
RouterMiddleware,
|
|
194
194
|
RouterParameterMiddleware,
|
|
195
|
-
RouterParamContext,
|
|
196
195
|
AllowedMethodsOptions,
|
|
197
196
|
UrlOptions,
|
|
198
|
-
HttpMethod
|
|
197
|
+
HttpMethod,
|
|
198
|
+
MatchResult,
|
|
199
|
+
LayerOptions,
|
|
200
|
+
Layer,
|
|
201
|
+
RouterEvent,
|
|
202
|
+
RouterEventSelector,
|
|
203
|
+
RouterEvents
|
|
199
204
|
} from '@koa/router';
|
|
200
205
|
import type { Next } from 'koa';
|
|
201
206
|
|
|
@@ -740,6 +745,56 @@ const url = Router.url('/users/:id', { id: 1, name: 'John' });
|
|
|
740
745
|
// => "/users/1"
|
|
741
746
|
```
|
|
742
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
|
+
|
|
743
798
|
## Advanced Features
|
|
744
799
|
|
|
745
800
|
### Host Matching
|
|
@@ -842,7 +897,8 @@ router.get('/post/:id', handler);
|
|
|
842
897
|
|
|
843
898
|
### Catch-All Routes
|
|
844
899
|
|
|
845
|
-
Create a catch-all route that
|
|
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:
|
|
846
902
|
|
|
847
903
|
```javascript
|
|
848
904
|
router.get('/users', handler1);
|
|
@@ -850,13 +906,38 @@ router.get('/posts', handler2);
|
|
|
850
906
|
|
|
851
907
|
// Catch-all for unmatched routes
|
|
852
908
|
router.all('{/*rest}', (ctx) => {
|
|
853
|
-
if (!ctx.
|
|
909
|
+
if (!ctx.body) {
|
|
854
910
|
ctx.status = 404;
|
|
855
911
|
ctx.body = { error: 'Not Found' };
|
|
856
912
|
}
|
|
857
913
|
});
|
|
858
914
|
```
|
|
859
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
|
+
|
|
860
941
|
### Array of Paths
|
|
861
942
|
|
|
862
943
|
Register multiple paths with the same middleware:
|
|
@@ -868,12 +949,30 @@ router.get(['/users', '/people'], handler);
|
|
|
868
949
|
|
|
869
950
|
### 404 Handling
|
|
870
951
|
|
|
871
|
-
Implement custom 404 handling
|
|
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`:**
|
|
872
972
|
|
|
873
973
|
```javascript
|
|
874
974
|
app.use(router.routes());
|
|
875
975
|
|
|
876
|
-
// 404 middleware - runs after router
|
|
877
976
|
app.use((ctx) => {
|
|
878
977
|
if (!ctx.matched || ctx.matched.length === 0) {
|
|
879
978
|
ctx.status = 404;
|
|
@@ -885,6 +984,69 @@ app.use((ctx) => {
|
|
|
885
984
|
});
|
|
886
985
|
```
|
|
887
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
|
+
|
|
888
1050
|
## Best Practices
|
|
889
1051
|
|
|
890
1052
|
### 1. Use Middleware Composition
|
|
@@ -983,6 +1145,9 @@ router.get('/users/:id', (ctx: RouterContext) => {
|
|
|
983
1145
|
// All matched layers
|
|
984
1146
|
const matched = ctx.matched; // Array of Layer objects
|
|
985
1147
|
|
|
1148
|
+
// Whether any route (with HTTP methods) was matched
|
|
1149
|
+
const wasMatched = ctx.routeMatched; // boolean | undefined
|
|
1150
|
+
|
|
986
1151
|
// Captured values from RegExp routes
|
|
987
1152
|
const captures = ctx.captures; // string[] | undefined
|
|
988
1153
|
|
|
@@ -1043,11 +1208,13 @@ See the [recipes directory](./recipes/) for complete TypeScript examples:
|
|
|
1043
1208
|
- **[Authentication & Authorization](./recipes/authentication-authorization/)** - JWT-based authentication with middleware
|
|
1044
1209
|
- **[Request Validation](./recipes/request-validation/)** - Validate request data with middleware
|
|
1045
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+)
|
|
1046
1212
|
- **[API Versioning](./recipes/api-versioning/)** - Implement API versioning with multiple routers
|
|
1047
1213
|
- **[Error Handling](./recipes/error-handling/)** - Centralized error handling with custom error classes
|
|
1048
1214
|
- **[Pagination](./recipes/pagination/)** - Implement pagination for list endpoints
|
|
1049
1215
|
- **[Health Checks](./recipes/health-checks/)** - Add health check endpoints for monitoring
|
|
1050
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
|
|
1051
1218
|
|
|
1052
1219
|
Each recipe file contains complete, runnable TypeScript code that you can copy and adapt to your needs.
|
|
1053
1220
|
|
package/dist/index.d.mts
CHANGED
|
@@ -172,6 +172,47 @@ declare class Layer<StateT = DefaultState, ContextT = DefaultContext, BodyT = un
|
|
|
172
172
|
private _reconfigurePathMatching;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Named constants for active router lifecycle events.
|
|
177
|
+
*
|
|
178
|
+
* Only events that are fully implemented appear here. Planned events will be
|
|
179
|
+
* added as each one is implemented so the public API always reflects what
|
|
180
|
+
* actually works.
|
|
181
|
+
*
|
|
182
|
+
* @experimental
|
|
183
|
+
*/
|
|
184
|
+
declare const RouterEvents: {
|
|
185
|
+
/**
|
|
186
|
+
* Fires when no route matched the request path + HTTP method.
|
|
187
|
+
*/
|
|
188
|
+
readonly NotFound: "not-found";
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Union of all valid router event name strings.
|
|
192
|
+
* Derived from `RouterEvents` so the two are always in sync.
|
|
193
|
+
*
|
|
194
|
+
* @experimental
|
|
195
|
+
*/
|
|
196
|
+
type RouterEvent = (typeof RouterEvents)[keyof typeof RouterEvents];
|
|
197
|
+
/**
|
|
198
|
+
* Accepts either a raw event name string or a selector function that receives
|
|
199
|
+
* the `RouterEvents` object and returns an event name.
|
|
200
|
+
*
|
|
201
|
+
* Both forms are equivalent — choose whichever reads better in context.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* // string
|
|
206
|
+
* 'not-found'
|
|
207
|
+
*
|
|
208
|
+
* // selector function
|
|
209
|
+
* (events) => events.NotFound
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @experimental
|
|
213
|
+
*/
|
|
214
|
+
type RouterEventSelector = RouterEvent | ((events: typeof RouterEvents) => RouterEvent);
|
|
215
|
+
|
|
175
216
|
type RouterInstance<StateT = koa.DefaultState, ContextT = koa.DefaultContext> = RouterImplementation<StateT, ContextT>;
|
|
176
217
|
/**
|
|
177
218
|
* Middleware with router property
|
|
@@ -189,6 +230,11 @@ declare class RouterImplementation<StateT = koa.DefaultState, ContextT = koa.Def
|
|
|
189
230
|
params: Record<string, RouterParameterMiddleware<StateT, ContextT> | RouterParameterMiddleware<StateT, ContextT>[]>;
|
|
190
231
|
stack: Layer<StateT, ContextT>[];
|
|
191
232
|
host?: string | string[] | RegExp;
|
|
233
|
+
/**
|
|
234
|
+
* Event emitter for router lifecycle events (experimental)
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
private _events;
|
|
192
238
|
/**
|
|
193
239
|
* Create a new router.
|
|
194
240
|
*
|
|
@@ -356,6 +402,52 @@ declare class RouterImplementation<StateT = koa.DefaultState, ContextT = koa.Def
|
|
|
356
402
|
*/
|
|
357
403
|
private _buildMiddlewareChain;
|
|
358
404
|
routes(): RouterComposedMiddleware<StateT, ContextT>;
|
|
405
|
+
/**
|
|
406
|
+
* Register an event handler on the router.
|
|
407
|
+
*
|
|
408
|
+
* @experimental This API is experimental and may change in future versions.
|
|
409
|
+
*
|
|
410
|
+
* **Active events:**
|
|
411
|
+
* - `'not-found'` — fires when no route matched path + method. Handlers are
|
|
412
|
+
* composed and called instead of `next()`, so they are responsible for
|
|
413
|
+
* calling `next()` themselves if they want to pass control downstream.
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
*
|
|
417
|
+
* All three forms are equivalent:
|
|
418
|
+
*
|
|
419
|
+
* ```javascript
|
|
420
|
+
* import { RouterEvents } from '@koa/router';
|
|
421
|
+
*
|
|
422
|
+
* // Named constant (recommended — autocomplete + refactor safe)
|
|
423
|
+
* router.on(RouterEvents.NotFound, handler);
|
|
424
|
+
*
|
|
425
|
+
* // Selector function (fluent style)
|
|
426
|
+
* router.on((events) => events.NotFound, handler);
|
|
427
|
+
*
|
|
428
|
+
* // Raw string (still accepted)
|
|
429
|
+
* router.on('not-found', handler);
|
|
430
|
+
* ```
|
|
431
|
+
*
|
|
432
|
+
* Multiple handlers compose in registration order:
|
|
433
|
+
*
|
|
434
|
+
* ```javascript
|
|
435
|
+
* router.on(RouterEvents.NotFound, async (ctx, next) => {
|
|
436
|
+
* console.log('no route matched', ctx.path);
|
|
437
|
+
* await next();
|
|
438
|
+
* });
|
|
439
|
+
* router.on(RouterEvents.NotFound, (ctx) => {
|
|
440
|
+
* ctx.status = 404;
|
|
441
|
+
* ctx.body = { error: 'Not Found' };
|
|
442
|
+
* });
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* @param event - Event name string, `RouterEvents` constant, or selector
|
|
446
|
+
* function `(events) => events.NotFound` (see `RouterEventSelector`)
|
|
447
|
+
* @param handler - Middleware to run when the event fires
|
|
448
|
+
* @returns This router instance for chaining
|
|
449
|
+
*/
|
|
450
|
+
on(event: RouterEventSelector, handler: RouterMiddleware<StateT, ContextT>): Router<StateT, ContextT>;
|
|
359
451
|
/**
|
|
360
452
|
* Returns separate middleware for responding to `OPTIONS` requests with
|
|
361
453
|
* an `Allow` header containing the allowed methods, as well as responding
|
|
@@ -806,6 +898,25 @@ type RouterContext<StateT = DefaultState, ContextT = DefaultContext, BodyT = unk
|
|
|
806
898
|
* Array of matched layers
|
|
807
899
|
*/
|
|
808
900
|
matched?: Layer<StateT, ContextT, BodyT>[];
|
|
901
|
+
/**
|
|
902
|
+
* Whether a route (with HTTP methods) was matched for this request.
|
|
903
|
+
* Set by the router before any handlers run.
|
|
904
|
+
*
|
|
905
|
+
* Use this in app-level middleware after `router.routes()` to detect
|
|
906
|
+
* requests that the router did not handle.
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* ```javascript
|
|
910
|
+
* app.use(router.routes());
|
|
911
|
+
* app.use((ctx) => {
|
|
912
|
+
* if (!ctx.routeMatched) {
|
|
913
|
+
* ctx.status = 404;
|
|
914
|
+
* ctx.body = { error: 'Not Found' };
|
|
915
|
+
* }
|
|
916
|
+
* });
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
919
|
+
routeMatched?: boolean;
|
|
809
920
|
/**
|
|
810
921
|
* Captured values from path
|
|
811
922
|
*/
|
|
@@ -889,4 +1000,4 @@ type ParameterValidationOptions = {
|
|
|
889
1000
|
*/
|
|
890
1001
|
declare function createParameterValidationMiddleware(parameterName: string, pattern: RegExp, options?: ParameterValidationOptions): RouterMiddleware<any, any, any> & RouterParameterMiddleware<any, any, any>;
|
|
891
1002
|
|
|
892
|
-
export { type AllowedMethodsOptions, type HttpMethod, Layer, type LayerOptions, type MatchResult, type ParameterValidationOptions, Router, type RouterContext, type RouterInstance, type RouterMethodFunction, type RouterMiddleware, type RouterOptions, type RouterOptionsWithMethods, type RouterParameterMiddleware, type RouterWithMethods, type UrlOptions, createParameterValidationMiddleware, Router as default };
|
|
1003
|
+
export { type AllowedMethodsOptions, type HttpMethod, Layer, type LayerOptions, type MatchResult, type ParameterValidationOptions, Router, type RouterContext, type RouterEvent, type RouterEventSelector, RouterEvents, type RouterInstance, type RouterMethodFunction, type RouterMiddleware, type RouterOptions, type RouterOptionsWithMethods, type RouterParameterMiddleware, type RouterWithMethods, type UrlOptions, createParameterValidationMiddleware, Router as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -172,6 +172,47 @@ declare class Layer<StateT = DefaultState, ContextT = DefaultContext, BodyT = un
|
|
|
172
172
|
private _reconfigurePathMatching;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Named constants for active router lifecycle events.
|
|
177
|
+
*
|
|
178
|
+
* Only events that are fully implemented appear here. Planned events will be
|
|
179
|
+
* added as each one is implemented so the public API always reflects what
|
|
180
|
+
* actually works.
|
|
181
|
+
*
|
|
182
|
+
* @experimental
|
|
183
|
+
*/
|
|
184
|
+
declare const RouterEvents: {
|
|
185
|
+
/**
|
|
186
|
+
* Fires when no route matched the request path + HTTP method.
|
|
187
|
+
*/
|
|
188
|
+
readonly NotFound: "not-found";
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Union of all valid router event name strings.
|
|
192
|
+
* Derived from `RouterEvents` so the two are always in sync.
|
|
193
|
+
*
|
|
194
|
+
* @experimental
|
|
195
|
+
*/
|
|
196
|
+
type RouterEvent = (typeof RouterEvents)[keyof typeof RouterEvents];
|
|
197
|
+
/**
|
|
198
|
+
* Accepts either a raw event name string or a selector function that receives
|
|
199
|
+
* the `RouterEvents` object and returns an event name.
|
|
200
|
+
*
|
|
201
|
+
* Both forms are equivalent — choose whichever reads better in context.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* // string
|
|
206
|
+
* 'not-found'
|
|
207
|
+
*
|
|
208
|
+
* // selector function
|
|
209
|
+
* (events) => events.NotFound
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @experimental
|
|
213
|
+
*/
|
|
214
|
+
type RouterEventSelector = RouterEvent | ((events: typeof RouterEvents) => RouterEvent);
|
|
215
|
+
|
|
175
216
|
type RouterInstance<StateT = koa.DefaultState, ContextT = koa.DefaultContext> = RouterImplementation<StateT, ContextT>;
|
|
176
217
|
/**
|
|
177
218
|
* Middleware with router property
|
|
@@ -189,6 +230,11 @@ declare class RouterImplementation<StateT = koa.DefaultState, ContextT = koa.Def
|
|
|
189
230
|
params: Record<string, RouterParameterMiddleware<StateT, ContextT> | RouterParameterMiddleware<StateT, ContextT>[]>;
|
|
190
231
|
stack: Layer<StateT, ContextT>[];
|
|
191
232
|
host?: string | string[] | RegExp;
|
|
233
|
+
/**
|
|
234
|
+
* Event emitter for router lifecycle events (experimental)
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
private _events;
|
|
192
238
|
/**
|
|
193
239
|
* Create a new router.
|
|
194
240
|
*
|
|
@@ -356,6 +402,52 @@ declare class RouterImplementation<StateT = koa.DefaultState, ContextT = koa.Def
|
|
|
356
402
|
*/
|
|
357
403
|
private _buildMiddlewareChain;
|
|
358
404
|
routes(): RouterComposedMiddleware<StateT, ContextT>;
|
|
405
|
+
/**
|
|
406
|
+
* Register an event handler on the router.
|
|
407
|
+
*
|
|
408
|
+
* @experimental This API is experimental and may change in future versions.
|
|
409
|
+
*
|
|
410
|
+
* **Active events:**
|
|
411
|
+
* - `'not-found'` — fires when no route matched path + method. Handlers are
|
|
412
|
+
* composed and called instead of `next()`, so they are responsible for
|
|
413
|
+
* calling `next()` themselves if they want to pass control downstream.
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
*
|
|
417
|
+
* All three forms are equivalent:
|
|
418
|
+
*
|
|
419
|
+
* ```javascript
|
|
420
|
+
* import { RouterEvents } from '@koa/router';
|
|
421
|
+
*
|
|
422
|
+
* // Named constant (recommended — autocomplete + refactor safe)
|
|
423
|
+
* router.on(RouterEvents.NotFound, handler);
|
|
424
|
+
*
|
|
425
|
+
* // Selector function (fluent style)
|
|
426
|
+
* router.on((events) => events.NotFound, handler);
|
|
427
|
+
*
|
|
428
|
+
* // Raw string (still accepted)
|
|
429
|
+
* router.on('not-found', handler);
|
|
430
|
+
* ```
|
|
431
|
+
*
|
|
432
|
+
* Multiple handlers compose in registration order:
|
|
433
|
+
*
|
|
434
|
+
* ```javascript
|
|
435
|
+
* router.on(RouterEvents.NotFound, async (ctx, next) => {
|
|
436
|
+
* console.log('no route matched', ctx.path);
|
|
437
|
+
* await next();
|
|
438
|
+
* });
|
|
439
|
+
* router.on(RouterEvents.NotFound, (ctx) => {
|
|
440
|
+
* ctx.status = 404;
|
|
441
|
+
* ctx.body = { error: 'Not Found' };
|
|
442
|
+
* });
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* @param event - Event name string, `RouterEvents` constant, or selector
|
|
446
|
+
* function `(events) => events.NotFound` (see `RouterEventSelector`)
|
|
447
|
+
* @param handler - Middleware to run when the event fires
|
|
448
|
+
* @returns This router instance for chaining
|
|
449
|
+
*/
|
|
450
|
+
on(event: RouterEventSelector, handler: RouterMiddleware<StateT, ContextT>): Router<StateT, ContextT>;
|
|
359
451
|
/**
|
|
360
452
|
* Returns separate middleware for responding to `OPTIONS` requests with
|
|
361
453
|
* an `Allow` header containing the allowed methods, as well as responding
|
|
@@ -806,6 +898,25 @@ type RouterContext<StateT = DefaultState, ContextT = DefaultContext, BodyT = unk
|
|
|
806
898
|
* Array of matched layers
|
|
807
899
|
*/
|
|
808
900
|
matched?: Layer<StateT, ContextT, BodyT>[];
|
|
901
|
+
/**
|
|
902
|
+
* Whether a route (with HTTP methods) was matched for this request.
|
|
903
|
+
* Set by the router before any handlers run.
|
|
904
|
+
*
|
|
905
|
+
* Use this in app-level middleware after `router.routes()` to detect
|
|
906
|
+
* requests that the router did not handle.
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* ```javascript
|
|
910
|
+
* app.use(router.routes());
|
|
911
|
+
* app.use((ctx) => {
|
|
912
|
+
* if (!ctx.routeMatched) {
|
|
913
|
+
* ctx.status = 404;
|
|
914
|
+
* ctx.body = { error: 'Not Found' };
|
|
915
|
+
* }
|
|
916
|
+
* });
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
919
|
+
routeMatched?: boolean;
|
|
809
920
|
/**
|
|
810
921
|
* Captured values from path
|
|
811
922
|
*/
|
|
@@ -889,4 +1000,4 @@ type ParameterValidationOptions = {
|
|
|
889
1000
|
*/
|
|
890
1001
|
declare function createParameterValidationMiddleware(parameterName: string, pattern: RegExp, options?: ParameterValidationOptions): RouterMiddleware<any, any, any> & RouterParameterMiddleware<any, any, any>;
|
|
891
1002
|
|
|
892
|
-
export { type AllowedMethodsOptions, type HttpMethod, Layer, type LayerOptions, type MatchResult, type ParameterValidationOptions, Router, type RouterContext, type RouterInstance, type RouterMethodFunction, type RouterMiddleware, type RouterOptions, type RouterOptionsWithMethods, type RouterParameterMiddleware, type RouterWithMethods, type UrlOptions, createParameterValidationMiddleware, Router as default };
|
|
1003
|
+
export { type AllowedMethodsOptions, type HttpMethod, Layer, type LayerOptions, type MatchResult, type ParameterValidationOptions, Router, type RouterContext, type RouterEvent, type RouterEventSelector, RouterEvents, type RouterInstance, type RouterMethodFunction, type RouterMiddleware, type RouterOptions, type RouterOptionsWithMethods, type RouterParameterMiddleware, type RouterWithMethods, type UrlOptions, createParameterValidationMiddleware, Router as default };
|
package/dist/index.js
CHANGED
|
@@ -31,11 +31,72 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Router: () => Router,
|
|
34
|
+
RouterEvents: () => RouterEvents,
|
|
34
35
|
createParameterValidationMiddleware: () => createParameterValidationMiddleware,
|
|
35
36
|
default: () => router_default
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
38
39
|
|
|
40
|
+
// src/utils/router-events.ts
|
|
41
|
+
var import_koa_compose = __toESM(require("koa-compose"));
|
|
42
|
+
var RouterEvents = {
|
|
43
|
+
/**
|
|
44
|
+
* Fires when no route matched the request path + HTTP method.
|
|
45
|
+
*/
|
|
46
|
+
NotFound: "not-found"
|
|
47
|
+
// /**
|
|
48
|
+
// * Fires when the request path matched a registered route but the HTTP
|
|
49
|
+
// * method did not match any of its allowed methods.
|
|
50
|
+
// *
|
|
51
|
+
// * @planned Not yet active — handlers are stored but not called.
|
|
52
|
+
// */
|
|
53
|
+
// MethodNotAllowed: 'method-not-allowed',
|
|
54
|
+
// /**
|
|
55
|
+
// * Fires after a route is matched and before its handlers run.
|
|
56
|
+
// * Useful for tracing and logging the matched route.
|
|
57
|
+
// *
|
|
58
|
+
// * @planned Not yet active — handlers are stored but not called.
|
|
59
|
+
// */
|
|
60
|
+
// Match: 'match',
|
|
61
|
+
// /**
|
|
62
|
+
// * Fires on every request that enters the router, before route matching.
|
|
63
|
+
// * Useful for per-router metrics and request logging.
|
|
64
|
+
// *
|
|
65
|
+
// * @planned Not yet active — handlers are stored but not called.
|
|
66
|
+
// */
|
|
67
|
+
// Dispatch: 'dispatch'
|
|
68
|
+
};
|
|
69
|
+
function resolveEvent(selector) {
|
|
70
|
+
return typeof selector === "function" ? selector(RouterEvents) : selector;
|
|
71
|
+
}
|
|
72
|
+
var RouterEventEmitter = class {
|
|
73
|
+
_handlers = /* @__PURE__ */ new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Register a handler for the given event.
|
|
76
|
+
* Multiple handlers for the same event are composed in registration order.
|
|
77
|
+
*/
|
|
78
|
+
register(event, handler) {
|
|
79
|
+
const existing = this._handlers.get(event) ?? [];
|
|
80
|
+
existing.push(handler);
|
|
81
|
+
this._handlers.set(event, existing);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Emit an event by composing and running all registered handlers.
|
|
85
|
+
* If no handlers are registered for the event, calls `next()` directly.
|
|
86
|
+
*
|
|
87
|
+
* @param event - The event to emit
|
|
88
|
+
* @param context - The router context
|
|
89
|
+
* @param next - The downstream next function
|
|
90
|
+
*/
|
|
91
|
+
emit(event, context, next) {
|
|
92
|
+
const handlers = this._handlers.get(event);
|
|
93
|
+
if (handlers && handlers.length > 0) {
|
|
94
|
+
return (0, import_koa_compose.default)(handlers)(context, next);
|
|
95
|
+
}
|
|
96
|
+
return next();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
39
100
|
// src/utils/parameter-match.ts
|
|
40
101
|
var import_http_errors = __toESM(require("http-errors"));
|
|
41
102
|
function createParameterValidationMiddleware(parameterName, pattern, options = {}) {
|
|
@@ -86,7 +147,7 @@ function createParameterValidationMiddleware(parameterName, pattern, options = {
|
|
|
86
147
|
}
|
|
87
148
|
|
|
88
149
|
// src/router.ts
|
|
89
|
-
var
|
|
150
|
+
var import_koa_compose2 = __toESM(require("koa-compose"));
|
|
90
151
|
var import_http_errors2 = __toESM(require("http-errors"));
|
|
91
152
|
|
|
92
153
|
// src/layer.ts
|
|
@@ -651,6 +712,11 @@ var RouterImplementation = class {
|
|
|
651
712
|
params;
|
|
652
713
|
stack;
|
|
653
714
|
host;
|
|
715
|
+
/**
|
|
716
|
+
* Event emitter for router lifecycle events (experimental)
|
|
717
|
+
* @internal
|
|
718
|
+
*/
|
|
719
|
+
_events = new RouterEventEmitter();
|
|
654
720
|
/**
|
|
655
721
|
* Create a new router.
|
|
656
722
|
*
|
|
@@ -922,8 +988,13 @@ var RouterImplementation = class {
|
|
|
922
988
|
const matchResult = this.match(requestPath, context.method);
|
|
923
989
|
this._storeMatchedRoutes(context, matchResult);
|
|
924
990
|
context.router = this;
|
|
991
|
+
context.routeMatched = matchResult.route;
|
|
925
992
|
if (!matchResult.route) {
|
|
926
|
-
return
|
|
993
|
+
return this._events.emit(
|
|
994
|
+
RouterEvents.NotFound,
|
|
995
|
+
context,
|
|
996
|
+
next
|
|
997
|
+
);
|
|
927
998
|
}
|
|
928
999
|
const matchedLayers = matchResult.pathAndMethod;
|
|
929
1000
|
this._setMatchedRouteInfo(context, matchedLayers);
|
|
@@ -931,7 +1002,7 @@ var RouterImplementation = class {
|
|
|
931
1002
|
matchedLayers,
|
|
932
1003
|
requestPath
|
|
933
1004
|
);
|
|
934
|
-
return (0,
|
|
1005
|
+
return (0, import_koa_compose2.default)(middlewareChain)(
|
|
935
1006
|
context,
|
|
936
1007
|
next
|
|
937
1008
|
);
|
|
@@ -1009,6 +1080,55 @@ var RouterImplementation = class {
|
|
|
1009
1080
|
routes() {
|
|
1010
1081
|
return this.middleware();
|
|
1011
1082
|
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Register an event handler on the router.
|
|
1085
|
+
*
|
|
1086
|
+
* @experimental This API is experimental and may change in future versions.
|
|
1087
|
+
*
|
|
1088
|
+
* **Active events:**
|
|
1089
|
+
* - `'not-found'` — fires when no route matched path + method. Handlers are
|
|
1090
|
+
* composed and called instead of `next()`, so they are responsible for
|
|
1091
|
+
* calling `next()` themselves if they want to pass control downstream.
|
|
1092
|
+
*
|
|
1093
|
+
* @example
|
|
1094
|
+
*
|
|
1095
|
+
* All three forms are equivalent:
|
|
1096
|
+
*
|
|
1097
|
+
* ```javascript
|
|
1098
|
+
* import { RouterEvents } from '@koa/router';
|
|
1099
|
+
*
|
|
1100
|
+
* // Named constant (recommended — autocomplete + refactor safe)
|
|
1101
|
+
* router.on(RouterEvents.NotFound, handler);
|
|
1102
|
+
*
|
|
1103
|
+
* // Selector function (fluent style)
|
|
1104
|
+
* router.on((events) => events.NotFound, handler);
|
|
1105
|
+
*
|
|
1106
|
+
* // Raw string (still accepted)
|
|
1107
|
+
* router.on('not-found', handler);
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* Multiple handlers compose in registration order:
|
|
1111
|
+
*
|
|
1112
|
+
* ```javascript
|
|
1113
|
+
* router.on(RouterEvents.NotFound, async (ctx, next) => {
|
|
1114
|
+
* console.log('no route matched', ctx.path);
|
|
1115
|
+
* await next();
|
|
1116
|
+
* });
|
|
1117
|
+
* router.on(RouterEvents.NotFound, (ctx) => {
|
|
1118
|
+
* ctx.status = 404;
|
|
1119
|
+
* ctx.body = { error: 'Not Found' };
|
|
1120
|
+
* });
|
|
1121
|
+
* ```
|
|
1122
|
+
*
|
|
1123
|
+
* @param event - Event name string, `RouterEvents` constant, or selector
|
|
1124
|
+
* function `(events) => events.NotFound` (see `RouterEventSelector`)
|
|
1125
|
+
* @param handler - Middleware to run when the event fires
|
|
1126
|
+
* @returns This router instance for chaining
|
|
1127
|
+
*/
|
|
1128
|
+
on(event, handler) {
|
|
1129
|
+
this._events.register(resolveEvent(event), handler);
|
|
1130
|
+
return this;
|
|
1131
|
+
}
|
|
1012
1132
|
/**
|
|
1013
1133
|
* Returns separate middleware for responding to `OPTIONS` requests with
|
|
1014
1134
|
* an `Allow` header containing the allowed methods, as well as responding
|
|
@@ -1487,6 +1607,7 @@ for (const httpMethod of httpMethods) {
|
|
|
1487
1607
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1488
1608
|
0 && (module.exports = {
|
|
1489
1609
|
Router,
|
|
1610
|
+
RouterEvents,
|
|
1490
1611
|
createParameterValidationMiddleware
|
|
1491
1612
|
});
|
|
1492
1613
|
if (module.exports.default) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,63 @@
|
|
|
1
|
+
// src/utils/router-events.ts
|
|
2
|
+
import compose from "koa-compose";
|
|
3
|
+
var RouterEvents = {
|
|
4
|
+
/**
|
|
5
|
+
* Fires when no route matched the request path + HTTP method.
|
|
6
|
+
*/
|
|
7
|
+
NotFound: "not-found"
|
|
8
|
+
// /**
|
|
9
|
+
// * Fires when the request path matched a registered route but the HTTP
|
|
10
|
+
// * method did not match any of its allowed methods.
|
|
11
|
+
// *
|
|
12
|
+
// * @planned Not yet active — handlers are stored but not called.
|
|
13
|
+
// */
|
|
14
|
+
// MethodNotAllowed: 'method-not-allowed',
|
|
15
|
+
// /**
|
|
16
|
+
// * Fires after a route is matched and before its handlers run.
|
|
17
|
+
// * Useful for tracing and logging the matched route.
|
|
18
|
+
// *
|
|
19
|
+
// * @planned Not yet active — handlers are stored but not called.
|
|
20
|
+
// */
|
|
21
|
+
// Match: 'match',
|
|
22
|
+
// /**
|
|
23
|
+
// * Fires on every request that enters the router, before route matching.
|
|
24
|
+
// * Useful for per-router metrics and request logging.
|
|
25
|
+
// *
|
|
26
|
+
// * @planned Not yet active — handlers are stored but not called.
|
|
27
|
+
// */
|
|
28
|
+
// Dispatch: 'dispatch'
|
|
29
|
+
};
|
|
30
|
+
function resolveEvent(selector) {
|
|
31
|
+
return typeof selector === "function" ? selector(RouterEvents) : selector;
|
|
32
|
+
}
|
|
33
|
+
var RouterEventEmitter = class {
|
|
34
|
+
_handlers = /* @__PURE__ */ new Map();
|
|
35
|
+
/**
|
|
36
|
+
* Register a handler for the given event.
|
|
37
|
+
* Multiple handlers for the same event are composed in registration order.
|
|
38
|
+
*/
|
|
39
|
+
register(event, handler) {
|
|
40
|
+
const existing = this._handlers.get(event) ?? [];
|
|
41
|
+
existing.push(handler);
|
|
42
|
+
this._handlers.set(event, existing);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Emit an event by composing and running all registered handlers.
|
|
46
|
+
* If no handlers are registered for the event, calls `next()` directly.
|
|
47
|
+
*
|
|
48
|
+
* @param event - The event to emit
|
|
49
|
+
* @param context - The router context
|
|
50
|
+
* @param next - The downstream next function
|
|
51
|
+
*/
|
|
52
|
+
emit(event, context, next) {
|
|
53
|
+
const handlers = this._handlers.get(event);
|
|
54
|
+
if (handlers && handlers.length > 0) {
|
|
55
|
+
return compose(handlers)(context, next);
|
|
56
|
+
}
|
|
57
|
+
return next();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
1
61
|
// src/utils/parameter-match.ts
|
|
2
62
|
import createHttpError from "http-errors";
|
|
3
63
|
function createParameterValidationMiddleware(parameterName, pattern, options = {}) {
|
|
@@ -48,7 +108,7 @@ function createParameterValidationMiddleware(parameterName, pattern, options = {
|
|
|
48
108
|
}
|
|
49
109
|
|
|
50
110
|
// src/router.ts
|
|
51
|
-
import
|
|
111
|
+
import compose2 from "koa-compose";
|
|
52
112
|
import HttpError from "http-errors";
|
|
53
113
|
|
|
54
114
|
// src/layer.ts
|
|
@@ -613,6 +673,11 @@ var RouterImplementation = class {
|
|
|
613
673
|
params;
|
|
614
674
|
stack;
|
|
615
675
|
host;
|
|
676
|
+
/**
|
|
677
|
+
* Event emitter for router lifecycle events (experimental)
|
|
678
|
+
* @internal
|
|
679
|
+
*/
|
|
680
|
+
_events = new RouterEventEmitter();
|
|
616
681
|
/**
|
|
617
682
|
* Create a new router.
|
|
618
683
|
*
|
|
@@ -884,8 +949,13 @@ var RouterImplementation = class {
|
|
|
884
949
|
const matchResult = this.match(requestPath, context.method);
|
|
885
950
|
this._storeMatchedRoutes(context, matchResult);
|
|
886
951
|
context.router = this;
|
|
952
|
+
context.routeMatched = matchResult.route;
|
|
887
953
|
if (!matchResult.route) {
|
|
888
|
-
return
|
|
954
|
+
return this._events.emit(
|
|
955
|
+
RouterEvents.NotFound,
|
|
956
|
+
context,
|
|
957
|
+
next
|
|
958
|
+
);
|
|
889
959
|
}
|
|
890
960
|
const matchedLayers = matchResult.pathAndMethod;
|
|
891
961
|
this._setMatchedRouteInfo(context, matchedLayers);
|
|
@@ -893,7 +963,7 @@ var RouterImplementation = class {
|
|
|
893
963
|
matchedLayers,
|
|
894
964
|
requestPath
|
|
895
965
|
);
|
|
896
|
-
return
|
|
966
|
+
return compose2(middlewareChain)(
|
|
897
967
|
context,
|
|
898
968
|
next
|
|
899
969
|
);
|
|
@@ -971,6 +1041,55 @@ var RouterImplementation = class {
|
|
|
971
1041
|
routes() {
|
|
972
1042
|
return this.middleware();
|
|
973
1043
|
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Register an event handler on the router.
|
|
1046
|
+
*
|
|
1047
|
+
* @experimental This API is experimental and may change in future versions.
|
|
1048
|
+
*
|
|
1049
|
+
* **Active events:**
|
|
1050
|
+
* - `'not-found'` — fires when no route matched path + method. Handlers are
|
|
1051
|
+
* composed and called instead of `next()`, so they are responsible for
|
|
1052
|
+
* calling `next()` themselves if they want to pass control downstream.
|
|
1053
|
+
*
|
|
1054
|
+
* @example
|
|
1055
|
+
*
|
|
1056
|
+
* All three forms are equivalent:
|
|
1057
|
+
*
|
|
1058
|
+
* ```javascript
|
|
1059
|
+
* import { RouterEvents } from '@koa/router';
|
|
1060
|
+
*
|
|
1061
|
+
* // Named constant (recommended — autocomplete + refactor safe)
|
|
1062
|
+
* router.on(RouterEvents.NotFound, handler);
|
|
1063
|
+
*
|
|
1064
|
+
* // Selector function (fluent style)
|
|
1065
|
+
* router.on((events) => events.NotFound, handler);
|
|
1066
|
+
*
|
|
1067
|
+
* // Raw string (still accepted)
|
|
1068
|
+
* router.on('not-found', handler);
|
|
1069
|
+
* ```
|
|
1070
|
+
*
|
|
1071
|
+
* Multiple handlers compose in registration order:
|
|
1072
|
+
*
|
|
1073
|
+
* ```javascript
|
|
1074
|
+
* router.on(RouterEvents.NotFound, async (ctx, next) => {
|
|
1075
|
+
* console.log('no route matched', ctx.path);
|
|
1076
|
+
* await next();
|
|
1077
|
+
* });
|
|
1078
|
+
* router.on(RouterEvents.NotFound, (ctx) => {
|
|
1079
|
+
* ctx.status = 404;
|
|
1080
|
+
* ctx.body = { error: 'Not Found' };
|
|
1081
|
+
* });
|
|
1082
|
+
* ```
|
|
1083
|
+
*
|
|
1084
|
+
* @param event - Event name string, `RouterEvents` constant, or selector
|
|
1085
|
+
* function `(events) => events.NotFound` (see `RouterEventSelector`)
|
|
1086
|
+
* @param handler - Middleware to run when the event fires
|
|
1087
|
+
* @returns This router instance for chaining
|
|
1088
|
+
*/
|
|
1089
|
+
on(event, handler) {
|
|
1090
|
+
this._events.register(resolveEvent(event), handler);
|
|
1091
|
+
return this;
|
|
1092
|
+
}
|
|
974
1093
|
/**
|
|
975
1094
|
* Returns separate middleware for responding to `OPTIONS` requests with
|
|
976
1095
|
* an `Allow` header containing the allowed methods, as well as responding
|
|
@@ -1448,6 +1567,7 @@ for (const httpMethod of httpMethods) {
|
|
|
1448
1567
|
}
|
|
1449
1568
|
export {
|
|
1450
1569
|
Router,
|
|
1570
|
+
RouterEvents,
|
|
1451
1571
|
createParameterValidationMiddleware,
|
|
1452
1572
|
router_default as default
|
|
1453
1573
|
};
|