astro-routify 1.2.2 → 1.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 +221 -4
- package/dist/core/RouteTrie.d.ts +4 -3
- package/dist/core/RouteTrie.js +101 -32
- package/dist/core/RouterBuilder.d.ts +96 -13
- package/dist/core/RouterBuilder.js +210 -21
- package/dist/core/decorators.d.ts +29 -0
- package/dist/core/decorators.js +49 -0
- package/dist/core/defineGroup.d.ts +32 -17
- package/dist/core/defineGroup.js +65 -23
- package/dist/core/defineHandler.d.ts +18 -8
- package/dist/core/defineHandler.js +1 -12
- package/dist/core/defineRoute.d.ts +27 -3
- package/dist/core/defineRoute.js +31 -9
- package/dist/core/defineRouter.d.ts +11 -1
- package/dist/core/defineRouter.js +63 -16
- 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 +57 -0
- package/dist/core/registry.d.ts +15 -0
- package/dist/core/registry.js +26 -0
- package/dist/core/responseHelpers.d.ts +13 -0
- package/dist/core/responseHelpers.js +32 -6
- package/dist/core/stream.js +14 -7
- package/dist/index.d.ts +306 -43
- package/dist/index.js +5 -1
- package/package.json +5 -3
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { defineRoute } from './defineRoute';
|
|
1
|
+
import { defineRoute, isRoute } from './defineRoute';
|
|
2
2
|
import { defineRouter } from './defineRouter';
|
|
3
|
+
import { defineGroup, RouteGroup } from './defineGroup';
|
|
3
4
|
import { HttpMethod } from './HttpMethod';
|
|
5
|
+
import { globalRegistry } from './registry';
|
|
4
6
|
/**
|
|
5
7
|
* A fluent builder for creating and composing API routes in Astro.
|
|
6
8
|
*
|
|
@@ -26,14 +28,134 @@ import { HttpMethod } from './HttpMethod';
|
|
|
26
28
|
*
|
|
27
29
|
* export const GET = router.build();
|
|
28
30
|
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example Auto-discovering routes via Vite glob:
|
|
33
|
+
* ```ts
|
|
34
|
+
* const router = new RouterBuilder()
|
|
35
|
+
* .addModules(import.meta.glob('./**\/*.routes.ts', { eager: true }));
|
|
36
|
+
*
|
|
37
|
+
* export const ALL = router.build();
|
|
38
|
+
* ```
|
|
29
39
|
*/
|
|
30
40
|
export class RouterBuilder {
|
|
31
41
|
constructor(options) {
|
|
32
42
|
this._routes = [];
|
|
43
|
+
this._groups = [];
|
|
44
|
+
this._middlewares = [];
|
|
45
|
+
this._shouldLog = false;
|
|
33
46
|
this._options = {
|
|
34
47
|
basePath: 'api',
|
|
35
48
|
...options,
|
|
36
49
|
};
|
|
50
|
+
if ((typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') ||
|
|
51
|
+
import.meta.env?.DEV) {
|
|
52
|
+
this._shouldLog = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Adds a global middleware to all routes registered in this builder.
|
|
57
|
+
*
|
|
58
|
+
* @param middleware - The middleware function.
|
|
59
|
+
* @returns The current builder instance.
|
|
60
|
+
*/
|
|
61
|
+
use(middleware) {
|
|
62
|
+
this._middlewares.push(middleware);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Creates and adds a new route group to the builder.
|
|
67
|
+
*
|
|
68
|
+
* @param basePath - The base path for the group.
|
|
69
|
+
* @param configure - Optional callback to configure the group.
|
|
70
|
+
* @returns The created RouteGroup instance.
|
|
71
|
+
*/
|
|
72
|
+
group(basePath, configure) {
|
|
73
|
+
const group = defineGroup(basePath, configure);
|
|
74
|
+
this.addGroup(group);
|
|
75
|
+
return group;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Adds all routes and groups that have been auto-registered via `defineRoute(..., true)`
|
|
79
|
+
* or `defineGroup(..., true)`.
|
|
80
|
+
*
|
|
81
|
+
* @returns The current builder instance.
|
|
82
|
+
*/
|
|
83
|
+
addRegistered() {
|
|
84
|
+
globalRegistry.getItems().forEach((item) => {
|
|
85
|
+
if (item instanceof RouteGroup) {
|
|
86
|
+
this.addGroup(item);
|
|
87
|
+
}
|
|
88
|
+
else if (isRoute(item)) {
|
|
89
|
+
this.addRoute(item);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Bulk registers routes and groups from a module collection.
|
|
96
|
+
* Ideal for use with Vite's `import.meta.glob` (with `{ eager: true }`).
|
|
97
|
+
*
|
|
98
|
+
* It will search for both default and named exports that are either `Route` or `RouteGroup`.
|
|
99
|
+
*
|
|
100
|
+
* @param modules A record of modules (e.g. from `import.meta.glob`).
|
|
101
|
+
* @returns The current builder instance.
|
|
102
|
+
*/
|
|
103
|
+
addModules(modules) {
|
|
104
|
+
Object.values(modules).forEach((m) => {
|
|
105
|
+
if (m instanceof RouteGroup) {
|
|
106
|
+
this.addGroup(m);
|
|
107
|
+
}
|
|
108
|
+
else if (isRoute(m)) {
|
|
109
|
+
this.addRoute(m);
|
|
110
|
+
}
|
|
111
|
+
else if (typeof m === 'object' && m !== null) {
|
|
112
|
+
Object.values(m).forEach((val) => {
|
|
113
|
+
if (val instanceof RouteGroup) {
|
|
114
|
+
this.addGroup(val);
|
|
115
|
+
}
|
|
116
|
+
else if (isRoute(val)) {
|
|
117
|
+
this.addRoute(val);
|
|
118
|
+
}
|
|
119
|
+
else if (Array.isArray(val)) {
|
|
120
|
+
val.forEach((item) => {
|
|
121
|
+
if (isRoute(item)) {
|
|
122
|
+
this.addRoute(item);
|
|
123
|
+
}
|
|
124
|
+
else if (item instanceof RouteGroup) {
|
|
125
|
+
this.addGroup(item);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Prints all registered routes to the console.
|
|
136
|
+
* Useful for debugging during development.
|
|
137
|
+
*
|
|
138
|
+
* @returns The current builder instance.
|
|
139
|
+
*/
|
|
140
|
+
logRoutes() {
|
|
141
|
+
console.log(`\x1b[36m[RouterBuilder]\x1b[0m Registered routes:`);
|
|
142
|
+
const limit = 30;
|
|
143
|
+
this._routes.slice(0, limit).forEach((r) => {
|
|
144
|
+
console.log(` \x1b[32m${r.method.padEnd(7)}\x1b[0m ${r.path}`);
|
|
145
|
+
});
|
|
146
|
+
if (this._routes.length > limit) {
|
|
147
|
+
console.log(` ... and ${this._routes.length - limit} more`);
|
|
148
|
+
}
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Disables the automatic logging of routes that happens in development mode.
|
|
153
|
+
*
|
|
154
|
+
* @returns The current builder instance.
|
|
155
|
+
*/
|
|
156
|
+
disableLogging() {
|
|
157
|
+
this._shouldLog = false;
|
|
158
|
+
return this;
|
|
37
159
|
}
|
|
38
160
|
/**
|
|
39
161
|
* @deprecated Prefer `addGroup()` or `addRoute()` for structured routing.
|
|
@@ -73,60 +195,72 @@ export class RouterBuilder {
|
|
|
73
195
|
* @returns The current builder instance (for chaining).
|
|
74
196
|
*/
|
|
75
197
|
addGroup(group) {
|
|
76
|
-
this.
|
|
198
|
+
this._groups.push(group);
|
|
77
199
|
return this;
|
|
78
200
|
}
|
|
79
201
|
/**
|
|
80
202
|
* Adds a GET route.
|
|
81
203
|
* @param path Route path (e.g., `/items/:id`)
|
|
82
|
-
* @param
|
|
204
|
+
* @param handlers Middleware(s) followed by a request handler function.
|
|
83
205
|
*/
|
|
84
|
-
addGet(path,
|
|
85
|
-
return this.add(HttpMethod.GET, path,
|
|
206
|
+
addGet(path, ...handlers) {
|
|
207
|
+
return this.add(HttpMethod.GET, path, ...handlers);
|
|
86
208
|
}
|
|
87
209
|
/**
|
|
88
210
|
* Adds a POST route.
|
|
89
211
|
* @param path Route path.
|
|
90
|
-
* @param
|
|
212
|
+
* @param handlers Middleware(s) followed by a request handler function.
|
|
91
213
|
*/
|
|
92
|
-
addPost(path,
|
|
93
|
-
return this.add(HttpMethod.POST, path,
|
|
214
|
+
addPost(path, ...handlers) {
|
|
215
|
+
return this.add(HttpMethod.POST, path, ...handlers);
|
|
94
216
|
}
|
|
95
217
|
/**
|
|
96
218
|
* Adds a PUT route.
|
|
97
219
|
* @param path Route path.
|
|
98
|
-
* @param
|
|
220
|
+
* @param handlers Middleware(s) followed by a request handler function.
|
|
99
221
|
*/
|
|
100
|
-
addPut(path,
|
|
101
|
-
return this.add(HttpMethod.PUT, path,
|
|
222
|
+
addPut(path, ...handlers) {
|
|
223
|
+
return this.add(HttpMethod.PUT, path, ...handlers);
|
|
102
224
|
}
|
|
103
225
|
/**
|
|
104
226
|
* Adds a DELETE route.
|
|
105
227
|
* @param path Route path.
|
|
106
|
-
* @param
|
|
228
|
+
* @param handlers Middleware(s) followed by a request handler function.
|
|
107
229
|
*/
|
|
108
|
-
addDelete(path,
|
|
109
|
-
return this.add(HttpMethod.DELETE, path,
|
|
230
|
+
addDelete(path, ...handlers) {
|
|
231
|
+
return this.add(HttpMethod.DELETE, path, ...handlers);
|
|
110
232
|
}
|
|
111
233
|
/**
|
|
112
234
|
* Adds a PATCH route.
|
|
113
235
|
* @param path Route path.
|
|
114
|
-
* @param
|
|
236
|
+
* @param handlers Middleware(s) followed by a request handler function.
|
|
115
237
|
*/
|
|
116
|
-
addPatch(path,
|
|
117
|
-
return this.add(HttpMethod.PATCH, path,
|
|
238
|
+
addPatch(path, ...handlers) {
|
|
239
|
+
return this.add(HttpMethod.PATCH, path, ...handlers);
|
|
118
240
|
}
|
|
119
241
|
/**
|
|
120
242
|
* Internal helper to add a route with any HTTP method.
|
|
121
243
|
*
|
|
122
244
|
* @param method The HTTP method.
|
|
123
245
|
* @param subPath Path segment (can be relative or absolute).
|
|
124
|
-
* @param
|
|
246
|
+
* @param args Middleware(s) and handler.
|
|
125
247
|
* @returns The current builder instance (for chaining).
|
|
126
248
|
*/
|
|
127
|
-
add(method, subPath,
|
|
249
|
+
add(method, subPath, ...args) {
|
|
250
|
+
let metadata;
|
|
251
|
+
if (args.length > 1 && typeof args[args.length - 1] === 'object' && typeof args[args.length - 2] === 'function') {
|
|
252
|
+
metadata = args.pop();
|
|
253
|
+
}
|
|
254
|
+
const handler = args.pop();
|
|
255
|
+
const middlewares = args;
|
|
128
256
|
const normalizedPath = subPath.startsWith('/') ? subPath : `/${subPath}`;
|
|
129
|
-
this._routes.push(defineRoute(
|
|
257
|
+
this._routes.push(defineRoute({
|
|
258
|
+
method,
|
|
259
|
+
path: normalizedPath,
|
|
260
|
+
handler,
|
|
261
|
+
middlewares,
|
|
262
|
+
metadata
|
|
263
|
+
}));
|
|
130
264
|
return this;
|
|
131
265
|
}
|
|
132
266
|
/**
|
|
@@ -138,7 +272,62 @@ export class RouterBuilder {
|
|
|
138
272
|
* @returns A fully resolved Astro route handler.
|
|
139
273
|
*/
|
|
140
274
|
build() {
|
|
141
|
-
|
|
275
|
+
if (this._shouldLog) {
|
|
276
|
+
this.logRoutes();
|
|
277
|
+
}
|
|
278
|
+
// Collect all routes from builder and groups
|
|
279
|
+
const allRoutes = [...this._routes];
|
|
280
|
+
for (const group of this._groups) {
|
|
281
|
+
allRoutes.push(...group.getRoutes());
|
|
282
|
+
}
|
|
283
|
+
// Apply global middlewares to all routes before building
|
|
284
|
+
const finalRoutes = allRoutes.map(route => ({
|
|
285
|
+
...route,
|
|
286
|
+
middlewares: [...this._middlewares, ...(route.middlewares || [])]
|
|
287
|
+
}));
|
|
288
|
+
return defineRouter(finalRoutes, this._options);
|
|
142
289
|
}
|
|
143
290
|
}
|
|
144
291
|
RouterBuilder._registerWarned = false;
|
|
292
|
+
/**
|
|
293
|
+
* A global RouterBuilder instance for easy, centralized route registration.
|
|
294
|
+
*/
|
|
295
|
+
RouterBuilder.global = new RouterBuilder();
|
|
296
|
+
/**
|
|
297
|
+
* A convenience helper to create a router.
|
|
298
|
+
*
|
|
299
|
+
* If modules are provided (e.g. from Vite's `import.meta.glob`), they will be registered.
|
|
300
|
+
* If no modules are provided, it will automatically include all routes that were
|
|
301
|
+
* registered via the auto-registration flags (`defineRoute(..., true)`).
|
|
302
|
+
*
|
|
303
|
+
* @example Auto-discovery via glob:
|
|
304
|
+
* ```ts
|
|
305
|
+
* export const ALL = createRouter(import.meta.glob('./**\/*.ts', { eager: true }));
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @example Auto-registration via global registry:
|
|
309
|
+
* ```ts
|
|
310
|
+
* export const ALL = createRouter();
|
|
311
|
+
* ```
|
|
312
|
+
*
|
|
313
|
+
* @param modulesOrOptions Either modules to register or router options.
|
|
314
|
+
* @param options Router options (if first arg is modules).
|
|
315
|
+
* @returns An Astro-compatible route handler.
|
|
316
|
+
*/
|
|
317
|
+
export function createRouter(modulesOrOptions, options) {
|
|
318
|
+
let modules;
|
|
319
|
+
let finalOptions;
|
|
320
|
+
if (modulesOrOptions && !('basePath' in modulesOrOptions || 'onNotFound' in modulesOrOptions || 'debug' in modulesOrOptions)) {
|
|
321
|
+
modules = modulesOrOptions;
|
|
322
|
+
finalOptions = options;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
finalOptions = modulesOrOptions;
|
|
326
|
+
}
|
|
327
|
+
const builder = new RouterBuilder(finalOptions);
|
|
328
|
+
if (modules) {
|
|
329
|
+
builder.addModules(modules);
|
|
330
|
+
}
|
|
331
|
+
builder.addRegistered();
|
|
332
|
+
return builder.build();
|
|
333
|
+
}
|
|
@@ -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
|
*
|
|
@@ -14,6 +15,7 @@ import { Handler } from "./defineHandler";
|
|
|
14
15
|
export declare class RouteGroup {
|
|
15
16
|
private basePath;
|
|
16
17
|
private routes;
|
|
18
|
+
private middlewares;
|
|
17
19
|
/**
|
|
18
20
|
* Creates a new route group with the specified base path.
|
|
19
21
|
* Trailing slashes are automatically removed.
|
|
@@ -25,49 +27,61 @@ export declare class RouteGroup {
|
|
|
25
27
|
* Returns the normalized base path used by the group.
|
|
26
28
|
*/
|
|
27
29
|
getBasePath(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Adds a middleware to all routes in this group.
|
|
32
|
+
*
|
|
33
|
+
* @param middleware - The middleware function to add
|
|
34
|
+
* @returns The current group instance
|
|
35
|
+
*/
|
|
36
|
+
use(middleware: Middleware): this;
|
|
28
37
|
/**
|
|
29
38
|
* Registers a GET route under the group's base path.
|
|
30
39
|
*
|
|
31
40
|
* @param path - Path relative to the base path (e.g. "/:id")
|
|
32
|
-
* @param
|
|
41
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
33
42
|
*/
|
|
34
|
-
addGet(path: string,
|
|
43
|
+
addGet(path: string, ...handlers: any[]): this;
|
|
35
44
|
/**
|
|
36
45
|
* Registers a POST route under the group's base path.
|
|
37
46
|
*
|
|
38
47
|
* @param path - Path relative to the base path
|
|
39
|
-
* @param
|
|
48
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
40
49
|
*/
|
|
41
|
-
addPost(path: string,
|
|
50
|
+
addPost(path: string, ...handlers: any[]): this;
|
|
42
51
|
/**
|
|
43
52
|
* Registers a PUT route under the group's base path.
|
|
44
53
|
*
|
|
45
54
|
* @param path - Path relative to the base path
|
|
46
|
-
* @param
|
|
55
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
47
56
|
*/
|
|
48
|
-
addPut(path: string,
|
|
57
|
+
addPut(path: string, ...handlers: any[]): this;
|
|
49
58
|
/**
|
|
50
59
|
* Registers a DELETE route under the group's base path.
|
|
51
60
|
*
|
|
52
61
|
* @param path - Path relative to the base path
|
|
53
|
-
* @param
|
|
62
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
54
63
|
*/
|
|
55
|
-
addDelete(path: string,
|
|
64
|
+
addDelete(path: string, ...handlers: any[]): this;
|
|
56
65
|
/**
|
|
57
66
|
* Registers a PATCH route under the group's base path.
|
|
58
67
|
*
|
|
59
68
|
* @param path - Path relative to the base path
|
|
60
|
-
* @param
|
|
69
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
61
70
|
*/
|
|
62
|
-
addPatch(path: string,
|
|
71
|
+
addPatch(path: string, ...handlers: any[]): this;
|
|
63
72
|
/**
|
|
64
|
-
*
|
|
73
|
+
* Registers a route under the group's base path.
|
|
65
74
|
*
|
|
66
75
|
* @param method - HTTP verb
|
|
67
|
-
* @param
|
|
68
|
-
* @param
|
|
76
|
+
* @param path - Path relative to the base path
|
|
77
|
+
* @param args - Middleware(s) and handler
|
|
78
|
+
* @returns The current group instance
|
|
79
|
+
*/
|
|
80
|
+
add(method: HttpMethod, path: string, ...args: any[]): this;
|
|
81
|
+
/**
|
|
82
|
+
* Registers the group and all its current routes to the global registry.
|
|
69
83
|
*/
|
|
70
|
-
|
|
84
|
+
register(): this;
|
|
71
85
|
/**
|
|
72
86
|
* Returns all the registered routes in the group.
|
|
73
87
|
*/
|
|
@@ -78,10 +92,11 @@ export declare class RouteGroup {
|
|
|
78
92
|
*
|
|
79
93
|
* @param basePath - The base path prefix for all routes
|
|
80
94
|
* @param configure - Optional callback to configure the group inline
|
|
95
|
+
* @param autoRegister - If true, registers the group to the global registry
|
|
81
96
|
*
|
|
82
97
|
* @example
|
|
83
98
|
* const users = defineGroup('/users', (group) => {
|
|
84
99
|
* group.addGet('/:id', handler);
|
|
85
|
-
* });
|
|
100
|
+
* }, true);
|
|
86
101
|
*/
|
|
87
|
-
export declare function defineGroup(basePath: string, configure?: (group: RouteGroup) => void): RouteGroup;
|
|
102
|
+
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
|
*
|
|
@@ -20,6 +21,7 @@ export class RouteGroup {
|
|
|
20
21
|
*/
|
|
21
22
|
constructor(basePath) {
|
|
22
23
|
this.routes = [];
|
|
24
|
+
this.middlewares = [];
|
|
23
25
|
this.basePath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
@@ -28,61 +30,97 @@ export class RouteGroup {
|
|
|
28
30
|
getBasePath() {
|
|
29
31
|
return this.basePath;
|
|
30
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Adds a middleware to all routes in this group.
|
|
35
|
+
*
|
|
36
|
+
* @param middleware - The middleware function to add
|
|
37
|
+
* @returns The current group instance
|
|
38
|
+
*/
|
|
39
|
+
use(middleware) {
|
|
40
|
+
this.middlewares.push(middleware);
|
|
41
|
+
// Apply to already registered routes in this group
|
|
42
|
+
for (const route of this.routes) {
|
|
43
|
+
if (!route.middlewares)
|
|
44
|
+
route.middlewares = [];
|
|
45
|
+
route.middlewares.push(middleware);
|
|
46
|
+
}
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
31
49
|
/**
|
|
32
50
|
* Registers a GET route under the group's base path.
|
|
33
51
|
*
|
|
34
52
|
* @param path - Path relative to the base path (e.g. "/:id")
|
|
35
|
-
* @param
|
|
53
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
36
54
|
*/
|
|
37
|
-
addGet(path,
|
|
38
|
-
return this.add(HttpMethod.GET, path,
|
|
55
|
+
addGet(path, ...handlers) {
|
|
56
|
+
return this.add(HttpMethod.GET, path, ...handlers);
|
|
39
57
|
}
|
|
40
58
|
/**
|
|
41
59
|
* Registers a POST route under the group's base path.
|
|
42
60
|
*
|
|
43
61
|
* @param path - Path relative to the base path
|
|
44
|
-
* @param
|
|
62
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
45
63
|
*/
|
|
46
|
-
addPost(path,
|
|
47
|
-
return this.add(HttpMethod.POST, path,
|
|
64
|
+
addPost(path, ...handlers) {
|
|
65
|
+
return this.add(HttpMethod.POST, path, ...handlers);
|
|
48
66
|
}
|
|
49
67
|
/**
|
|
50
68
|
* Registers a PUT route under the group's base path.
|
|
51
69
|
*
|
|
52
70
|
* @param path - Path relative to the base path
|
|
53
|
-
* @param
|
|
71
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
54
72
|
*/
|
|
55
|
-
addPut(path,
|
|
56
|
-
return this.add(HttpMethod.PUT, path,
|
|
73
|
+
addPut(path, ...handlers) {
|
|
74
|
+
return this.add(HttpMethod.PUT, path, ...handlers);
|
|
57
75
|
}
|
|
58
76
|
/**
|
|
59
77
|
* Registers a DELETE route under the group's base path.
|
|
60
78
|
*
|
|
61
79
|
* @param path - Path relative to the base path
|
|
62
|
-
* @param
|
|
80
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
63
81
|
*/
|
|
64
|
-
addDelete(path,
|
|
65
|
-
return this.add(HttpMethod.DELETE, path,
|
|
82
|
+
addDelete(path, ...handlers) {
|
|
83
|
+
return this.add(HttpMethod.DELETE, path, ...handlers);
|
|
66
84
|
}
|
|
67
85
|
/**
|
|
68
86
|
* Registers a PATCH route under the group's base path.
|
|
69
87
|
*
|
|
70
88
|
* @param path - Path relative to the base path
|
|
71
|
-
* @param
|
|
89
|
+
* @param handlers - Middleware(s) followed by a handler function
|
|
72
90
|
*/
|
|
73
|
-
addPatch(path,
|
|
74
|
-
return this.add(HttpMethod.PATCH, path,
|
|
91
|
+
addPatch(path, ...handlers) {
|
|
92
|
+
return this.add(HttpMethod.PATCH, path, ...handlers);
|
|
75
93
|
}
|
|
76
94
|
/**
|
|
77
|
-
*
|
|
95
|
+
* Registers a route under the group's base path.
|
|
78
96
|
*
|
|
79
97
|
* @param method - HTTP verb
|
|
80
|
-
* @param
|
|
81
|
-
* @param
|
|
98
|
+
* @param path - Path relative to the base path
|
|
99
|
+
* @param args - Middleware(s) and handler
|
|
100
|
+
* @returns The current group instance
|
|
82
101
|
*/
|
|
83
|
-
add(method,
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
add(method, path, ...args) {
|
|
103
|
+
let metadata;
|
|
104
|
+
if (args.length > 1 && typeof args[args.length - 1] === 'object' && typeof args[args.length - 2] === 'function') {
|
|
105
|
+
metadata = args.pop();
|
|
106
|
+
}
|
|
107
|
+
const handler = args.pop();
|
|
108
|
+
const middlewares = args;
|
|
109
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
110
|
+
this.routes.push(defineRoute({
|
|
111
|
+
method,
|
|
112
|
+
path: `${this.basePath}${normalizedPath}`,
|
|
113
|
+
handler,
|
|
114
|
+
middlewares: [...this.middlewares, ...middlewares],
|
|
115
|
+
metadata
|
|
116
|
+
}));
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Registers the group and all its current routes to the global registry.
|
|
121
|
+
*/
|
|
122
|
+
register() {
|
|
123
|
+
globalRegistry.register(this);
|
|
86
124
|
return this;
|
|
87
125
|
}
|
|
88
126
|
/**
|
|
@@ -97,15 +135,19 @@ export class RouteGroup {
|
|
|
97
135
|
*
|
|
98
136
|
* @param basePath - The base path prefix for all routes
|
|
99
137
|
* @param configure - Optional callback to configure the group inline
|
|
138
|
+
* @param autoRegister - If true, registers the group to the global registry
|
|
100
139
|
*
|
|
101
140
|
* @example
|
|
102
141
|
* const users = defineGroup('/users', (group) => {
|
|
103
142
|
* group.addGet('/:id', handler);
|
|
104
|
-
* });
|
|
143
|
+
* }, true);
|
|
105
144
|
*/
|
|
106
|
-
export function defineGroup(basePath, configure) {
|
|
145
|
+
export function defineGroup(basePath, configure, autoRegister) {
|
|
107
146
|
const group = new RouteGroup(basePath);
|
|
108
147
|
if (configure)
|
|
109
148
|
configure(group);
|
|
149
|
+
if (autoRegister) {
|
|
150
|
+
globalRegistry.register(group);
|
|
151
|
+
}
|
|
110
152
|
return group;
|
|
111
153
|
}
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import type { APIContext, APIRoute } from 'astro';
|
|
2
2
|
import { type ResultResponse } from './responseHelpers';
|
|
3
|
+
/**
|
|
4
|
+
* Enhanced Astro context for Routify.
|
|
5
|
+
*/
|
|
6
|
+
export interface RoutifyContext extends APIContext {
|
|
7
|
+
/**
|
|
8
|
+
* Parsed query parameters from the URL.
|
|
9
|
+
*/
|
|
10
|
+
query: Record<string, string>;
|
|
11
|
+
/**
|
|
12
|
+
* Shared data container for middlewares and handlers (e.g., validation results).
|
|
13
|
+
*/
|
|
14
|
+
data: Record<string, any>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A middleware function that can modify the context or short-circuit the response.
|
|
18
|
+
*/
|
|
19
|
+
export type Middleware = (ctx: RoutifyContext, next: () => Promise<Response>) => Promise<Response> | Response;
|
|
3
20
|
/**
|
|
4
21
|
* A flexible route handler that can return:
|
|
5
22
|
* - a native `Response` object,
|
|
6
23
|
* - a structured `ResultResponse` object,
|
|
7
24
|
* - or a file stream (Blob, ArrayBuffer, or ReadableStream).
|
|
8
25
|
*/
|
|
9
|
-
export type Handler = (ctx:
|
|
26
|
+
export type Handler = (ctx: RoutifyContext) => Promise<ResultResponse | Response> | ResultResponse | Response;
|
|
10
27
|
/**
|
|
11
28
|
* Wraps a `Handler` function into an `APIRoute` that:
|
|
12
29
|
* - logs requests and responses,
|
|
@@ -18,10 +35,3 @@ export type Handler = (ctx: APIContext) => Promise<ResultResponse | Response> |
|
|
|
18
35
|
* @returns An Astro-compatible `APIRoute` function
|
|
19
36
|
*/
|
|
20
37
|
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>;
|