astro-routify 1.2.2 → 1.5.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 +367 -28
- package/dist/core/RouteTrie.d.ts +4 -3
- package/dist/core/RouteTrie.js +132 -35
- package/dist/core/RouterBuilder.d.ts +96 -13
- package/dist/core/RouterBuilder.js +243 -21
- package/dist/core/decorators.d.ts +29 -0
- package/dist/core/decorators.js +49 -0
- package/dist/core/defineGroup.d.ts +33 -17
- package/dist/core/defineGroup.js +66 -23
- package/dist/core/defineHandler.d.ts +31 -13
- package/dist/core/defineHandler.js +1 -23
- package/dist/core/defineRoute.d.ts +32 -3
- package/dist/core/defineRoute.js +36 -9
- package/dist/core/defineRouter.d.ts +11 -1
- package/dist/core/defineRouter.js +79 -16
- package/dist/core/internal/createJsonStreamRoute.d.ts +1 -1
- package/dist/core/internal/createJsonStreamRoute.js +12 -4
- package/dist/core/middlewares.d.ts +47 -0
- package/dist/core/middlewares.js +110 -0
- package/dist/core/openapi.d.ts +17 -0
- package/dist/core/openapi.js +84 -0
- package/dist/core/registry.d.ts +15 -0
- package/dist/core/registry.js +26 -0
- package/dist/core/responseHelpers.d.ts +22 -5
- package/dist/core/responseHelpers.js +121 -20
- package/dist/core/stream.d.ts +3 -3
- package/dist/core/stream.js +16 -9
- package/dist/core/streamJsonArray.d.ts +1 -1
- package/dist/core/streamJsonArray.js +1 -1
- package/dist/index.d.ts +338 -57
- package/dist/index.js +5 -1
- package/package.json +5 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @Get decorator - auto-registers a GET route.
|
|
3
|
+
*/
|
|
4
|
+
export declare const Get: (path: string) => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
|
|
5
|
+
/**
|
|
6
|
+
* @Post decorator - auto-registers a POST route.
|
|
7
|
+
*/
|
|
8
|
+
export declare const Post: (path: string) => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
|
|
9
|
+
/**
|
|
10
|
+
* @Put decorator - auto-registers a PUT route.
|
|
11
|
+
*/
|
|
12
|
+
export declare const Put: (path: string) => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
|
|
13
|
+
/**
|
|
14
|
+
* @Delete decorator - auto-registers a DELETE route.
|
|
15
|
+
*/
|
|
16
|
+
export declare const Delete: (path: string) => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
|
|
17
|
+
/**
|
|
18
|
+
* @Patch decorator - auto-registers a PATCH route.
|
|
19
|
+
*/
|
|
20
|
+
export declare const Patch: (path: string) => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
|
|
21
|
+
/**
|
|
22
|
+
* @RouteGroup decorator - can be used on classes to auto-register a group.
|
|
23
|
+
* Note: This requires the class to have a static method or property that returns the routes,
|
|
24
|
+
* or it can be used in conjunction with method decorators.
|
|
25
|
+
*
|
|
26
|
+
* For now, we'll implement a simple version that can be used on a class
|
|
27
|
+
* if the class is intended to be a group.
|
|
28
|
+
*/
|
|
29
|
+
export declare function Group(basePath: string): (constructor: Function) => void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { HttpMethod } from './HttpMethod';
|
|
2
|
+
import { defineRoute } from './defineRoute';
|
|
3
|
+
/**
|
|
4
|
+
* Decorator factory for HTTP methods.
|
|
5
|
+
*/
|
|
6
|
+
function createMethodDecorator(method) {
|
|
7
|
+
return function (path) {
|
|
8
|
+
return function (target, propertyKey, descriptor) {
|
|
9
|
+
const handler = descriptor ? descriptor.value : target[propertyKey];
|
|
10
|
+
if (typeof handler === 'function') {
|
|
11
|
+
defineRoute(method, path, handler, true);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @Get decorator - auto-registers a GET route.
|
|
18
|
+
*/
|
|
19
|
+
export const Get = createMethodDecorator(HttpMethod.GET);
|
|
20
|
+
/**
|
|
21
|
+
* @Post decorator - auto-registers a POST route.
|
|
22
|
+
*/
|
|
23
|
+
export const Post = createMethodDecorator(HttpMethod.POST);
|
|
24
|
+
/**
|
|
25
|
+
* @Put decorator - auto-registers a PUT route.
|
|
26
|
+
*/
|
|
27
|
+
export const Put = createMethodDecorator(HttpMethod.PUT);
|
|
28
|
+
/**
|
|
29
|
+
* @Delete decorator - auto-registers a DELETE route.
|
|
30
|
+
*/
|
|
31
|
+
export const Delete = createMethodDecorator(HttpMethod.DELETE);
|
|
32
|
+
/**
|
|
33
|
+
* @Patch decorator - auto-registers a PATCH route.
|
|
34
|
+
*/
|
|
35
|
+
export const Patch = createMethodDecorator(HttpMethod.PATCH);
|
|
36
|
+
/**
|
|
37
|
+
* @RouteGroup decorator - can be used on classes to auto-register a group.
|
|
38
|
+
* Note: This requires the class to have a static method or property that returns the routes,
|
|
39
|
+
* or it can be used in conjunction with method decorators.
|
|
40
|
+
*
|
|
41
|
+
* For now, we'll implement a simple version that can be used on a class
|
|
42
|
+
* if the class is intended to be a group.
|
|
43
|
+
*/
|
|
44
|
+
export function Group(basePath) {
|
|
45
|
+
return function (constructor) {
|
|
46
|
+
// In a more advanced implementation, we could collect all methods
|
|
47
|
+
// and register them as a group. For now, we'll keep it simple.
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { HttpMethod } from './HttpMethod';
|
|
1
2
|
import { type Route } from './defineRoute';
|
|
2
|
-
import {
|
|
3
|
+
import { Middleware } from "./defineHandler";
|
|
3
4
|
/**
|
|
4
5
|
* Represents a group of routes under a shared base path.
|
|
5
6
|
*
|
|
@@ -12,8 +13,10 @@ import { Handler } from "./defineHandler";
|
|
|
12
13
|
* .addPost('/', createUser);
|
|
13
14
|
*/
|
|
14
15
|
export declare class RouteGroup {
|
|
16
|
+
readonly _routifyType = "group";
|
|
15
17
|
private basePath;
|
|
16
18
|
private routes;
|
|
19
|
+
private middlewares;
|
|
17
20
|
/**
|
|
18
21
|
* Creates a new route group with the specified base path.
|
|
19
22
|
* Trailing slashes are automatically removed.
|
|
@@ -25,49 +28,61 @@ export declare class RouteGroup {
|
|
|
25
28
|
* Returns the normalized base path used by the group.
|
|
26
29
|
*/
|
|
27
30
|
getBasePath(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Adds a middleware to all routes in this group.
|
|
33
|
+
*
|
|
34
|
+
* @param middleware - The middleware function to add
|
|
35
|
+
* @returns The current group instance
|
|
36
|
+
*/
|
|
37
|
+
use(middleware: Middleware): this;
|
|
28
38
|
/**
|
|
29
39
|
* Registers a GET route under the group's base path.
|
|
30
40
|
*
|
|
31
41
|
* @param path - Path relative to the base path (e.g. "/:id")
|
|
32
|
-
* @param
|
|
42
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
33
43
|
*/
|
|
34
|
-
addGet(path: string,
|
|
44
|
+
addGet(path: string, ...handlers: any[]): this;
|
|
35
45
|
/**
|
|
36
46
|
* Registers a POST route under the group's base path.
|
|
37
47
|
*
|
|
38
48
|
* @param path - Path relative to the base path
|
|
39
|
-
* @param
|
|
49
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
40
50
|
*/
|
|
41
|
-
addPost(path: string,
|
|
51
|
+
addPost(path: string, ...handlers: any[]): this;
|
|
42
52
|
/**
|
|
43
53
|
* Registers a PUT route under the group's base path.
|
|
44
54
|
*
|
|
45
55
|
* @param path - Path relative to the base path
|
|
46
|
-
* @param
|
|
56
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
47
57
|
*/
|
|
48
|
-
addPut(path: string,
|
|
58
|
+
addPut(path: string, ...handlers: any[]): this;
|
|
49
59
|
/**
|
|
50
60
|
* Registers a DELETE route under the group's base path.
|
|
51
61
|
*
|
|
52
62
|
* @param path - Path relative to the base path
|
|
53
|
-
* @param
|
|
63
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
54
64
|
*/
|
|
55
|
-
addDelete(path: string,
|
|
65
|
+
addDelete(path: string, ...handlers: any[]): this;
|
|
56
66
|
/**
|
|
57
67
|
* Registers a PATCH route under the group's base path.
|
|
58
68
|
*
|
|
59
69
|
* @param path - Path relative to the base path
|
|
60
|
-
* @param
|
|
70
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
61
71
|
*/
|
|
62
|
-
addPatch(path: string,
|
|
72
|
+
addPatch(path: string, ...handlers: any[]): this;
|
|
63
73
|
/**
|
|
64
|
-
*
|
|
74
|
+
* Registers a route under the group's base path.
|
|
65
75
|
*
|
|
66
76
|
* @param method - HTTP verb
|
|
67
|
-
* @param
|
|
68
|
-
* @param
|
|
77
|
+
* @param path - Path relative to the base path
|
|
78
|
+
* @param args - Middleware(s) and handler
|
|
79
|
+
* @returns The current group instance
|
|
80
|
+
*/
|
|
81
|
+
add(method: HttpMethod, path: string, ...args: any[]): this;
|
|
82
|
+
/**
|
|
83
|
+
* Registers the group and all its current routes to the global registry.
|
|
69
84
|
*/
|
|
70
|
-
|
|
85
|
+
register(): this;
|
|
71
86
|
/**
|
|
72
87
|
* Returns all the registered routes in the group.
|
|
73
88
|
*/
|
|
@@ -78,10 +93,11 @@ export declare class RouteGroup {
|
|
|
78
93
|
*
|
|
79
94
|
* @param basePath - The base path prefix for all routes
|
|
80
95
|
* @param configure - Optional callback to configure the group inline
|
|
96
|
+
* @param autoRegister - If true, registers the group to the global registry
|
|
81
97
|
*
|
|
82
98
|
* @example
|
|
83
99
|
* const users = defineGroup('/users', (group) => {
|
|
84
100
|
* group.addGet('/:id', handler);
|
|
85
|
-
* });
|
|
101
|
+
* }, true);
|
|
86
102
|
*/
|
|
87
|
-
export declare function defineGroup(basePath: string, configure?: (group: RouteGroup) => void): RouteGroup;
|
|
103
|
+
export declare function defineGroup(basePath: string, configure?: (group: RouteGroup) => void, autoRegister?: boolean): RouteGroup;
|
package/dist/core/defineGroup.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HttpMethod } from './HttpMethod';
|
|
2
2
|
import { defineRoute } from './defineRoute';
|
|
3
|
+
import { globalRegistry } from './registry';
|
|
3
4
|
/**
|
|
4
5
|
* Represents a group of routes under a shared base path.
|
|
5
6
|
*
|
|
@@ -19,7 +20,9 @@ export class RouteGroup {
|
|
|
19
20
|
* @param basePath - The common prefix for all routes in the group (e.g. "/users")
|
|
20
21
|
*/
|
|
21
22
|
constructor(basePath) {
|
|
23
|
+
this._routifyType = 'group';
|
|
22
24
|
this.routes = [];
|
|
25
|
+
this.middlewares = [];
|
|
23
26
|
this.basePath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
@@ -28,61 +31,97 @@ export class RouteGroup {
|
|
|
28
31
|
getBasePath() {
|
|
29
32
|
return this.basePath;
|
|
30
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Adds a middleware to all routes in this group.
|
|
36
|
+
*
|
|
37
|
+
* @param middleware - The middleware function to add
|
|
38
|
+
* @returns The current group instance
|
|
39
|
+
*/
|
|
40
|
+
use(middleware) {
|
|
41
|
+
this.middlewares.push(middleware);
|
|
42
|
+
// Apply to already registered routes in this group
|
|
43
|
+
for (const route of this.routes) {
|
|
44
|
+
if (!route.middlewares)
|
|
45
|
+
route.middlewares = [];
|
|
46
|
+
route.middlewares.push(middleware);
|
|
47
|
+
}
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
31
50
|
/**
|
|
32
51
|
* Registers a GET route under the group's base path.
|
|
33
52
|
*
|
|
34
53
|
* @param path - Path relative to the base path (e.g. "/:id")
|
|
35
|
-
* @param
|
|
54
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
36
55
|
*/
|
|
37
|
-
addGet(path,
|
|
38
|
-
return this.add(HttpMethod.GET, path,
|
|
56
|
+
addGet(path, ...handlers) {
|
|
57
|
+
return this.add(HttpMethod.GET, path, ...handlers);
|
|
39
58
|
}
|
|
40
59
|
/**
|
|
41
60
|
* Registers a POST route under the group's base path.
|
|
42
61
|
*
|
|
43
62
|
* @param path - Path relative to the base path
|
|
44
|
-
* @param
|
|
63
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
45
64
|
*/
|
|
46
|
-
addPost(path,
|
|
47
|
-
return this.add(HttpMethod.POST, path,
|
|
65
|
+
addPost(path, ...handlers) {
|
|
66
|
+
return this.add(HttpMethod.POST, path, ...handlers);
|
|
48
67
|
}
|
|
49
68
|
/**
|
|
50
69
|
* Registers a PUT route under the group's base path.
|
|
51
70
|
*
|
|
52
71
|
* @param path - Path relative to the base path
|
|
53
|
-
* @param
|
|
72
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
54
73
|
*/
|
|
55
|
-
addPut(path,
|
|
56
|
-
return this.add(HttpMethod.PUT, path,
|
|
74
|
+
addPut(path, ...handlers) {
|
|
75
|
+
return this.add(HttpMethod.PUT, path, ...handlers);
|
|
57
76
|
}
|
|
58
77
|
/**
|
|
59
78
|
* Registers a DELETE route under the group's base path.
|
|
60
79
|
*
|
|
61
80
|
* @param path - Path relative to the base path
|
|
62
|
-
* @param
|
|
81
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
63
82
|
*/
|
|
64
|
-
addDelete(path,
|
|
65
|
-
return this.add(HttpMethod.DELETE, path,
|
|
83
|
+
addDelete(path, ...handlers) {
|
|
84
|
+
return this.add(HttpMethod.DELETE, path, ...handlers);
|
|
66
85
|
}
|
|
67
86
|
/**
|
|
68
87
|
* Registers a PATCH route under the group's base path.
|
|
69
88
|
*
|
|
70
89
|
* @param path - Path relative to the base path
|
|
71
|
-
* @param
|
|
90
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
72
91
|
*/
|
|
73
|
-
addPatch(path,
|
|
74
|
-
return this.add(HttpMethod.PATCH, path,
|
|
92
|
+
addPatch(path, ...handlers) {
|
|
93
|
+
return this.add(HttpMethod.PATCH, path, ...handlers);
|
|
75
94
|
}
|
|
76
95
|
/**
|
|
77
|
-
*
|
|
96
|
+
* Registers a route under the group's base path.
|
|
78
97
|
*
|
|
79
98
|
* @param method - HTTP verb
|
|
80
|
-
* @param
|
|
81
|
-
* @param
|
|
99
|
+
* @param path - Path relative to the base path
|
|
100
|
+
* @param args - Middleware(s) and handler
|
|
101
|
+
* @returns The current group instance
|
|
82
102
|
*/
|
|
83
|
-
add(method,
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
add(method, path, ...args) {
|
|
104
|
+
let metadata;
|
|
105
|
+
if (args.length > 1 && typeof args[args.length - 1] === 'object' && typeof args[args.length - 2] === 'function') {
|
|
106
|
+
metadata = args.pop();
|
|
107
|
+
}
|
|
108
|
+
const handler = args.pop();
|
|
109
|
+
const middlewares = args;
|
|
110
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
111
|
+
this.routes.push(defineRoute({
|
|
112
|
+
method,
|
|
113
|
+
path: `${this.basePath}${normalizedPath}`,
|
|
114
|
+
handler,
|
|
115
|
+
middlewares: [...this.middlewares, ...middlewares],
|
|
116
|
+
metadata
|
|
117
|
+
}));
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Registers the group and all its current routes to the global registry.
|
|
122
|
+
*/
|
|
123
|
+
register() {
|
|
124
|
+
globalRegistry.register(this);
|
|
86
125
|
return this;
|
|
87
126
|
}
|
|
88
127
|
/**
|
|
@@ -97,15 +136,19 @@ export class RouteGroup {
|
|
|
97
136
|
*
|
|
98
137
|
* @param basePath - The base path prefix for all routes
|
|
99
138
|
* @param configure - Optional callback to configure the group inline
|
|
139
|
+
* @param autoRegister - If true, registers the group to the global registry
|
|
100
140
|
*
|
|
101
141
|
* @example
|
|
102
142
|
* const users = defineGroup('/users', (group) => {
|
|
103
143
|
* group.addGet('/:id', handler);
|
|
104
|
-
* });
|
|
144
|
+
* }, true);
|
|
105
145
|
*/
|
|
106
|
-
export function defineGroup(basePath, configure) {
|
|
146
|
+
export function defineGroup(basePath, configure, autoRegister) {
|
|
107
147
|
const group = new RouteGroup(basePath);
|
|
108
148
|
if (configure)
|
|
109
149
|
configure(group);
|
|
150
|
+
if (autoRegister) {
|
|
151
|
+
globalRegistry.register(group);
|
|
152
|
+
}
|
|
110
153
|
return group;
|
|
111
154
|
}
|
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
import type { APIContext, APIRoute } from 'astro';
|
|
2
|
-
import { type
|
|
2
|
+
import { type HandlerResult } from './responseHelpers';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* - a native `Response` object,
|
|
6
|
-
* - a structured `ResultResponse` object,
|
|
7
|
-
* - or a file stream (Blob, ArrayBuffer, or ReadableStream).
|
|
4
|
+
* Enhanced Astro context for Routify.
|
|
8
5
|
*/
|
|
9
|
-
export
|
|
6
|
+
export interface RoutifyContext<State = Record<string, any>> extends APIContext {
|
|
7
|
+
/**
|
|
8
|
+
* Parsed query parameters from the URL.
|
|
9
|
+
* Note: If multiple parameters have the same key, only the last one is included.
|
|
10
|
+
* Use `searchParams` for full multi-value support.
|
|
11
|
+
*/
|
|
12
|
+
query: Record<string, string | string[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Full URLSearchParams object for the incoming request.
|
|
15
|
+
*/
|
|
16
|
+
searchParams: URLSearchParams;
|
|
17
|
+
/**
|
|
18
|
+
* Shared state container for middlewares and handlers (e.g., validation results).
|
|
19
|
+
* This is where middlewares can store information for subsequent handlers.
|
|
20
|
+
*/
|
|
21
|
+
state: State;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convenience type alias for RoutifyContext.
|
|
25
|
+
*/
|
|
26
|
+
export type Context<State = Record<string, any>> = RoutifyContext<State>;
|
|
27
|
+
/**
|
|
28
|
+
* A middleware function that can modify the context or short-circuit the response.
|
|
29
|
+
*/
|
|
30
|
+
export type Middleware<State = any> = (ctx: RoutifyContext<State>, next: () => Promise<Response>) => Promise<Response> | Response;
|
|
31
|
+
/**
|
|
32
|
+
* A flexible route handler that can return various types.
|
|
33
|
+
*/
|
|
34
|
+
export type Handler<State = any> = (ctx: RoutifyContext<State>) => Promise<HandlerResult> | HandlerResult;
|
|
10
35
|
/**
|
|
11
36
|
* Wraps a `Handler` function into an `APIRoute` that:
|
|
12
37
|
* - logs requests and responses,
|
|
@@ -18,10 +43,3 @@ export type Handler = (ctx: APIContext) => Promise<ResultResponse | Response> |
|
|
|
18
43
|
* @returns An Astro-compatible `APIRoute` function
|
|
19
44
|
*/
|
|
20
45
|
export declare function defineHandler(handler: Handler): APIRoute;
|
|
21
|
-
/**
|
|
22
|
-
* Type guard to detect ReadableStreams, used for streamed/binary responses.
|
|
23
|
-
*
|
|
24
|
-
* @param value - Any value to test
|
|
25
|
-
* @returns True if it looks like a ReadableStream
|
|
26
|
-
*/
|
|
27
|
-
export declare function isReadableStream(value: unknown): value is ReadableStream<Uint8Array>;
|
|
@@ -33,18 +33,7 @@ export function defineHandler(handler) {
|
|
|
33
33
|
logResponse(result.status, start);
|
|
34
34
|
return result;
|
|
35
35
|
}
|
|
36
|
-
//
|
|
37
|
-
if (result?.body instanceof Blob ||
|
|
38
|
-
result?.body instanceof ArrayBuffer ||
|
|
39
|
-
isReadableStream(result?.body)) {
|
|
40
|
-
const res = new Response(result.body, {
|
|
41
|
-
status: result.status,
|
|
42
|
-
headers: result.headers,
|
|
43
|
-
});
|
|
44
|
-
logResponse(res.status, start);
|
|
45
|
-
return res;
|
|
46
|
-
}
|
|
47
|
-
// Structured ResultResponse → native Astro Response
|
|
36
|
+
// Structured ResultResponse or other HandlerResult → native Astro Response
|
|
48
37
|
const finalResponse = toAstroResponse(result);
|
|
49
38
|
logResponse(finalResponse.status, start);
|
|
50
39
|
return finalResponse;
|
|
@@ -57,14 +46,3 @@ export function defineHandler(handler) {
|
|
|
57
46
|
}
|
|
58
47
|
};
|
|
59
48
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Type guard to detect ReadableStreams, used for streamed/binary responses.
|
|
62
|
-
*
|
|
63
|
-
* @param value - Any value to test
|
|
64
|
-
* @returns True if it looks like a ReadableStream
|
|
65
|
-
*/
|
|
66
|
-
export function isReadableStream(value) {
|
|
67
|
-
return (typeof value === 'object' &&
|
|
68
|
-
value !== null &&
|
|
69
|
-
typeof value.getReader === 'function');
|
|
70
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HttpMethod } from './HttpMethod';
|
|
2
|
-
import type { Handler } from './defineHandler';
|
|
2
|
+
import type { Handler, Middleware } from './defineHandler';
|
|
3
3
|
/**
|
|
4
4
|
* Represents a single route definition.
|
|
5
5
|
*/
|
|
@@ -16,6 +16,19 @@ export interface Route {
|
|
|
16
16
|
* The function that handles the request when matched.
|
|
17
17
|
*/
|
|
18
18
|
handler: Handler;
|
|
19
|
+
/**
|
|
20
|
+
* Optional array of middlewares to run before the handler.
|
|
21
|
+
*/
|
|
22
|
+
middlewares?: Middleware[];
|
|
23
|
+
/**
|
|
24
|
+
* Optional metadata for the route (e.g. for OpenAPI generation).
|
|
25
|
+
*/
|
|
26
|
+
metadata?: Record<string, any>;
|
|
27
|
+
/**
|
|
28
|
+
* Internal marker to identify the object type during module discovery.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
_routifyType?: 'route';
|
|
19
32
|
}
|
|
20
33
|
/**
|
|
21
34
|
* Defines a route using a `Route` object.
|
|
@@ -24,9 +37,10 @@ export interface Route {
|
|
|
24
37
|
* defineRoute({ method: 'GET', path: '/users', handler });
|
|
25
38
|
*
|
|
26
39
|
* @param route - A fully constructed route object
|
|
40
|
+
* @param autoRegister - If true, registers the route to the global registry
|
|
27
41
|
* @returns The validated Route object
|
|
28
42
|
*/
|
|
29
|
-
export declare function defineRoute(route: Route): Route;
|
|
43
|
+
export declare function defineRoute(route: Route, autoRegister?: boolean): Route;
|
|
30
44
|
/**
|
|
31
45
|
* Defines a route by specifying its method, path, and handler explicitly.
|
|
32
46
|
*
|
|
@@ -36,6 +50,21 @@ export declare function defineRoute(route: Route): Route;
|
|
|
36
50
|
* @param method - HTTP method to match
|
|
37
51
|
* @param path - Route path (must start with `/`)
|
|
38
52
|
* @param handler - Function to handle the matched request
|
|
53
|
+
* @param autoRegister - If true, registers the route to the global registry
|
|
39
54
|
* @returns The validated Route object
|
|
40
55
|
*/
|
|
41
|
-
export declare function defineRoute(method: HttpMethod, path: string, handler: Handler): Route;
|
|
56
|
+
export declare function defineRoute(method: HttpMethod, path: string, handler: Handler, autoRegister?: boolean): Route;
|
|
57
|
+
/**
|
|
58
|
+
* Ensures the route is properly formed and uses a valid method + path format.
|
|
59
|
+
*
|
|
60
|
+
* @param route - Route to validate
|
|
61
|
+
* @throws If method is unsupported or path doesn't start with `/`
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateRoute({ method, path }: Route): void;
|
|
64
|
+
/**
|
|
65
|
+
* Checks if an object implements the `Route` interface.
|
|
66
|
+
*
|
|
67
|
+
* @param obj - The object to check
|
|
68
|
+
* @returns True if the object is a valid Route
|
|
69
|
+
*/
|
|
70
|
+
export declare function isRoute(obj: any): obj is Route;
|
package/dist/core/defineRoute.js
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import { ALLOWED_HTTP_METHODS } from './HttpMethod';
|
|
2
|
+
import { globalRegistry } from './registry';
|
|
2
3
|
/**
|
|
3
4
|
* Internal route definition logic that supports both overloads.
|
|
4
5
|
*/
|
|
5
|
-
export function defineRoute(methodOrRoute,
|
|
6
|
+
export function defineRoute(methodOrRoute, maybePathOrAutoRegister, maybeHandler, maybeAutoRegister) {
|
|
7
|
+
let autoRegister = false;
|
|
8
|
+
let route;
|
|
6
9
|
if (typeof methodOrRoute === 'object') {
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
route = methodOrRoute;
|
|
11
|
+
autoRegister = !!maybePathOrAutoRegister;
|
|
9
12
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
else {
|
|
14
|
+
route = {
|
|
15
|
+
method: methodOrRoute,
|
|
16
|
+
path: maybePathOrAutoRegister,
|
|
17
|
+
handler: maybeHandler,
|
|
18
|
+
};
|
|
19
|
+
autoRegister = !!maybeAutoRegister;
|
|
20
|
+
}
|
|
21
|
+
route._routifyType = 'route';
|
|
15
22
|
validateRoute(route);
|
|
23
|
+
if (autoRegister) {
|
|
24
|
+
globalRegistry.register(route);
|
|
25
|
+
}
|
|
16
26
|
return route;
|
|
17
27
|
}
|
|
18
28
|
/**
|
|
@@ -21,11 +31,28 @@ export function defineRoute(methodOrRoute, maybePath, maybeHandler) {
|
|
|
21
31
|
* @param route - Route to validate
|
|
22
32
|
* @throws If method is unsupported or path doesn't start with `/`
|
|
23
33
|
*/
|
|
24
|
-
function validateRoute({ method, path }) {
|
|
34
|
+
export function validateRoute({ method, path }) {
|
|
25
35
|
if (!path.startsWith('/')) {
|
|
26
36
|
throw new Error(`Route path must start with '/': ${path}`);
|
|
27
37
|
}
|
|
28
38
|
if (!ALLOWED_HTTP_METHODS.has(method)) {
|
|
29
39
|
throw new Error(`Unsupported HTTP method in route: ${method}`);
|
|
30
40
|
}
|
|
41
|
+
if (path.includes('**') && !path.endsWith('**')) {
|
|
42
|
+
throw new Error(`Catch-all '**' is only allowed at the end of a path: ${path}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Checks if an object implements the `Route` interface.
|
|
47
|
+
*
|
|
48
|
+
* @param obj - The object to check
|
|
49
|
+
* @returns True if the object is a valid Route
|
|
50
|
+
*/
|
|
51
|
+
export function isRoute(obj) {
|
|
52
|
+
return (obj &&
|
|
53
|
+
typeof obj === 'object' &&
|
|
54
|
+
(obj._routifyType === 'route' ||
|
|
55
|
+
(typeof obj.method === 'string' &&
|
|
56
|
+
typeof obj.path === 'string' &&
|
|
57
|
+
typeof obj.handler === 'function')));
|
|
31
58
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { APIRoute } from 'astro';
|
|
2
|
-
import {
|
|
2
|
+
import { type RoutifyContext } from './defineHandler';
|
|
3
|
+
import { notFound, type HandlerResult } from './responseHelpers';
|
|
3
4
|
import type { Route } from './defineRoute';
|
|
4
5
|
/**
|
|
5
6
|
* Optional configuration for the router instance.
|
|
@@ -14,6 +15,15 @@ export interface RouterOptions {
|
|
|
14
15
|
* Custom handler to return when no route is matched (404).
|
|
15
16
|
*/
|
|
16
17
|
onNotFound?: () => ReturnType<typeof notFound>;
|
|
18
|
+
/**
|
|
19
|
+
* If true, enables debug logging for route matching.
|
|
20
|
+
* Useful during development to trace which route is being matched.
|
|
21
|
+
*/
|
|
22
|
+
debug?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Custom error handler for the router.
|
|
25
|
+
*/
|
|
26
|
+
onError?: (error: unknown, ctx: RoutifyContext) => HandlerResult | Response;
|
|
17
27
|
}
|
|
18
28
|
/**
|
|
19
29
|
* Defines a router that dynamically matches registered routes based on method and path.
|