clear-router 2.1.10 → 2.1.12
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 +1 -0
- package/dist/{basic-Chn8OGPD.d.cts → basic-C_1O6RVq.d.cts} +22 -3
- package/dist/{basic-DJmmZq1h.d.mts → basic-cLeny2Zk.d.mts} +22 -3
- package/dist/express/index.cjs +89 -2
- package/dist/express/index.d.cts +11 -1
- package/dist/express/index.d.mts +11 -1
- package/dist/express/index.mjs +89 -2
- package/dist/h3/index.cjs +85 -3
- package/dist/h3/index.d.cts +6 -1
- package/dist/h3/index.d.mts +6 -1
- package/dist/h3/index.mjs +85 -3
- package/dist/index.d.cts +8 -1
- package/dist/index.d.mts +8 -1
- package/dist/types/basic.d.mts +12 -1
- package/dist/types/express.d.mts +5 -2
- package/dist/types/h3.d.mts +7 -2
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -42,6 +42,7 @@ yarn add clear-router express
|
|
|
42
42
|
|
|
43
43
|
- Simple and clean route declarations (get, post, put, delete, patch, options, head)
|
|
44
44
|
- Grouped routes with prefix
|
|
45
|
+
- Method override support via body or header keys (configurable)
|
|
45
46
|
- Middleware stack: per-route and group-level
|
|
46
47
|
- Controller-method pair as route handler
|
|
47
48
|
- Supports HttpContext style handlers: { req, res, next }
|
|
@@ -5,10 +5,15 @@ import { H3, H3Event, Middleware as Middleware$1, TypedServerRequest } from "h3"
|
|
|
5
5
|
type H3App = Omit<H3['fetch'], 'fetch'> & {
|
|
6
6
|
fetch: (request: TypedServerRequest) => Promise<Response>;
|
|
7
7
|
};
|
|
8
|
+
type HttpRequest = H3Event['req'] & {
|
|
9
|
+
getBody: () => Record<string, any>;
|
|
10
|
+
};
|
|
8
11
|
/**
|
|
9
12
|
* HTTP context passed to route handlers
|
|
10
13
|
*/
|
|
11
|
-
type HttpContext$1 = H3Event & {
|
|
14
|
+
type HttpContext$1 = Omit<H3Event, 'req'> & {
|
|
15
|
+
req: HttpRequest;
|
|
16
|
+
};
|
|
12
17
|
/**
|
|
13
18
|
* Route handler function type
|
|
14
19
|
*/
|
|
@@ -66,11 +71,14 @@ declare class ClearRequest<X = any, M = Middleware$1 | Middleware> {
|
|
|
66
71
|
}
|
|
67
72
|
//#endregion
|
|
68
73
|
//#region types/express.d.ts
|
|
74
|
+
interface RequestWithGetBody extends Request {
|
|
75
|
+
getBody: () => Record<string, any>;
|
|
76
|
+
}
|
|
69
77
|
/**
|
|
70
78
|
* HTTP context passed to route handlers
|
|
71
79
|
*/
|
|
72
80
|
interface HttpContext {
|
|
73
|
-
req:
|
|
81
|
+
req: RequestWithGetBody;
|
|
74
82
|
res: Response$1;
|
|
75
83
|
next: NextFunction;
|
|
76
84
|
}
|
|
@@ -115,5 +123,16 @@ type ControllerAction = 'index' | 'show' | 'create' | 'update' | 'destroy';
|
|
|
115
123
|
*/
|
|
116
124
|
type RequestData = Record<string, any>;
|
|
117
125
|
type ApiResourceMiddleware<M extends Middleware | Middleware$1> = M | M[] | { [K in ControllerAction]?: M | M[] };
|
|
126
|
+
interface RouterConfig {
|
|
127
|
+
/**
|
|
128
|
+
* Configuration for method override functionality, allowing clients to use a
|
|
129
|
+
* specific header or body parameter to override the HTTP method.
|
|
130
|
+
*/
|
|
131
|
+
methodOverride?: {
|
|
132
|
+
/** Whether method override is enabled */enabled?: boolean; /** Keys in the request body to check for method override */
|
|
133
|
+
bodyKeys?: string[] | string; /** Keys in the request headers to check for method override */
|
|
134
|
+
headerKeys?: string[] | string;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
118
137
|
//#endregion
|
|
119
|
-
export {
|
|
138
|
+
export { Handler as a, Route as c, HttpContext$1 as d, Middleware$1 as f, RouterConfig as i, H3App as l, ControllerAction as n, HttpContext as o, HttpMethod as r, Middleware as s, ApiResourceMiddleware as t, Handler$1 as u };
|
|
@@ -5,10 +5,15 @@ import { NextFunction, Request, Response as Response$1 } from "express";
|
|
|
5
5
|
type H3App = Omit<H3['fetch'], 'fetch'> & {
|
|
6
6
|
fetch: (request: TypedServerRequest) => Promise<Response>;
|
|
7
7
|
};
|
|
8
|
+
type HttpRequest = H3Event['req'] & {
|
|
9
|
+
getBody: () => Record<string, any>;
|
|
10
|
+
};
|
|
8
11
|
/**
|
|
9
12
|
* HTTP context passed to route handlers
|
|
10
13
|
*/
|
|
11
|
-
type HttpContext$1 = H3Event & {
|
|
14
|
+
type HttpContext$1 = Omit<H3Event, 'req'> & {
|
|
15
|
+
req: HttpRequest;
|
|
16
|
+
};
|
|
12
17
|
/**
|
|
13
18
|
* Route handler function type
|
|
14
19
|
*/
|
|
@@ -66,11 +71,14 @@ declare class ClearRequest<X = any, M = Middleware$1 | Middleware> {
|
|
|
66
71
|
}
|
|
67
72
|
//#endregion
|
|
68
73
|
//#region types/express.d.ts
|
|
74
|
+
interface RequestWithGetBody extends Request {
|
|
75
|
+
getBody: () => Record<string, any>;
|
|
76
|
+
}
|
|
69
77
|
/**
|
|
70
78
|
* HTTP context passed to route handlers
|
|
71
79
|
*/
|
|
72
80
|
interface HttpContext {
|
|
73
|
-
req:
|
|
81
|
+
req: RequestWithGetBody;
|
|
74
82
|
res: Response$1;
|
|
75
83
|
next: NextFunction;
|
|
76
84
|
}
|
|
@@ -115,5 +123,16 @@ type ControllerAction = 'index' | 'show' | 'create' | 'update' | 'destroy';
|
|
|
115
123
|
*/
|
|
116
124
|
type RequestData = Record<string, any>;
|
|
117
125
|
type ApiResourceMiddleware<M extends Middleware | Middleware$1> = M | M[] | { [K in ControllerAction]?: M | M[] };
|
|
126
|
+
interface RouterConfig {
|
|
127
|
+
/**
|
|
128
|
+
* Configuration for method override functionality, allowing clients to use a
|
|
129
|
+
* specific header or body parameter to override the HTTP method.
|
|
130
|
+
*/
|
|
131
|
+
methodOverride?: {
|
|
132
|
+
/** Whether method override is enabled */enabled?: boolean; /** Keys in the request body to check for method override */
|
|
133
|
+
bodyKeys?: string[] | string; /** Keys in the request headers to check for method override */
|
|
134
|
+
headerKeys?: string[] | string;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
118
137
|
//#endregion
|
|
119
|
-
export {
|
|
138
|
+
export { Handler as a, Route as c, HttpContext$1 as d, Middleware$1 as f, RouterConfig as i, H3App as l, ControllerAction as n, HttpContext as o, HttpMethod as r, Middleware as s, ApiResourceMiddleware as t, Handler$1 as u };
|
package/dist/express/index.cjs
CHANGED
|
@@ -11,6 +11,11 @@ let node_async_hooks = require("node:async_hooks");
|
|
|
11
11
|
* @repository https://github.com/toneflix/clear-router
|
|
12
12
|
*/
|
|
13
13
|
var Router = class Router {
|
|
14
|
+
static config = { methodOverride: {
|
|
15
|
+
enabled: true,
|
|
16
|
+
bodyKeys: ["_method"],
|
|
17
|
+
headerKeys: ["x-http-method"]
|
|
18
|
+
} };
|
|
14
19
|
static groupContext = new node_async_hooks.AsyncLocalStorage();
|
|
15
20
|
/**
|
|
16
21
|
* All registered routes
|
|
@@ -45,6 +50,56 @@ var Router = class Router {
|
|
|
45
50
|
return "/" + path.split("/").filter(Boolean).join("/");
|
|
46
51
|
}
|
|
47
52
|
/**
|
|
53
|
+
* Configure router settings to modify behavior.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Configuration options for the router
|
|
56
|
+
* @returns
|
|
57
|
+
*/
|
|
58
|
+
static configure(options) {
|
|
59
|
+
if (!this.config.methodOverride) this.config.methodOverride = {
|
|
60
|
+
enabled: true,
|
|
61
|
+
bodyKeys: ["_method"],
|
|
62
|
+
headerKeys: ["x-http-method"]
|
|
63
|
+
};
|
|
64
|
+
const override = options?.methodOverride;
|
|
65
|
+
if (!override) return;
|
|
66
|
+
if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
|
|
67
|
+
const bodyKeys = override.bodyKeys;
|
|
68
|
+
if (typeof bodyKeys !== "undefined") this.config.methodOverride.bodyKeys = (Array.isArray(bodyKeys) ? bodyKeys : [bodyKeys]).map((e) => String(e).trim()).filter(Boolean);
|
|
69
|
+
const headerKeys = override.headerKeys;
|
|
70
|
+
if (typeof headerKeys !== "undefined") this.config.methodOverride.headerKeys = (Array.isArray(headerKeys) ? headerKeys : [headerKeys]).map((e) => String(e).trim().toLowerCase()).filter(Boolean);
|
|
71
|
+
}
|
|
72
|
+
static ensureRequestBodyAccessor(req) {
|
|
73
|
+
if (typeof req.getBody !== "function") req.getBody = () => req.body ?? {};
|
|
74
|
+
}
|
|
75
|
+
static resolveMethodOverride(method, headers, body) {
|
|
76
|
+
if (!this.config.methodOverride?.enabled || method.toLowerCase() !== "post") return null;
|
|
77
|
+
let override;
|
|
78
|
+
for (const key of this.config.methodOverride?.headerKeys || []) {
|
|
79
|
+
const value = headers?.[key];
|
|
80
|
+
if (Array.isArray(value) ? value[0] : value) {
|
|
81
|
+
override = Array.isArray(value) ? value[0] : value;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!override && body && typeof body === "object") for (const key of this.config.methodOverride?.bodyKeys || []) {
|
|
86
|
+
const value = body[key];
|
|
87
|
+
if (typeof value !== "undefined" && value !== null && value !== "") {
|
|
88
|
+
override = value;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const normalized = String(override || "").trim().toLowerCase();
|
|
93
|
+
if (!normalized) return null;
|
|
94
|
+
if ([
|
|
95
|
+
"put",
|
|
96
|
+
"patch",
|
|
97
|
+
"delete",
|
|
98
|
+
"post"
|
|
99
|
+
].includes(normalized)) return normalized;
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
48
103
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
49
104
|
* @param methods - HTTP method(s) for the route
|
|
50
105
|
* @param path - Route path
|
|
@@ -256,8 +311,39 @@ var Router = class Router {
|
|
|
256
311
|
console.error("[ROUTES]", error.message);
|
|
257
312
|
throw error;
|
|
258
313
|
}
|
|
259
|
-
router[method](route.path,
|
|
314
|
+
router[method](route.path, (req, res, next) => {
|
|
315
|
+
Router.ensureRequestBodyAccessor(req);
|
|
316
|
+
const override = Router.resolveMethodOverride(req.method, req.headers, req.body);
|
|
317
|
+
if (method === "post" && override && override !== "post") return next("route");
|
|
318
|
+
return next();
|
|
319
|
+
}, ...route.middlewares || [], async (req, res, next) => {
|
|
320
|
+
try {
|
|
321
|
+
Router.ensureRequestBodyAccessor(req);
|
|
322
|
+
const ctx = {
|
|
323
|
+
req,
|
|
324
|
+
res,
|
|
325
|
+
next
|
|
326
|
+
};
|
|
327
|
+
const inst = instance ?? route;
|
|
328
|
+
await Router.bindRequestToInstance(ctx, inst, route);
|
|
329
|
+
const result = handlerFunction(ctx, inst.clearRequest);
|
|
330
|
+
await Promise.resolve(result);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
next(error);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
if ([
|
|
336
|
+
"put",
|
|
337
|
+
"patch",
|
|
338
|
+
"delete"
|
|
339
|
+
].includes(method)) router.post(route.path, (req, res, next) => {
|
|
340
|
+
Router.ensureRequestBodyAccessor(req);
|
|
341
|
+
if (Router.resolveMethodOverride(req.method, req.headers, req.body) !== method) return next("route");
|
|
342
|
+
req.method = method.toUpperCase();
|
|
343
|
+
return next();
|
|
344
|
+
}, ...route.middlewares || [], async (req, res, next) => {
|
|
260
345
|
try {
|
|
346
|
+
Router.ensureRequestBodyAccessor(req);
|
|
261
347
|
const ctx = {
|
|
262
348
|
req,
|
|
263
349
|
res,
|
|
@@ -276,8 +362,9 @@ var Router = class Router {
|
|
|
276
362
|
}
|
|
277
363
|
static async bindRequestToInstance(ctx, instance, route) {
|
|
278
364
|
if (!instance) return;
|
|
365
|
+
Router.ensureRequestBodyAccessor(ctx.req);
|
|
279
366
|
instance.ctx = ctx;
|
|
280
|
-
instance.body = ctx.req.
|
|
367
|
+
instance.body = ctx.req.getBody();
|
|
281
368
|
instance.query = ctx.req.query;
|
|
282
369
|
instance.params = ctx.req.params;
|
|
283
370
|
instance.clearRequest = new require_Route.ClearRequest({
|
package/dist/express/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as Handler, c as Route, i as RouterConfig, n as ControllerAction, o as HttpContext, r as HttpMethod, s as Middleware, t as ApiResourceMiddleware } from "../basic-C_1O6RVq.cjs";
|
|
2
2
|
import { Router as Router$1 } from "express";
|
|
3
3
|
|
|
4
4
|
//#region src/express/router.d.ts
|
|
@@ -10,6 +10,7 @@ import { Router as Router$1 } from "express";
|
|
|
10
10
|
* @repository https://github.com/toneflix/clear-router
|
|
11
11
|
*/
|
|
12
12
|
declare class Router {
|
|
13
|
+
static config: RouterConfig;
|
|
13
14
|
private static readonly groupContext;
|
|
14
15
|
/**
|
|
15
16
|
* All registered routes
|
|
@@ -41,6 +42,15 @@ declare class Router {
|
|
|
41
42
|
* @returns Normalized path
|
|
42
43
|
*/
|
|
43
44
|
static normalizePath(path: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Configure router settings to modify behavior.
|
|
47
|
+
*
|
|
48
|
+
* @param options - Configuration options for the router
|
|
49
|
+
* @returns
|
|
50
|
+
*/
|
|
51
|
+
static configure(options?: RouterConfig): void;
|
|
52
|
+
private static ensureRequestBodyAccessor;
|
|
53
|
+
private static resolveMethodOverride;
|
|
44
54
|
/**
|
|
45
55
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
46
56
|
* @param methods - HTTP method(s) for the route
|
package/dist/express/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as Handler, c as Route, i as RouterConfig, n as ControllerAction, o as HttpContext, r as HttpMethod, s as Middleware, t as ApiResourceMiddleware } from "../basic-cLeny2Zk.mjs";
|
|
2
2
|
import { Router as Router$1 } from "express";
|
|
3
3
|
|
|
4
4
|
//#region src/express/router.d.ts
|
|
@@ -10,6 +10,7 @@ import { Router as Router$1 } from "express";
|
|
|
10
10
|
* @repository https://github.com/toneflix/clear-router
|
|
11
11
|
*/
|
|
12
12
|
declare class Router {
|
|
13
|
+
static config: RouterConfig;
|
|
13
14
|
private static readonly groupContext;
|
|
14
15
|
/**
|
|
15
16
|
* All registered routes
|
|
@@ -41,6 +42,15 @@ declare class Router {
|
|
|
41
42
|
* @returns Normalized path
|
|
42
43
|
*/
|
|
43
44
|
static normalizePath(path: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Configure router settings to modify behavior.
|
|
47
|
+
*
|
|
48
|
+
* @param options - Configuration options for the router
|
|
49
|
+
* @returns
|
|
50
|
+
*/
|
|
51
|
+
static configure(options?: RouterConfig): void;
|
|
52
|
+
private static ensureRequestBodyAccessor;
|
|
53
|
+
private static resolveMethodOverride;
|
|
44
54
|
/**
|
|
45
55
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
46
56
|
* @param methods - HTTP method(s) for the route
|
package/dist/express/index.mjs
CHANGED
|
@@ -10,6 +10,11 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
10
10
|
* @repository https://github.com/toneflix/clear-router
|
|
11
11
|
*/
|
|
12
12
|
var Router = class Router {
|
|
13
|
+
static config = { methodOverride: {
|
|
14
|
+
enabled: true,
|
|
15
|
+
bodyKeys: ["_method"],
|
|
16
|
+
headerKeys: ["x-http-method"]
|
|
17
|
+
} };
|
|
13
18
|
static groupContext = new AsyncLocalStorage();
|
|
14
19
|
/**
|
|
15
20
|
* All registered routes
|
|
@@ -44,6 +49,56 @@ var Router = class Router {
|
|
|
44
49
|
return "/" + path.split("/").filter(Boolean).join("/");
|
|
45
50
|
}
|
|
46
51
|
/**
|
|
52
|
+
* Configure router settings to modify behavior.
|
|
53
|
+
*
|
|
54
|
+
* @param options - Configuration options for the router
|
|
55
|
+
* @returns
|
|
56
|
+
*/
|
|
57
|
+
static configure(options) {
|
|
58
|
+
if (!this.config.methodOverride) this.config.methodOverride = {
|
|
59
|
+
enabled: true,
|
|
60
|
+
bodyKeys: ["_method"],
|
|
61
|
+
headerKeys: ["x-http-method"]
|
|
62
|
+
};
|
|
63
|
+
const override = options?.methodOverride;
|
|
64
|
+
if (!override) return;
|
|
65
|
+
if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
|
|
66
|
+
const bodyKeys = override.bodyKeys;
|
|
67
|
+
if (typeof bodyKeys !== "undefined") this.config.methodOverride.bodyKeys = (Array.isArray(bodyKeys) ? bodyKeys : [bodyKeys]).map((e) => String(e).trim()).filter(Boolean);
|
|
68
|
+
const headerKeys = override.headerKeys;
|
|
69
|
+
if (typeof headerKeys !== "undefined") this.config.methodOverride.headerKeys = (Array.isArray(headerKeys) ? headerKeys : [headerKeys]).map((e) => String(e).trim().toLowerCase()).filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
static ensureRequestBodyAccessor(req) {
|
|
72
|
+
if (typeof req.getBody !== "function") req.getBody = () => req.body ?? {};
|
|
73
|
+
}
|
|
74
|
+
static resolveMethodOverride(method, headers, body) {
|
|
75
|
+
if (!this.config.methodOverride?.enabled || method.toLowerCase() !== "post") return null;
|
|
76
|
+
let override;
|
|
77
|
+
for (const key of this.config.methodOverride?.headerKeys || []) {
|
|
78
|
+
const value = headers?.[key];
|
|
79
|
+
if (Array.isArray(value) ? value[0] : value) {
|
|
80
|
+
override = Array.isArray(value) ? value[0] : value;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!override && body && typeof body === "object") for (const key of this.config.methodOverride?.bodyKeys || []) {
|
|
85
|
+
const value = body[key];
|
|
86
|
+
if (typeof value !== "undefined" && value !== null && value !== "") {
|
|
87
|
+
override = value;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const normalized = String(override || "").trim().toLowerCase();
|
|
92
|
+
if (!normalized) return null;
|
|
93
|
+
if ([
|
|
94
|
+
"put",
|
|
95
|
+
"patch",
|
|
96
|
+
"delete",
|
|
97
|
+
"post"
|
|
98
|
+
].includes(normalized)) return normalized;
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
47
102
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
48
103
|
* @param methods - HTTP method(s) for the route
|
|
49
104
|
* @param path - Route path
|
|
@@ -255,8 +310,39 @@ var Router = class Router {
|
|
|
255
310
|
console.error("[ROUTES]", error.message);
|
|
256
311
|
throw error;
|
|
257
312
|
}
|
|
258
|
-
router[method](route.path,
|
|
313
|
+
router[method](route.path, (req, res, next) => {
|
|
314
|
+
Router.ensureRequestBodyAccessor(req);
|
|
315
|
+
const override = Router.resolveMethodOverride(req.method, req.headers, req.body);
|
|
316
|
+
if (method === "post" && override && override !== "post") return next("route");
|
|
317
|
+
return next();
|
|
318
|
+
}, ...route.middlewares || [], async (req, res, next) => {
|
|
319
|
+
try {
|
|
320
|
+
Router.ensureRequestBodyAccessor(req);
|
|
321
|
+
const ctx = {
|
|
322
|
+
req,
|
|
323
|
+
res,
|
|
324
|
+
next
|
|
325
|
+
};
|
|
326
|
+
const inst = instance ?? route;
|
|
327
|
+
await Router.bindRequestToInstance(ctx, inst, route);
|
|
328
|
+
const result = handlerFunction(ctx, inst.clearRequest);
|
|
329
|
+
await Promise.resolve(result);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
next(error);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
if ([
|
|
335
|
+
"put",
|
|
336
|
+
"patch",
|
|
337
|
+
"delete"
|
|
338
|
+
].includes(method)) router.post(route.path, (req, res, next) => {
|
|
339
|
+
Router.ensureRequestBodyAccessor(req);
|
|
340
|
+
if (Router.resolveMethodOverride(req.method, req.headers, req.body) !== method) return next("route");
|
|
341
|
+
req.method = method.toUpperCase();
|
|
342
|
+
return next();
|
|
343
|
+
}, ...route.middlewares || [], async (req, res, next) => {
|
|
259
344
|
try {
|
|
345
|
+
Router.ensureRequestBodyAccessor(req);
|
|
260
346
|
const ctx = {
|
|
261
347
|
req,
|
|
262
348
|
res,
|
|
@@ -275,8 +361,9 @@ var Router = class Router {
|
|
|
275
361
|
}
|
|
276
362
|
static async bindRequestToInstance(ctx, instance, route) {
|
|
277
363
|
if (!instance) return;
|
|
364
|
+
Router.ensureRequestBodyAccessor(ctx.req);
|
|
278
365
|
instance.ctx = ctx;
|
|
279
|
-
instance.body = ctx.req.
|
|
366
|
+
instance.body = ctx.req.getBody();
|
|
280
367
|
instance.query = ctx.req.query;
|
|
281
368
|
instance.params = ctx.req.params;
|
|
282
369
|
instance.clearRequest = new ClearRequest({
|
package/dist/h3/index.cjs
CHANGED
|
@@ -11,6 +11,12 @@ let h3 = require("h3");
|
|
|
11
11
|
* @repository https://github.com/toneflix/clear-router
|
|
12
12
|
*/
|
|
13
13
|
var Router = class Router {
|
|
14
|
+
static config = { methodOverride: {
|
|
15
|
+
enabled: true,
|
|
16
|
+
bodyKeys: ["_method"],
|
|
17
|
+
headerKeys: ["x-http-method"]
|
|
18
|
+
} };
|
|
19
|
+
static bodyCache = /* @__PURE__ */ new WeakMap();
|
|
14
20
|
static groupContext = new node_async_hooks.AsyncLocalStorage();
|
|
15
21
|
/**
|
|
16
22
|
* All registered routes
|
|
@@ -44,6 +50,62 @@ var Router = class Router {
|
|
|
44
50
|
static normalizePath(path) {
|
|
45
51
|
return "/" + path.split("/").filter(Boolean).join("/");
|
|
46
52
|
}
|
|
53
|
+
static configure(options) {
|
|
54
|
+
if (!this.config.methodOverride) this.config.methodOverride = {
|
|
55
|
+
enabled: true,
|
|
56
|
+
bodyKeys: ["_method"],
|
|
57
|
+
headerKeys: ["x-http-method"]
|
|
58
|
+
};
|
|
59
|
+
const override = options?.methodOverride;
|
|
60
|
+
if (!override) return;
|
|
61
|
+
if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
|
|
62
|
+
const bodyKeys = override.bodyKeys;
|
|
63
|
+
if (typeof bodyKeys !== "undefined") this.config.methodOverride.bodyKeys = (Array.isArray(bodyKeys) ? bodyKeys : [bodyKeys]).map((e) => String(e).trim()).filter(Boolean);
|
|
64
|
+
const headerKeys = override.headerKeys;
|
|
65
|
+
if (typeof headerKeys !== "undefined") this.config.methodOverride.headerKeys = (Array.isArray(headerKeys) ? headerKeys : [headerKeys]).map((e) => String(e).trim().toLowerCase()).filter(Boolean);
|
|
66
|
+
}
|
|
67
|
+
static async readBodyCached(ctx) {
|
|
68
|
+
if (this.bodyCache.has(ctx)) {
|
|
69
|
+
const cached = this.bodyCache.get(ctx);
|
|
70
|
+
ctx.req.getBody = () => cached;
|
|
71
|
+
return cached;
|
|
72
|
+
}
|
|
73
|
+
let body = {};
|
|
74
|
+
if (ctx.req.headers.get("content-type")?.includes("multipart/form-data")) (await ctx.req.formData()).forEach((value, key) => {
|
|
75
|
+
body[key] = value;
|
|
76
|
+
});
|
|
77
|
+
else body = await (0, h3.readBody)(ctx) ?? {};
|
|
78
|
+
ctx.req.getBody = () => body;
|
|
79
|
+
this.bodyCache.set(ctx, body);
|
|
80
|
+
return body;
|
|
81
|
+
}
|
|
82
|
+
static resolveMethodOverride(method, headers, body) {
|
|
83
|
+
if (!this.config.methodOverride?.enabled || method.toLowerCase() !== "post") return null;
|
|
84
|
+
let override;
|
|
85
|
+
for (const key of this.config.methodOverride?.headerKeys || []) {
|
|
86
|
+
const value = headers.get(key);
|
|
87
|
+
if (value) {
|
|
88
|
+
override = value;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!override && body && typeof body === "object") for (const key of this.config.methodOverride?.bodyKeys || []) {
|
|
93
|
+
const value = body[key];
|
|
94
|
+
if (typeof value !== "undefined" && value !== null && value !== "") {
|
|
95
|
+
override = value;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const normalized = String(override || "").trim().toLowerCase();
|
|
100
|
+
if (!normalized) return null;
|
|
101
|
+
if ([
|
|
102
|
+
"put",
|
|
103
|
+
"patch",
|
|
104
|
+
"delete",
|
|
105
|
+
"post"
|
|
106
|
+
].includes(normalized)) return normalized;
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
47
109
|
/**
|
|
48
110
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
49
111
|
* @param methods - HTTP method(s) for the route
|
|
@@ -266,8 +328,28 @@ var Router = class Router {
|
|
|
266
328
|
app[method](route.path, async (event) => {
|
|
267
329
|
try {
|
|
268
330
|
const ctx = event;
|
|
331
|
+
const reqBody = await Router.readBodyCached(ctx);
|
|
332
|
+
const override = Router.resolveMethodOverride(ctx.req.method, ctx.req.headers, reqBody);
|
|
333
|
+
if (method === "post" && override && override !== "post") return;
|
|
334
|
+
const inst = instance ?? route;
|
|
335
|
+
await Router.bindRequestToInstance(ctx, inst, route, reqBody);
|
|
336
|
+
const result = handlerFunction(ctx, inst.clearRequest);
|
|
337
|
+
return await Promise.resolve(result);
|
|
338
|
+
} catch (error) {
|
|
339
|
+
return error;
|
|
340
|
+
}
|
|
341
|
+
}, { middleware: route.middlewares });
|
|
342
|
+
if ([
|
|
343
|
+
"put",
|
|
344
|
+
"patch",
|
|
345
|
+
"delete"
|
|
346
|
+
].includes(method)) app.post(route.path, async (event) => {
|
|
347
|
+
try {
|
|
348
|
+
const ctx = event;
|
|
349
|
+
const reqBody = await Router.readBodyCached(ctx);
|
|
350
|
+
if (Router.resolveMethodOverride(ctx.req.method, ctx.req.headers, reqBody) !== method) return;
|
|
269
351
|
const inst = instance ?? route;
|
|
270
|
-
await Router.bindRequestToInstance(ctx, inst, route);
|
|
352
|
+
await Router.bindRequestToInstance(ctx, inst, route, reqBody);
|
|
271
353
|
const result = handlerFunction(ctx, inst.clearRequest);
|
|
272
354
|
return await Promise.resolve(result);
|
|
273
355
|
} catch (error) {
|
|
@@ -278,10 +360,10 @@ var Router = class Router {
|
|
|
278
360
|
}
|
|
279
361
|
return app;
|
|
280
362
|
}
|
|
281
|
-
static async bindRequestToInstance(ctx, instance, route) {
|
|
363
|
+
static async bindRequestToInstance(ctx, instance, route, body) {
|
|
282
364
|
if (!instance) return;
|
|
283
365
|
instance.ctx = ctx;
|
|
284
|
-
instance.body = await
|
|
366
|
+
instance.body = body ?? await Router.readBodyCached(ctx);
|
|
285
367
|
instance.query = (0, h3.getQuery)(ctx);
|
|
286
368
|
instance.params = (0, h3.getRouterParams)(ctx, { decode: true });
|
|
287
369
|
instance.clearRequest = new require_Route.ClearRequest({
|
package/dist/h3/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as
|
|
1
|
+
import { c as Route, d as HttpContext, f as Middleware, i as RouterConfig, l as H3App, n as ControllerAction, r as HttpMethod, t as ApiResourceMiddleware, u as Handler } from "../basic-C_1O6RVq.cjs";
|
|
2
2
|
import { H3 } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region src/h3/router.d.ts
|
|
@@ -9,6 +9,8 @@ import { H3 } from "h3";
|
|
|
9
9
|
* @repository https://github.com/toneflix/clear-router
|
|
10
10
|
*/
|
|
11
11
|
declare class Router {
|
|
12
|
+
static config: RouterConfig;
|
|
13
|
+
private static readonly bodyCache;
|
|
12
14
|
private static readonly groupContext;
|
|
13
15
|
/**
|
|
14
16
|
* All registered routes
|
|
@@ -40,6 +42,9 @@ declare class Router {
|
|
|
40
42
|
* @returns Normalized path
|
|
41
43
|
*/
|
|
42
44
|
static normalizePath(path: string): string;
|
|
45
|
+
static configure(options?: RouterConfig): void;
|
|
46
|
+
private static readBodyCached;
|
|
47
|
+
private static resolveMethodOverride;
|
|
43
48
|
/**
|
|
44
49
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
45
50
|
* @param methods - HTTP method(s) for the route
|
package/dist/h3/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as
|
|
1
|
+
import { c as Route, d as HttpContext, f as Middleware, i as RouterConfig, l as H3App, n as ControllerAction, r as HttpMethod, t as ApiResourceMiddleware, u as Handler } from "../basic-cLeny2Zk.mjs";
|
|
2
2
|
import { H3 } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region src/h3/router.d.ts
|
|
@@ -9,6 +9,8 @@ import { H3 } from "h3";
|
|
|
9
9
|
* @repository https://github.com/toneflix/clear-router
|
|
10
10
|
*/
|
|
11
11
|
declare class Router {
|
|
12
|
+
static config: RouterConfig;
|
|
13
|
+
private static readonly bodyCache;
|
|
12
14
|
private static readonly groupContext;
|
|
13
15
|
/**
|
|
14
16
|
* All registered routes
|
|
@@ -40,6 +42,9 @@ declare class Router {
|
|
|
40
42
|
* @returns Normalized path
|
|
41
43
|
*/
|
|
42
44
|
static normalizePath(path: string): string;
|
|
45
|
+
static configure(options?: RouterConfig): void;
|
|
46
|
+
private static readBodyCached;
|
|
47
|
+
private static resolveMethodOverride;
|
|
43
48
|
/**
|
|
44
49
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
45
50
|
* @param methods - HTTP method(s) for the route
|
package/dist/h3/index.mjs
CHANGED
|
@@ -10,6 +10,12 @@ import { getQuery, getRouterParams, readBody } from "h3";
|
|
|
10
10
|
* @repository https://github.com/toneflix/clear-router
|
|
11
11
|
*/
|
|
12
12
|
var Router = class Router {
|
|
13
|
+
static config = { methodOverride: {
|
|
14
|
+
enabled: true,
|
|
15
|
+
bodyKeys: ["_method"],
|
|
16
|
+
headerKeys: ["x-http-method"]
|
|
17
|
+
} };
|
|
18
|
+
static bodyCache = /* @__PURE__ */ new WeakMap();
|
|
13
19
|
static groupContext = new AsyncLocalStorage();
|
|
14
20
|
/**
|
|
15
21
|
* All registered routes
|
|
@@ -43,6 +49,62 @@ var Router = class Router {
|
|
|
43
49
|
static normalizePath(path) {
|
|
44
50
|
return "/" + path.split("/").filter(Boolean).join("/");
|
|
45
51
|
}
|
|
52
|
+
static configure(options) {
|
|
53
|
+
if (!this.config.methodOverride) this.config.methodOverride = {
|
|
54
|
+
enabled: true,
|
|
55
|
+
bodyKeys: ["_method"],
|
|
56
|
+
headerKeys: ["x-http-method"]
|
|
57
|
+
};
|
|
58
|
+
const override = options?.methodOverride;
|
|
59
|
+
if (!override) return;
|
|
60
|
+
if (typeof override.enabled === "boolean") this.config.methodOverride.enabled = override.enabled;
|
|
61
|
+
const bodyKeys = override.bodyKeys;
|
|
62
|
+
if (typeof bodyKeys !== "undefined") this.config.methodOverride.bodyKeys = (Array.isArray(bodyKeys) ? bodyKeys : [bodyKeys]).map((e) => String(e).trim()).filter(Boolean);
|
|
63
|
+
const headerKeys = override.headerKeys;
|
|
64
|
+
if (typeof headerKeys !== "undefined") this.config.methodOverride.headerKeys = (Array.isArray(headerKeys) ? headerKeys : [headerKeys]).map((e) => String(e).trim().toLowerCase()).filter(Boolean);
|
|
65
|
+
}
|
|
66
|
+
static async readBodyCached(ctx) {
|
|
67
|
+
if (this.bodyCache.has(ctx)) {
|
|
68
|
+
const cached = this.bodyCache.get(ctx);
|
|
69
|
+
ctx.req.getBody = () => cached;
|
|
70
|
+
return cached;
|
|
71
|
+
}
|
|
72
|
+
let body = {};
|
|
73
|
+
if (ctx.req.headers.get("content-type")?.includes("multipart/form-data")) (await ctx.req.formData()).forEach((value, key) => {
|
|
74
|
+
body[key] = value;
|
|
75
|
+
});
|
|
76
|
+
else body = await readBody(ctx) ?? {};
|
|
77
|
+
ctx.req.getBody = () => body;
|
|
78
|
+
this.bodyCache.set(ctx, body);
|
|
79
|
+
return body;
|
|
80
|
+
}
|
|
81
|
+
static resolveMethodOverride(method, headers, body) {
|
|
82
|
+
if (!this.config.methodOverride?.enabled || method.toLowerCase() !== "post") return null;
|
|
83
|
+
let override;
|
|
84
|
+
for (const key of this.config.methodOverride?.headerKeys || []) {
|
|
85
|
+
const value = headers.get(key);
|
|
86
|
+
if (value) {
|
|
87
|
+
override = value;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!override && body && typeof body === "object") for (const key of this.config.methodOverride?.bodyKeys || []) {
|
|
92
|
+
const value = body[key];
|
|
93
|
+
if (typeof value !== "undefined" && value !== null && value !== "") {
|
|
94
|
+
override = value;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const normalized = String(override || "").trim().toLowerCase();
|
|
99
|
+
if (!normalized) return null;
|
|
100
|
+
if ([
|
|
101
|
+
"put",
|
|
102
|
+
"patch",
|
|
103
|
+
"delete",
|
|
104
|
+
"post"
|
|
105
|
+
].includes(normalized)) return normalized;
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
46
108
|
/**
|
|
47
109
|
* Add a route with specified HTTP methods, path, handler, and middlewares
|
|
48
110
|
* @param methods - HTTP method(s) for the route
|
|
@@ -265,8 +327,28 @@ var Router = class Router {
|
|
|
265
327
|
app[method](route.path, async (event) => {
|
|
266
328
|
try {
|
|
267
329
|
const ctx = event;
|
|
330
|
+
const reqBody = await Router.readBodyCached(ctx);
|
|
331
|
+
const override = Router.resolveMethodOverride(ctx.req.method, ctx.req.headers, reqBody);
|
|
332
|
+
if (method === "post" && override && override !== "post") return;
|
|
333
|
+
const inst = instance ?? route;
|
|
334
|
+
await Router.bindRequestToInstance(ctx, inst, route, reqBody);
|
|
335
|
+
const result = handlerFunction(ctx, inst.clearRequest);
|
|
336
|
+
return await Promise.resolve(result);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
return error;
|
|
339
|
+
}
|
|
340
|
+
}, { middleware: route.middlewares });
|
|
341
|
+
if ([
|
|
342
|
+
"put",
|
|
343
|
+
"patch",
|
|
344
|
+
"delete"
|
|
345
|
+
].includes(method)) app.post(route.path, async (event) => {
|
|
346
|
+
try {
|
|
347
|
+
const ctx = event;
|
|
348
|
+
const reqBody = await Router.readBodyCached(ctx);
|
|
349
|
+
if (Router.resolveMethodOverride(ctx.req.method, ctx.req.headers, reqBody) !== method) return;
|
|
268
350
|
const inst = instance ?? route;
|
|
269
|
-
await Router.bindRequestToInstance(ctx, inst, route);
|
|
351
|
+
await Router.bindRequestToInstance(ctx, inst, route, reqBody);
|
|
270
352
|
const result = handlerFunction(ctx, inst.clearRequest);
|
|
271
353
|
return await Promise.resolve(result);
|
|
272
354
|
} catch (error) {
|
|
@@ -277,10 +359,10 @@ var Router = class Router {
|
|
|
277
359
|
}
|
|
278
360
|
return app;
|
|
279
361
|
}
|
|
280
|
-
static async bindRequestToInstance(ctx, instance, route) {
|
|
362
|
+
static async bindRequestToInstance(ctx, instance, route, body) {
|
|
281
363
|
if (!instance) return;
|
|
282
364
|
instance.ctx = ctx;
|
|
283
|
-
instance.body = await
|
|
365
|
+
instance.body = body ?? await Router.readBodyCached(ctx);
|
|
284
366
|
instance.query = getQuery(ctx);
|
|
285
367
|
instance.params = getRouterParams(ctx, { decode: true });
|
|
286
368
|
instance.clearRequest = new ClearRequest({
|
package/dist/index.d.cts
CHANGED
|
@@ -2,10 +2,15 @@ import { NextFunction, Request, Response as Response$1 } from "express";
|
|
|
2
2
|
import { H3Event, Middleware as Middleware$1 } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region types/h3.d.ts
|
|
5
|
+
type HttpRequest = H3Event['req'] & {
|
|
6
|
+
getBody: () => Record<string, any>;
|
|
7
|
+
};
|
|
5
8
|
/**
|
|
6
9
|
* HTTP context passed to route handlers
|
|
7
10
|
*/
|
|
8
|
-
type HttpContext = H3Event & {
|
|
11
|
+
type HttpContext = Omit<H3Event, 'req'> & {
|
|
12
|
+
req: HttpRequest;
|
|
13
|
+
};
|
|
9
14
|
/**
|
|
10
15
|
* Route handler function type
|
|
11
16
|
*/
|
|
@@ -13,10 +18,12 @@ type RouteHandler = (
|
|
|
13
18
|
/**
|
|
14
19
|
* H3 event context
|
|
15
20
|
*/
|
|
21
|
+
|
|
16
22
|
ctx: HttpContext,
|
|
17
23
|
/**
|
|
18
24
|
* ClearRequest instance
|
|
19
25
|
*/
|
|
26
|
+
|
|
20
27
|
req: ClearRequest) => any | Promise<any>;
|
|
21
28
|
/**
|
|
22
29
|
* Handler can be either a function or controller reference
|
package/dist/index.d.mts
CHANGED
|
@@ -2,10 +2,15 @@ import { NextFunction, Request, Response as Response$1 } from "express";
|
|
|
2
2
|
import { H3Event, Middleware as Middleware$1 } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region types/h3.d.ts
|
|
5
|
+
type HttpRequest = H3Event['req'] & {
|
|
6
|
+
getBody: () => Record<string, any>;
|
|
7
|
+
};
|
|
5
8
|
/**
|
|
6
9
|
* HTTP context passed to route handlers
|
|
7
10
|
*/
|
|
8
|
-
type HttpContext = H3Event & {
|
|
11
|
+
type HttpContext = Omit<H3Event, 'req'> & {
|
|
12
|
+
req: HttpRequest;
|
|
13
|
+
};
|
|
9
14
|
/**
|
|
10
15
|
* Route handler function type
|
|
11
16
|
*/
|
|
@@ -13,10 +18,12 @@ type RouteHandler = (
|
|
|
13
18
|
/**
|
|
14
19
|
* H3 event context
|
|
15
20
|
*/
|
|
21
|
+
|
|
16
22
|
ctx: HttpContext,
|
|
17
23
|
/**
|
|
18
24
|
* ClearRequest instance
|
|
19
25
|
*/
|
|
26
|
+
|
|
20
27
|
req: ClearRequest) => any | Promise<any>;
|
|
21
28
|
/**
|
|
22
29
|
* Handler can be either a function or controller reference
|
package/dist/types/basic.d.mts
CHANGED
|
@@ -19,5 +19,16 @@ type ControllerAction = 'index' | 'show' | 'create' | 'update' | 'destroy';
|
|
|
19
19
|
*/
|
|
20
20
|
type RequestData = Record<string, any>;
|
|
21
21
|
type ApiResourceMiddleware<M extends Middleware$1 | Middleware> = M | M[] | { [K in ControllerAction]?: M | M[] };
|
|
22
|
+
interface RouterConfig {
|
|
23
|
+
/**
|
|
24
|
+
* Configuration for method override functionality, allowing clients to use a
|
|
25
|
+
* specific header or body parameter to override the HTTP method.
|
|
26
|
+
*/
|
|
27
|
+
methodOverride?: {
|
|
28
|
+
/** Whether method override is enabled */enabled?: boolean; /** Keys in the request body to check for method override */
|
|
29
|
+
bodyKeys?: string[] | string; /** Keys in the request headers to check for method override */
|
|
30
|
+
headerKeys?: string[] | string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
22
33
|
//#endregion
|
|
23
|
-
export { ApiResourceMiddleware, ControllerAction, ControllerHandler, HttpMethod, RequestData };
|
|
34
|
+
export { ApiResourceMiddleware, ControllerAction, ControllerHandler, HttpMethod, RequestData, RouterConfig };
|
package/dist/types/express.d.mts
CHANGED
|
@@ -3,11 +3,14 @@ import { ControllerHandler } from "./basic.mjs";
|
|
|
3
3
|
import { NextFunction, Request, Response } from "express";
|
|
4
4
|
|
|
5
5
|
//#region types/express.d.ts
|
|
6
|
+
interface RequestWithGetBody extends Request {
|
|
7
|
+
getBody: () => Record<string, any>;
|
|
8
|
+
}
|
|
6
9
|
/**
|
|
7
10
|
* HTTP context passed to route handlers
|
|
8
11
|
*/
|
|
9
12
|
interface HttpContext {
|
|
10
|
-
req:
|
|
13
|
+
req: RequestWithGetBody;
|
|
11
14
|
res: Response;
|
|
12
15
|
next: NextFunction;
|
|
13
16
|
}
|
|
@@ -34,4 +37,4 @@ type Handler = RouteHandler | ControllerHandler;
|
|
|
34
37
|
*/
|
|
35
38
|
type Middleware = (req: Request, res: Response, next: NextFunction) => any | Promise<any>;
|
|
36
39
|
//#endregion
|
|
37
|
-
export { Handler, HttpContext, Middleware, RouteHandler };
|
|
40
|
+
export { Handler, HttpContext, Middleware, RequestWithGetBody, RouteHandler };
|
package/dist/types/h3.d.mts
CHANGED
|
@@ -7,10 +7,15 @@ type H3App = Omit<H3['fetch'], 'fetch'> & {
|
|
|
7
7
|
fetch: (request: TypedServerRequest) => Promise<Response>;
|
|
8
8
|
};
|
|
9
9
|
type MaybePromise<T = unknown> = T | Promise<T>;
|
|
10
|
+
type HttpRequest = H3Event['req'] & {
|
|
11
|
+
getBody: () => Record<string, any>;
|
|
12
|
+
};
|
|
10
13
|
/**
|
|
11
14
|
* HTTP context passed to route handlers
|
|
12
15
|
*/
|
|
13
|
-
type HttpContext = H3Event & {
|
|
16
|
+
type HttpContext = Omit<H3Event, 'req'> & {
|
|
17
|
+
req: HttpRequest;
|
|
18
|
+
};
|
|
14
19
|
/**
|
|
15
20
|
* Route handler function type
|
|
16
21
|
*/
|
|
@@ -31,4 +36,4 @@ req: ClearRequest) => any | Promise<any>;
|
|
|
31
36
|
type Handler = RouteHandler | ControllerHandler;
|
|
32
37
|
type NextFunction = () => MaybePromise<unknown | undefined>;
|
|
33
38
|
//#endregion
|
|
34
|
-
export { H3App, Handler, HttpContext, MaybePromise, type Middleware, NextFunction, RouteHandler };
|
|
39
|
+
export { H3App, Handler, HttpContext, HttpRequest, MaybePromise, type Middleware, NextFunction, RouteHandler };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clear-router",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.12",
|
|
4
4
|
"description": "Laravel-style routing system for Express.js and H3, with CommonJS, ESM, and TypeScript support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"h3",
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"typescript": "^5.3.3",
|
|
81
81
|
"typescript-eslint": "^8.56.1",
|
|
82
82
|
"vite-tsconfig-paths": "^6.1.1",
|
|
83
|
+
"vitepress": "^1.6.4",
|
|
83
84
|
"vitest": "^4.0.18"
|
|
84
85
|
},
|
|
85
86
|
"engines": {
|
|
@@ -88,6 +89,9 @@
|
|
|
88
89
|
"scripts": {
|
|
89
90
|
"test": "vitest",
|
|
90
91
|
"lint": "eslint",
|
|
92
|
+
"docs:dev": "vitepress dev docs",
|
|
93
|
+
"docs:build": "vitepress build docs",
|
|
94
|
+
"docs:preview": "vitepress preview docs",
|
|
91
95
|
"test:esm": "vitest tests/esm.test.ts",
|
|
92
96
|
"test:ts": "vitest tests/typescript.test.ts",
|
|
93
97
|
"test:coverage": "vitest run --coverage",
|