@koa/router 15.1.2 → 15.2.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 +30 -0
- package/dist/index.d.mts +44 -1
- package/dist/index.d.ts +44 -1
- package/dist/index.js +55 -4
- package/dist/index.mjs +50 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -490,6 +490,36 @@ router.get('/files/{/*path}', (ctx) => {
|
|
|
490
490
|
|
|
491
491
|
**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.
|
|
492
492
|
|
|
493
|
+
**Helper for parameter validation (v14+)** <small>(Added on v15.2)</small>
|
|
494
|
+
|
|
495
|
+
If you want to keep regex-style validation, register a param middleware instead:
|
|
496
|
+
|
|
497
|
+
```javascript
|
|
498
|
+
import Router, { createParameterValidationMiddleware } from '@koa/router';
|
|
499
|
+
|
|
500
|
+
const uuid =
|
|
501
|
+
/^[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}$/;
|
|
502
|
+
|
|
503
|
+
const validateId = createParameterValidationMiddleware('id', uuid);
|
|
504
|
+
|
|
505
|
+
router.param('id', validateId).get('/role/:id', middleware);
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Or validate inline on a specific route:
|
|
509
|
+
|
|
510
|
+
```javascript
|
|
511
|
+
import Router, { createParameterValidationMiddleware } from '@koa/router';
|
|
512
|
+
|
|
513
|
+
const uuid =
|
|
514
|
+
/^[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}$/;
|
|
515
|
+
|
|
516
|
+
router.get(
|
|
517
|
+
'/role/:id',
|
|
518
|
+
createParameterValidationMiddleware('id', uuid),
|
|
519
|
+
middleware
|
|
520
|
+
);
|
|
521
|
+
```
|
|
522
|
+
|
|
493
523
|
### router.routes()
|
|
494
524
|
|
|
495
525
|
Returns router middleware which dispatches matched routes.
|
package/dist/index.d.mts
CHANGED
|
@@ -842,4 +842,47 @@ type RouterMethodFunction<StateT = DefaultState, ContextT = DefaultContext> = {
|
|
|
842
842
|
*/
|
|
843
843
|
type RouterWithMethods<M extends string, StateT = DefaultState, ContextT = DefaultContext> = RouterInstance<StateT, ContextT> & Record<Lowercase<M>, RouterMethodFunction<StateT, ContextT>>;
|
|
844
844
|
|
|
845
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Parameter validation helpers.
|
|
847
|
+
*
|
|
848
|
+
* These utilities exist to help migrate legacy `:param(regex)` usage from older
|
|
849
|
+
* router/path-to-regexp versions to v14+ (path-to-regexp v8), where inline
|
|
850
|
+
* parameter regexes are no longer supported in route strings.
|
|
851
|
+
*/
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Options for createParameterValidationMiddleware helper
|
|
855
|
+
*/
|
|
856
|
+
type ParameterValidationOptions = {
|
|
857
|
+
/**
|
|
858
|
+
* HTTP status to use when the value does not match
|
|
859
|
+
* @default 400
|
|
860
|
+
*/
|
|
861
|
+
status?: number;
|
|
862
|
+
/**
|
|
863
|
+
* Error message to use when the value does not match
|
|
864
|
+
* @default `Invalid value for parameter "<parameterName>"`
|
|
865
|
+
*/
|
|
866
|
+
message?: string;
|
|
867
|
+
/**
|
|
868
|
+
* Whether the error message should be exposed to the client.
|
|
869
|
+
* Passed through to HttpError#expose.
|
|
870
|
+
*/
|
|
871
|
+
expose?: boolean;
|
|
872
|
+
/**
|
|
873
|
+
* Optional custom error factory. If provided, it is used
|
|
874
|
+
* instead of the default HttpError.
|
|
875
|
+
*/
|
|
876
|
+
createError?: (parameterName: string, value: string) => Error;
|
|
877
|
+
};
|
|
878
|
+
/**
|
|
879
|
+
* Convenience helper to recreate legacy `:param(regex)` validation.
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* const validateUuid = createParameterValidationMiddleware('id', uuidRegex);
|
|
883
|
+
* router.param('id', validateUuid).get('/role/:id', handler);
|
|
884
|
+
* router.get('/role/:id', createParameterValidationMiddleware('id', uuidRegex)
|
|
885
|
+
*/
|
|
886
|
+
declare function createParameterValidationMiddleware(parameterName: string, pattern: RegExp, options?: ParameterValidationOptions): RouterMiddleware<any, any, any> & RouterParameterMiddleware<any, any, any>;
|
|
887
|
+
|
|
888
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -842,4 +842,47 @@ type RouterMethodFunction<StateT = DefaultState, ContextT = DefaultContext> = {
|
|
|
842
842
|
*/
|
|
843
843
|
type RouterWithMethods<M extends string, StateT = DefaultState, ContextT = DefaultContext> = RouterInstance<StateT, ContextT> & Record<Lowercase<M>, RouterMethodFunction<StateT, ContextT>>;
|
|
844
844
|
|
|
845
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Parameter validation helpers.
|
|
847
|
+
*
|
|
848
|
+
* These utilities exist to help migrate legacy `:param(regex)` usage from older
|
|
849
|
+
* router/path-to-regexp versions to v14+ (path-to-regexp v8), where inline
|
|
850
|
+
* parameter regexes are no longer supported in route strings.
|
|
851
|
+
*/
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Options for createParameterValidationMiddleware helper
|
|
855
|
+
*/
|
|
856
|
+
type ParameterValidationOptions = {
|
|
857
|
+
/**
|
|
858
|
+
* HTTP status to use when the value does not match
|
|
859
|
+
* @default 400
|
|
860
|
+
*/
|
|
861
|
+
status?: number;
|
|
862
|
+
/**
|
|
863
|
+
* Error message to use when the value does not match
|
|
864
|
+
* @default `Invalid value for parameter "<parameterName>"`
|
|
865
|
+
*/
|
|
866
|
+
message?: string;
|
|
867
|
+
/**
|
|
868
|
+
* Whether the error message should be exposed to the client.
|
|
869
|
+
* Passed through to HttpError#expose.
|
|
870
|
+
*/
|
|
871
|
+
expose?: boolean;
|
|
872
|
+
/**
|
|
873
|
+
* Optional custom error factory. If provided, it is used
|
|
874
|
+
* instead of the default HttpError.
|
|
875
|
+
*/
|
|
876
|
+
createError?: (parameterName: string, value: string) => Error;
|
|
877
|
+
};
|
|
878
|
+
/**
|
|
879
|
+
* Convenience helper to recreate legacy `:param(regex)` validation.
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* const validateUuid = createParameterValidationMiddleware('id', uuidRegex);
|
|
883
|
+
* router.param('id', validateUuid).get('/role/:id', handler);
|
|
884
|
+
* router.get('/role/:id', createParameterValidationMiddleware('id', uuidRegex)
|
|
885
|
+
*/
|
|
886
|
+
declare function createParameterValidationMiddleware(parameterName: string, pattern: RegExp, options?: ParameterValidationOptions): RouterMiddleware<any, any, any> & RouterParameterMiddleware<any, any, any>;
|
|
887
|
+
|
|
888
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -31,13 +31,63 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Router: () => Router,
|
|
34
|
+
createParameterValidationMiddleware: () => createParameterValidationMiddleware,
|
|
34
35
|
default: () => router_default
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(index_exports);
|
|
37
38
|
|
|
39
|
+
// src/utils/parameter-match.ts
|
|
40
|
+
var import_http_errors = __toESM(require("http-errors"));
|
|
41
|
+
function createParameterValidationMiddleware(parameterName, pattern, options = {}) {
|
|
42
|
+
if (!(pattern instanceof RegExp)) {
|
|
43
|
+
throw new TypeError("pattern must be a RegExp instance");
|
|
44
|
+
}
|
|
45
|
+
const matcher = new RegExp(pattern.source, pattern.flags);
|
|
46
|
+
const createDefaultHttpError = (message) => {
|
|
47
|
+
const httpError = (0, import_http_errors.default)(options.status ?? 400, message);
|
|
48
|
+
if (options.expose !== void 0) {
|
|
49
|
+
httpError.expose = options.expose;
|
|
50
|
+
}
|
|
51
|
+
return httpError;
|
|
52
|
+
};
|
|
53
|
+
const validateValue = (value) => {
|
|
54
|
+
if (matcher.global || matcher.sticky) {
|
|
55
|
+
matcher.lastIndex = 0;
|
|
56
|
+
}
|
|
57
|
+
if (matcher.test(value)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (options.createError) {
|
|
61
|
+
throw options.createError(parameterName, value);
|
|
62
|
+
}
|
|
63
|
+
throw createDefaultHttpError(
|
|
64
|
+
options.message ?? `Invalid value for parameter "${parameterName}": "${value}"`
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
const middleware = async (argument1, argument2, argument3) => {
|
|
68
|
+
if (typeof argument1 !== "string") {
|
|
69
|
+
const context = argument1;
|
|
70
|
+
const next2 = argument2;
|
|
71
|
+
const parameterValue = context.params && parameterName in context.params ? context.params[parameterName] : void 0;
|
|
72
|
+
if (typeof parameterValue !== "string") {
|
|
73
|
+
throw createDefaultHttpError(
|
|
74
|
+
options.message ?? `Missing required parameter "${parameterName}" in route params`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
validateValue(parameterValue);
|
|
78
|
+
return next2();
|
|
79
|
+
}
|
|
80
|
+
const value = argument1;
|
|
81
|
+
const next = argument3;
|
|
82
|
+
validateValue(value);
|
|
83
|
+
return next();
|
|
84
|
+
};
|
|
85
|
+
return middleware;
|
|
86
|
+
}
|
|
87
|
+
|
|
38
88
|
// src/router.ts
|
|
39
89
|
var import_koa_compose = __toESM(require("koa-compose"));
|
|
40
|
-
var
|
|
90
|
+
var import_http_errors2 = __toESM(require("http-errors"));
|
|
41
91
|
|
|
42
92
|
// src/layer.ts
|
|
43
93
|
var import_node_url = require("url");
|
|
@@ -1058,7 +1108,7 @@ var RouterImplementation = class {
|
|
|
1058
1108
|
*/
|
|
1059
1109
|
_handleNotImplemented(context, allowedMethodsList, options) {
|
|
1060
1110
|
if (options.throw) {
|
|
1061
|
-
const error = typeof options.notImplemented === "function" ? options.notImplemented() : new
|
|
1111
|
+
const error = typeof options.notImplemented === "function" ? options.notImplemented() : new import_http_errors2.default.NotImplemented();
|
|
1062
1112
|
throw error;
|
|
1063
1113
|
}
|
|
1064
1114
|
context.status = 501;
|
|
@@ -1079,7 +1129,7 @@ var RouterImplementation = class {
|
|
|
1079
1129
|
*/
|
|
1080
1130
|
_handleMethodNotAllowed(context, allowedMethodsList, options) {
|
|
1081
1131
|
if (options.throw) {
|
|
1082
|
-
const error = typeof options.methodNotAllowed === "function" ? options.methodNotAllowed() : new
|
|
1132
|
+
const error = typeof options.methodNotAllowed === "function" ? options.methodNotAllowed() : new import_http_errors2.default.MethodNotAllowed();
|
|
1083
1133
|
throw error;
|
|
1084
1134
|
}
|
|
1085
1135
|
context.status = 405;
|
|
@@ -1436,7 +1486,8 @@ for (const httpMethod of httpMethods) {
|
|
|
1436
1486
|
}
|
|
1437
1487
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1438
1488
|
0 && (module.exports = {
|
|
1439
|
-
Router
|
|
1489
|
+
Router,
|
|
1490
|
+
createParameterValidationMiddleware
|
|
1440
1491
|
});
|
|
1441
1492
|
if (module.exports.default) {
|
|
1442
1493
|
Object.assign(module.exports.default, module.exports);
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
// src/utils/parameter-match.ts
|
|
2
|
+
import createHttpError from "http-errors";
|
|
3
|
+
function createParameterValidationMiddleware(parameterName, pattern, options = {}) {
|
|
4
|
+
if (!(pattern instanceof RegExp)) {
|
|
5
|
+
throw new TypeError("pattern must be a RegExp instance");
|
|
6
|
+
}
|
|
7
|
+
const matcher = new RegExp(pattern.source, pattern.flags);
|
|
8
|
+
const createDefaultHttpError = (message) => {
|
|
9
|
+
const httpError = createHttpError(options.status ?? 400, message);
|
|
10
|
+
if (options.expose !== void 0) {
|
|
11
|
+
httpError.expose = options.expose;
|
|
12
|
+
}
|
|
13
|
+
return httpError;
|
|
14
|
+
};
|
|
15
|
+
const validateValue = (value) => {
|
|
16
|
+
if (matcher.global || matcher.sticky) {
|
|
17
|
+
matcher.lastIndex = 0;
|
|
18
|
+
}
|
|
19
|
+
if (matcher.test(value)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (options.createError) {
|
|
23
|
+
throw options.createError(parameterName, value);
|
|
24
|
+
}
|
|
25
|
+
throw createDefaultHttpError(
|
|
26
|
+
options.message ?? `Invalid value for parameter "${parameterName}": "${value}"`
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
const middleware = async (argument1, argument2, argument3) => {
|
|
30
|
+
if (typeof argument1 !== "string") {
|
|
31
|
+
const context = argument1;
|
|
32
|
+
const next2 = argument2;
|
|
33
|
+
const parameterValue = context.params && parameterName in context.params ? context.params[parameterName] : void 0;
|
|
34
|
+
if (typeof parameterValue !== "string") {
|
|
35
|
+
throw createDefaultHttpError(
|
|
36
|
+
options.message ?? `Missing required parameter "${parameterName}" in route params`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
validateValue(parameterValue);
|
|
40
|
+
return next2();
|
|
41
|
+
}
|
|
42
|
+
const value = argument1;
|
|
43
|
+
const next = argument3;
|
|
44
|
+
validateValue(value);
|
|
45
|
+
return next();
|
|
46
|
+
};
|
|
47
|
+
return middleware;
|
|
48
|
+
}
|
|
49
|
+
|
|
1
50
|
// src/router.ts
|
|
2
51
|
import compose from "koa-compose";
|
|
3
52
|
import HttpError from "http-errors";
|
|
@@ -1399,5 +1448,6 @@ for (const httpMethod of httpMethods) {
|
|
|
1399
1448
|
}
|
|
1400
1449
|
export {
|
|
1401
1450
|
Router,
|
|
1451
|
+
createParameterValidationMiddleware,
|
|
1402
1452
|
router_default as default
|
|
1403
1453
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koa/router",
|
|
3
3
|
"description": "Router middleware for koa. Maintained by Forward Email and Lad.",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.2.0",
|
|
5
5
|
"author": "Alex Mingoia <talk@alexmingoia.com>",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/koajs/router/issues",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"test:recipes": "TS_NODE_PROJECT=tsconfig.recipes.json node --require ts-node/register --test recipes/**/*.test.ts",
|
|
111
111
|
"pretest:all": "npm run lint && npm run build",
|
|
112
112
|
"test:all": "TS_NODE_PROJECT=tsconfig.ts-node.json node --require ts-node/register --test test/*.test.ts test/**/*.test.ts recipes/**/*.test.ts",
|
|
113
|
-
"test:coverage": "c8 npm run test:all",
|
|
113
|
+
"test:coverage": "c8 --all --exclude eslint.config.js --exclude tsup.config.ts --exclude src/types.ts --exclude \"bench/**\" --exclude \"dist/**\" --exclude \"recipes/**\" --exclude \"test/**\" --exclude-after-remap npm run test:all",
|
|
114
114
|
"ts:check": "tsc --noEmit --project tsconfig.typecheck.json",
|
|
115
115
|
"ts:check:test": "tsc --noEmit --project tsconfig.test.json",
|
|
116
116
|
"prebuild": "rimraf dist",
|