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.
@@ -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._routes.push(...group.getRoutes());
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 handler Request handler function.
204
+ * @param handlers Middleware(s) followed by a request handler function.
83
205
  */
84
- addGet(path, handler) {
85
- return this.add(HttpMethod.GET, path, handler);
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 handler Request handler function.
212
+ * @param handlers Middleware(s) followed by a request handler function.
91
213
  */
92
- addPost(path, handler) {
93
- return this.add(HttpMethod.POST, path, handler);
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 handler Request handler function.
220
+ * @param handlers Middleware(s) followed by a request handler function.
99
221
  */
100
- addPut(path, handler) {
101
- return this.add(HttpMethod.PUT, path, handler);
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 handler Request handler function.
228
+ * @param handlers Middleware(s) followed by a request handler function.
107
229
  */
108
- addDelete(path, handler) {
109
- return this.add(HttpMethod.DELETE, path, handler);
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 handler Request handler function.
236
+ * @param handlers Middleware(s) followed by a request handler function.
115
237
  */
116
- addPatch(path, handler) {
117
- return this.add(HttpMethod.PATCH, path, handler);
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 handler Request handler.
246
+ * @param args Middleware(s) and handler.
125
247
  * @returns The current builder instance (for chaining).
126
248
  */
127
- add(method, subPath, handler) {
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(method, normalizedPath, handler));
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
- return defineRouter(this._routes, this._options);
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 { Handler } from "./defineHandler";
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 handler - The handler function for this route
41
+ * @param handlers - Middleware(s) followed by a handler function
33
42
  */
34
- addGet(path: string, handler: Handler): this;
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 handler - The handler function for this route
48
+ * @param handlers - Middleware(s) followed by a handler function
40
49
  */
41
- addPost(path: string, handler: Handler): this;
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 handler - The handler function for this route
55
+ * @param handlers - Middleware(s) followed by a handler function
47
56
  */
48
- addPut(path: string, handler: Handler): this;
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 handler - The handler function for this route
62
+ * @param handlers - Middleware(s) followed by a handler function
54
63
  */
55
- addDelete(path: string, handler: Handler): this;
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 handler - The handler function for this route
69
+ * @param handlers - Middleware(s) followed by a handler function
61
70
  */
62
- addPatch(path: string, handler: Handler): this;
71
+ addPatch(path: string, ...handlers: any[]): this;
63
72
  /**
64
- * Internal method to register a route under the group with any HTTP method.
73
+ * Registers a route under the group's base path.
65
74
  *
66
75
  * @param method - HTTP verb
67
- * @param subPath - Route path relative to the base
68
- * @param handler - The handler function for this route
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
- private add;
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;
@@ -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 handler - The handler function for this route
53
+ * @param handlers - Middleware(s) followed by a handler function
36
54
  */
37
- addGet(path, handler) {
38
- return this.add(HttpMethod.GET, path, handler);
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 handler - The handler function for this route
62
+ * @param handlers - Middleware(s) followed by a handler function
45
63
  */
46
- addPost(path, handler) {
47
- return this.add(HttpMethod.POST, path, handler);
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 handler - The handler function for this route
71
+ * @param handlers - Middleware(s) followed by a handler function
54
72
  */
55
- addPut(path, handler) {
56
- return this.add(HttpMethod.PUT, path, handler);
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 handler - The handler function for this route
80
+ * @param handlers - Middleware(s) followed by a handler function
63
81
  */
64
- addDelete(path, handler) {
65
- return this.add(HttpMethod.DELETE, path, handler);
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 handler - The handler function for this route
89
+ * @param handlers - Middleware(s) followed by a handler function
72
90
  */
73
- addPatch(path, handler) {
74
- return this.add(HttpMethod.PATCH, path, handler);
91
+ addPatch(path, ...handlers) {
92
+ return this.add(HttpMethod.PATCH, path, ...handlers);
75
93
  }
76
94
  /**
77
- * Internal method to register a route under the group with any HTTP method.
95
+ * Registers a route under the group's base path.
78
96
  *
79
97
  * @param method - HTTP verb
80
- * @param subPath - Route path relative to the base
81
- * @param handler - The handler function for this route
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, subPath, handler) {
84
- const normalizedPath = subPath.startsWith('/') ? subPath : `/${subPath}`;
85
- this.routes.push(defineRoute(method, `${this.basePath}${normalizedPath}`, handler));
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: APIContext) => Promise<ResultResponse | Response> | ResultResponse | Response;
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>;