@nextrush/class 1.0.0-beta.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.
@@ -0,0 +1,2306 @@
1
+ import { HttpMethod, Context, RouteHandler, Middleware, MetadataContribution } from '@nextrush/types';
2
+ import { Token, Constructor as Constructor$1, Scope, Container } from '@nextrush/di';
3
+ export { Container, Repository, Service, container, createContainer, inject } from '@nextrush/di';
4
+ import { Application } from '@nextrush/core';
5
+ import { InternalServerError, HttpErrorOptions, ForbiddenError, BadRequestError } from '@nextrush/errors';
6
+ export { HttpError } from '@nextrush/errors';
7
+
8
+ /**
9
+ * @nextrush/decorators - Controller Type Definitions
10
+ *
11
+ * Metadata and options shapes for the @Controller decorator, plus the shared
12
+ * middleware reference type used by both controller- and route-level metadata.
13
+ */
14
+ /**
15
+ * Reference to middleware - can be a class token or function
16
+ */
17
+ type MiddlewareRef = symbol | string | ((...args: unknown[]) => unknown);
18
+ /**
19
+ * Controller metadata stored by @Controller decorator
20
+ */
21
+ interface ControllerMetadata {
22
+ /** Base path prefix for all routes in this controller */
23
+ readonly path: string;
24
+ /** Optional controller version for API versioning */
25
+ readonly version?: string;
26
+ /** Middleware to apply to all routes in this controller */
27
+ readonly middleware?: MiddlewareRef[];
28
+ /** Controller-level tags for documentation/grouping */
29
+ readonly tags?: string[];
30
+ }
31
+ /**
32
+ * Options for @Controller decorator
33
+ */
34
+ interface ControllerOptions {
35
+ /** Base path prefix for all routes */
36
+ path?: string;
37
+ /** API version prefix (e.g., 'v1' → '/v1/users') */
38
+ version?: string;
39
+ /** Middleware to apply to all routes */
40
+ middleware?: MiddlewareRef[];
41
+ /** Tags for documentation grouping */
42
+ tags?: string[];
43
+ }
44
+
45
+ /**
46
+ * @nextrush/decorators - Route Type Definitions
47
+ *
48
+ * Metadata and options shapes for route decorators (@Get, @Post, etc.) and the
49
+ * response-shaping decorators (@SetHeader, @Redirect).
50
+ */
51
+
52
+ /**
53
+ * Supported HTTP methods for route decorators.
54
+ *
55
+ * `'ALL'` is a decorator-metadata-only sentinel produced exclusively by
56
+ * `@All()` (T016) — it means "every standard method," not a literal HTTP
57
+ * verb, and never reaches the wire. It is intentionally NOT a member of
58
+ * `@nextrush/router`'s `HttpMethod` (a real, on-the-wire method set that the
59
+ * matching engine and static-route hash keys are built around) — widening
60
+ * that frozen core type for a class-package decorator concern would ripple
61
+ * into router internals with no benefit. The registrar's dispatch
62
+ * (`route.method.toLowerCase()` → `router['all']`) already resolves this
63
+ * value correctly since `Router.all()` exists with that exact name.
64
+ */
65
+ type RouteMethods = Extract<HttpMethod, 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'> | 'ALL';
66
+ /**
67
+ * Route metadata stored by @Get, @Post, etc. decorators
68
+ */
69
+ interface ControllerRouteMetadata {
70
+ /** HTTP method for this route */
71
+ readonly method: RouteMethods;
72
+ /** Path pattern for this route (relative to controller path) */
73
+ readonly path: string;
74
+ /** Method name on the controller class */
75
+ readonly methodName: string | symbol;
76
+ /** Parameter index in the prototype */
77
+ readonly propertyKey: string | symbol;
78
+ /** Route-specific middleware */
79
+ readonly middleware?: MiddlewareRef[];
80
+ /** Response status code (default: 200 for GET, 201 for POST) */
81
+ readonly statusCode?: number;
82
+ /** Route description for documentation */
83
+ readonly description?: string;
84
+ /** Whether this route is deprecated */
85
+ readonly deprecated?: boolean;
86
+ }
87
+ /**
88
+ * @deprecated Use {@link ControllerRouteMetadata}. `RouteMetadata` collided with the
89
+ * unrelated, renderer-facing `RouteMetadata` contract exported from `@nextrush/types` (and
90
+ * re-exported via `nextrush`'s `.` entry) — the two shapes are structurally incompatible
91
+ * despite sharing a name. This alias will be removed in the next major; migrate now.
92
+ * See docs/RFC/framework-composition/020-framework-composition-integrity.md.
93
+ */
94
+ type RouteMetadata = ControllerRouteMetadata;
95
+ /**
96
+ * Options for route decorators (@Get, @Post, etc.)
97
+ */
98
+ interface RouteOptions {
99
+ /** Route path (alternative to string argument) */
100
+ path?: string;
101
+ /** Route-specific middleware */
102
+ middleware?: MiddlewareRef[];
103
+ /** Response status code */
104
+ statusCode?: number;
105
+ /** Route description */
106
+ description?: string;
107
+ /** Mark route as deprecated */
108
+ deprecated?: boolean;
109
+ }
110
+ /**
111
+ * Metadata for @SetHeader decorator — stored per method.
112
+ */
113
+ interface ResponseHeaderMetadata {
114
+ readonly name: string;
115
+ readonly value: string;
116
+ }
117
+ /**
118
+ * Metadata for @Redirect decorator — stored per method.
119
+ */
120
+ interface RedirectMetadata {
121
+ readonly url: string;
122
+ readonly statusCode: number;
123
+ }
124
+
125
+ /**
126
+ * @nextrush/decorators - Parameter Type Definitions
127
+ *
128
+ * Metadata and options shapes for parameter decorators (@Body, @Param, @Query,
129
+ * @Header, and custom param decorators), plus their transform/extractor types.
130
+ */
131
+
132
+ /**
133
+ * Parameter source types for parameter decorators
134
+ */
135
+ type ParamSource = 'body' | 'query' | 'param' | 'header' | 'ctx' | 'req' | 'res' | 'custom';
136
+ /**
137
+ * Transform function for parameter value transformation.
138
+ * Supports both sync and async transforms.
139
+ */
140
+ type TransformFn<TInput = unknown, TOutput = unknown> = ((value: TInput) => TOutput) | ((value: TInput) => Promise<TOutput>);
141
+ /**
142
+ * Custom parameter extractor function.
143
+ *
144
+ * Receives the context object and returns the extracted value.
145
+ * Supports both sync and async extraction.
146
+ */
147
+ type CustomParamExtractor<T = unknown> = ((ctx: Context) => T) | ((ctx: Context) => Promise<T>);
148
+ /**
149
+ * Parameter metadata stored by @Body, @Param, etc. decorators
150
+ */
151
+ interface ParamMetadata {
152
+ /** Source of the parameter value */
153
+ readonly source: ParamSource;
154
+ /** Parameter index in method signature */
155
+ readonly index: number;
156
+ /** Property name to extract (e.g., 'id' from params.id) */
157
+ readonly name?: string;
158
+ /** Whether the parameter is required (default: true for body/param) */
159
+ readonly required?: boolean;
160
+ /** Default value if not provided */
161
+ readonly defaultValue?: unknown;
162
+ /** Validation pipe or transform function */
163
+ readonly transform?: TransformFn;
164
+ /** Custom extractor function for user-defined param decorators */
165
+ readonly customExtractor?: CustomParamExtractor;
166
+ }
167
+ /**
168
+ * Options for @Body decorator
169
+ */
170
+ interface BodyOptions {
171
+ /** Whether the body is required (default: true) */
172
+ required?: boolean;
173
+ /** Transform function to apply */
174
+ transform?: TransformFn;
175
+ }
176
+ /**
177
+ * Options for @Param decorator
178
+ */
179
+ interface ParamOptions {
180
+ /** Whether the param is required (default: true) */
181
+ required?: boolean;
182
+ /** Default value if not provided */
183
+ defaultValue?: unknown;
184
+ /** Transform function (e.g., parseInt for numeric IDs) */
185
+ transform?: TransformFn;
186
+ }
187
+ /**
188
+ * Options for @Query decorator
189
+ */
190
+ interface QueryOptions {
191
+ /** Whether the query param is required (default: false) */
192
+ required?: boolean;
193
+ /** Default value if not provided */
194
+ defaultValue?: unknown;
195
+ /** Transform function */
196
+ transform?: TransformFn;
197
+ }
198
+ /**
199
+ * Options for @Header decorator
200
+ */
201
+ interface HeaderOptions {
202
+ /** Whether the header is required (default: false) */
203
+ required?: boolean;
204
+ /** Default value if not provided */
205
+ defaultValue?: unknown;
206
+ }
207
+
208
+ /**
209
+ * @nextrush/decorators - Guard Type Definitions
210
+ *
211
+ * Types for the @UseGuard decorator: the guard context, function and
212
+ * class-based guard contracts, and the stored guard metadata. Also home to the
213
+ * generic Constructor primitive shared with exception-filter types.
214
+ */
215
+ /**
216
+ * Constructor type for class-based guards
217
+ */
218
+ type Constructor<T = unknown> = new (...args: unknown[]) => T;
219
+ /**
220
+ * Minimal context interface for guards (avoids circular dependency)
221
+ */
222
+ interface GuardContext {
223
+ readonly method: string;
224
+ readonly path: string;
225
+ readonly params: Record<string, string>;
226
+ readonly query: Record<string, string | string[] | undefined>;
227
+ readonly headers: Record<string, string | string[] | undefined>;
228
+ readonly body: unknown;
229
+ readonly state: Record<string, unknown>;
230
+ get(name: string): string | undefined;
231
+ }
232
+ /**
233
+ * Guard function type.
234
+ *
235
+ * Guards determine if a request should proceed to the handler.
236
+ * Return true to allow, false to reject, or throw an error for custom handling.
237
+ */
238
+ type GuardFn = (ctx: GuardContext) => boolean | Promise<boolean>;
239
+ /**
240
+ * Interface for class-based guards with dependency injection support.
241
+ *
242
+ * Implement this interface to create guards that can be:
243
+ * - Resolved from the DI container
244
+ * - Injected with dependencies
245
+ * - Unit tested with mock dependencies
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * import { Service } from '@nextrush/di';
250
+ * import type { CanActivate, GuardContext } from 'nextrush/class';
251
+ *
252
+ * @Service()
253
+ * class AuthGuard implements CanActivate {
254
+ * constructor(private authService: AuthService) {}
255
+ *
256
+ * async canActivate(ctx: GuardContext): Promise<boolean> {
257
+ * const token = ctx.get('authorization');
258
+ * if (!token) return false;
259
+ *
260
+ * const user = await this.authService.verify(token);
261
+ * ctx.state.user = user;
262
+ * return Boolean(user);
263
+ * }
264
+ * }
265
+ * ```
266
+ */
267
+ interface CanActivate {
268
+ canActivate(ctx: GuardContext): boolean | Promise<boolean>;
269
+ }
270
+ /**
271
+ * Guard type that can be either a function or a class implementing CanActivate.
272
+ * Used by @UseGuard decorator to accept both patterns.
273
+ */
274
+ type Guard = GuardFn | Constructor<CanActivate>;
275
+ /**
276
+ * Guard metadata stored by @UseGuard decorator
277
+ */
278
+ interface GuardMetadata {
279
+ /** Array of guards (can be functions or class constructors) */
280
+ readonly guards: Guard[];
281
+ /** Whether this is a class or method level guard */
282
+ readonly target: 'class' | 'method';
283
+ /** Method name (only for method-level guards) */
284
+ readonly methodName?: string | symbol;
285
+ }
286
+
287
+ /**
288
+ * @nextrush/decorators - Exception Filter Type Definitions
289
+ *
290
+ * Types for the @UseFilter / @Catch decorators: the filter contract, its class
291
+ * constructor alias, and the stored filter metadata.
292
+ */
293
+
294
+ /**
295
+ * Interface for class-based exception filters with dependency injection support.
296
+ *
297
+ * A filter catches errors thrown by a controller route (guards, parameter
298
+ * resolution, or the handler method) and produces the response by mutating
299
+ * `ctx` (status, headers, body). Filters are resolved from the DI container,
300
+ * so they may inject services (loggers, metrics, error mappers).
301
+ *
302
+ * Which errors a filter handles is declared with {@link Catch}. A filter is
303
+ * only invoked when attached to a controller/route via {@link UseFilter}.
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * import { Service } from '@nextrush/di';
308
+ * import { Catch, type ExceptionFilter } from 'nextrush/class';
309
+ * import { NotFoundError } from '@nextrush/errors';
310
+ * import type { Context } from '@nextrush/types';
311
+ *
312
+ * @Service()
313
+ * @Catch(EntityNotFoundError)
314
+ * class NotFoundFilter implements ExceptionFilter {
315
+ * catch(error: unknown, ctx: Context): void {
316
+ * ctx.status = 404;
317
+ * ctx.json({ error: 'Resource not found' });
318
+ * }
319
+ * }
320
+ * ```
321
+ */
322
+ interface ExceptionFilter {
323
+ catch(error: unknown, ctx: Context): void | Promise<void>;
324
+ }
325
+ /**
326
+ * Constructor type for a class-based exception filter.
327
+ * Accepted by {@link UseFilter}; resolved from the DI container at catch time.
328
+ */
329
+ type ExceptionFilterClass = Constructor<ExceptionFilter>;
330
+ /**
331
+ * Exception filter metadata stored by the @UseFilter decorator.
332
+ */
333
+ interface FilterMetadata {
334
+ /** Filter classes applied at this target */
335
+ readonly filters: ExceptionFilterClass[];
336
+ /** Whether this is a class or method level filter */
337
+ readonly target: 'class' | 'method';
338
+ /** Method name (only for method-level filters) */
339
+ readonly methodName?: string | symbol;
340
+ }
341
+
342
+ /**
343
+ * @nextrush/decorators - Interceptor Type Definitions
344
+ *
345
+ * Types for the @UseInterceptor decorator: the interceptor contract, its class
346
+ * constructor alias, and the stored interceptor metadata.
347
+ *
348
+ * An interceptor wraps the controller-method call (onion / around advice): it
349
+ * runs code before calling `next()`, awaits the result, and may transform or
350
+ * replace it — the returned value becomes the new result flowing into response
351
+ * handling. Interceptors are Promise-based (not Observable) and resolved from
352
+ * the DI container, so they may inject services (loggers, metrics, mappers).
353
+ */
354
+
355
+ /**
356
+ * Interface for class-based interceptors with dependency injection support.
357
+ *
358
+ * `intercept` receives the request {@link Context} and a `next` callback that
359
+ * invokes the rest of the chain (inner interceptors, ultimately the controller
360
+ * method) and resolves to its result. Call `next()` to proceed; the value you
361
+ * return becomes the result — return `next()`'s value unchanged to pass through,
362
+ * or return a different value to transform the response. Wrap `next()` in
363
+ * try/catch to observe or recover from handler errors; rethrow to propagate.
364
+ *
365
+ * @example
366
+ * ```typescript
367
+ * import { Service } from '@nextrush/di';
368
+ * import type { Interceptor } from 'nextrush/class';
369
+ * import type { Context } from '@nextrush/types';
370
+ *
371
+ * @Service()
372
+ * class WrapInterceptor implements Interceptor {
373
+ * async intercept(ctx: Context, next: () => Promise<unknown>): Promise<unknown> {
374
+ * const data = await next();
375
+ * return { data, timestamp: Date.now() };
376
+ * }
377
+ * }
378
+ * ```
379
+ */
380
+ interface Interceptor {
381
+ intercept(ctx: Context, next: () => Promise<unknown>): Promise<unknown>;
382
+ }
383
+ /**
384
+ * Constructor type for a class-based interceptor.
385
+ * Accepted by {@link UseInterceptor}; resolved from the DI container per request.
386
+ */
387
+ type InterceptorClass = Constructor<Interceptor>;
388
+ /**
389
+ * Interceptor metadata stored by the @UseInterceptor decorator.
390
+ */
391
+ interface InterceptorMetadata {
392
+ /** Interceptor classes applied at this target */
393
+ readonly interceptors: InterceptorClass[];
394
+ /** Whether this is a class or method level interceptor */
395
+ readonly target: 'class' | 'method';
396
+ /** Method name (only for method-level interceptors) */
397
+ readonly methodName?: string | symbol;
398
+ }
399
+
400
+ /**
401
+ * @nextrush/decorators - Service Lifecycle Hook Type Definitions
402
+ *
403
+ * Two duck-typed behavioral interfaces — `OnInit` and `OnShutdown` — that a
404
+ * `@Service`/`@Repository`/`@Config` (or any DI-managed instance) may implement
405
+ * to participate in the application lifecycle. There is intentionally **no
406
+ * decorator**: a service opts in purely by declaring the method, and the
407
+ * controllers registrar detects it by presence via the guards below.
408
+ *
409
+ * Unlike {@link isGuardClass} (which inspects a class *constructor*'s prototype),
410
+ * these guards operate on resolved *instances*, because the registrar has
411
+ * already resolved each service from the container before deciding whether it
412
+ * takes part in the lifecycle.
413
+ *
414
+ * @see `@nextrush/controllers` `registerControllers` — bridges these hooks into
415
+ * `app.ready()` (calls `onInit`) and `app.close()` (calls `onShutdown`).
416
+ */
417
+ /**
418
+ * Implemented by a service that needs to run initialization logic once, when the
419
+ * application boots (`app.ready()`), after all controllers and their service
420
+ * graph have been registered and resolved.
421
+ *
422
+ * `onInit` runs in dependency order — a service's dependencies initialize before
423
+ * the service that depends on them (a reverse-BFS approximation of the graph).
424
+ * An async `onInit` is awaited, so boot does not complete until every hook has
425
+ * settled. Registration must happen before `serve()`/`ready()`.
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * import { Service } from '@nextrush/di';
430
+ * import type { OnInit } from 'nextrush/class';
431
+ *
432
+ * @Service()
433
+ * class Database implements OnInit {
434
+ * async onInit(): Promise<void> {
435
+ * await this.pool.connect();
436
+ * }
437
+ * }
438
+ * ```
439
+ */
440
+ interface OnInit {
441
+ onInit(): void | Promise<void>;
442
+ }
443
+ /**
444
+ * Implemented by a service that needs to release resources when the application
445
+ * shuts down (`app.close()`).
446
+ *
447
+ * `onShutdown` runs in the **reverse** of the `onInit` order (dependents tear
448
+ * down before their dependencies), and an async `onShutdown` is awaited.
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * import { Service } from '@nextrush/di';
453
+ * import type { OnShutdown } from 'nextrush/class';
454
+ *
455
+ * @Service()
456
+ * class Database implements OnShutdown {
457
+ * async onShutdown(): Promise<void> {
458
+ * await this.pool.end();
459
+ * }
460
+ * }
461
+ * ```
462
+ */
463
+ interface OnShutdown {
464
+ onShutdown(): void | Promise<void>;
465
+ }
466
+ /**
467
+ * Narrow an arbitrary value to {@link OnInit} by detecting a callable `onInit`
468
+ * member. Traverses the prototype chain, so both object literals and class
469
+ * instances are detected. Returns `false` for `null`, non-objects, and values
470
+ * whose `onInit` is not a function.
471
+ */
472
+ declare function isOnInit(value: unknown): value is OnInit;
473
+ /**
474
+ * Narrow an arbitrary value to {@link OnShutdown} by detecting a callable
475
+ * `onShutdown` member. Same semantics as {@link isOnInit}.
476
+ */
477
+ declare function isOnShutdown(value: unknown): value is OnShutdown;
478
+
479
+ /**
480
+ * @nextrush/decorators - Metadata Keys & Runtime Helpers
481
+ *
482
+ * The reflect-metadata storage keys plus the runtime type-guard helpers that
483
+ * back the decorator implementations. These are the only runtime values in the
484
+ * type layer — everything else in the sibling *-types modules is type-only.
485
+ */
486
+
487
+ /**
488
+ * Metadata keys used for decorator storage
489
+ */
490
+ declare const DECORATOR_METADATA_KEYS: {
491
+ readonly CONTROLLER: symbol;
492
+ readonly MODULE: symbol;
493
+ readonly ROUTES: symbol;
494
+ readonly PARAMS: symbol;
495
+ readonly MIDDLEWARE: symbol;
496
+ readonly GUARDS: symbol;
497
+ readonly INTERCEPTORS: symbol;
498
+ readonly FILTERS: symbol;
499
+ readonly CATCH: symbol;
500
+ readonly RESPONSE_HEADERS: symbol;
501
+ readonly REDIRECT: symbol;
502
+ readonly HTTP_CODE: symbol;
503
+ };
504
+ /**
505
+ * Type guard to check if a value is a valid HTTP method (decorator-metadata
506
+ * sense — includes `'ALL'`, the `@All()` any-method sentinel; T016).
507
+ */
508
+ declare function isValidHttpMethod(method: string): method is RouteMethods;
509
+ /**
510
+ * Type guard to check if a value is a valid param source
511
+ */
512
+ declare function isValidParamSource(source: string): source is ParamSource;
513
+ /**
514
+ * Type guard to check if a guard is a class (constructor) rather than a function.
515
+ *
516
+ * This checks if the guard has a prototype with the canActivate method defined,
517
+ * which indicates it's a class implementing CanActivate rather than a function.
518
+ */
519
+ declare function isGuardClass(guard: Guard): guard is Constructor<CanActivate>;
520
+
521
+ /**
522
+ * @nextrush/decorators - Class Decorators
523
+ *
524
+ * Controller decorator that marks a class as an HTTP controller.
525
+ * Makes the class injectable for DI via @nextrush/di abstraction.
526
+ * Lifecycle management (singleton/transient) is deferred to the
527
+ * controllers plugin registry, enabling proper test isolation.
528
+ * Uses legacy decorators for compatibility with parameter decorators.
529
+ */
530
+
531
+ /**
532
+ * Marks a class as an HTTP controller with DI support.
533
+ *
534
+ * This decorator:
535
+ * 1. Registers the class as an HTTP controller with route metadata
536
+ * 2. Makes the class injectable (resolvable by the DI container)
537
+ *
538
+ * Lifecycle is managed by the controllers plugin, not the decorator.
539
+ * You do NOT need to add @Service() when using @Controller() - it's included!
540
+ *
541
+ * @param pathOrOptions - Base path string or controller options
542
+ * @returns Class decorator
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * // Simple path - DI is automatic!
547
+ * @Controller('/users')
548
+ * class UserController {
549
+ * constructor(private userService: UserService) {} // Auto-injected
550
+ * }
551
+ *
552
+ * // With options
553
+ * @Controller({ path: '/users', version: 'v1' })
554
+ * class UserController { }
555
+ *
556
+ * // Default path (uses class name)
557
+ * @Controller()
558
+ * class UserController { } // → '/user'
559
+ * ```
560
+ */
561
+ declare function Controller(pathOrOptions?: string | ControllerOptions): ClassDecorator;
562
+
563
+ /**
564
+ * @nextrush/decorators - Module Type Definitions
565
+ *
566
+ * Metadata and options shapes for the @Module decorator. A module groups a
567
+ * feature's imports, controllers, and providers behind one registration entry
568
+ * point. `exports` is captured for future per-module encapsulation (see
569
+ * RFC-NEXTRUSH-MODULES §5) and is not enforced today.
570
+ */
571
+
572
+ /**
573
+ * A provider config: register `provide` using one of `useClass` / `useValue` /
574
+ * `useFactory`. Exactly one of the three `use*` forms should be set.
575
+ *
576
+ * - `useClass` — construct the given class (DI-injected).
577
+ * - `useValue` — bind a constant value (scope is ignored).
578
+ * - `useFactory` — call the factory; `inject` lists tokens resolved and passed
579
+ * to it as arguments (in order).
580
+ *
581
+ * `scope` defaults to `'singleton'` for class/factory providers.
582
+ */
583
+ interface ModuleProviderConfig {
584
+ /** Token the provider is registered under (class, string, or symbol). */
585
+ provide: Token;
586
+ /** Construct this class to satisfy the token. */
587
+ useClass?: Constructor$1;
588
+ /** Bind this constant value to the token. */
589
+ useValue?: unknown;
590
+ /** Call this factory to produce the value. */
591
+ useFactory?: (...args: unknown[]) => unknown;
592
+ /** Tokens resolved and passed (in order) as arguments to `useFactory`. */
593
+ inject?: Token[];
594
+ /** Lifecycle scope. Defaults to `'singleton'` for class/factory providers. */
595
+ scope?: Scope;
596
+ }
597
+ /**
598
+ * A module provider is either a bare class constructor (registered with its
599
+ * declared `@Service` scope, or `singleton` if undecorated) or a full provider
600
+ * config.
601
+ */
602
+ type ModuleProvider = Function | ModuleProviderConfig;
603
+ /**
604
+ * Options for the @Module decorator.
605
+ */
606
+ interface ModuleOptions {
607
+ /** Other `@Module` classes this module composes. */
608
+ imports?: Function[];
609
+ /** `@Controller` classes owned by this module. */
610
+ controllers?: Function[];
611
+ /** Providers (services/values/factories) this module registers. */
612
+ providers?: ModuleProvider[];
613
+ /**
614
+ * Providers this module makes visible to importers. Recorded now for future
615
+ * per-module encapsulation; not enforced yet (see RFC-NEXTRUSH-MODULES §5).
616
+ */
617
+ exports?: Function[];
618
+ }
619
+ /**
620
+ * Normalized module metadata stored by @Module. Every field is defaulted to an
621
+ * empty array so readers never return `undefined` collections.
622
+ */
623
+ interface ModuleMetadata {
624
+ readonly imports: Function[];
625
+ readonly controllers: Function[];
626
+ readonly providers: ModuleProvider[];
627
+ readonly exports: Function[];
628
+ }
629
+
630
+ /**
631
+ * @nextrush/decorators - Module Decorator
632
+ *
633
+ * `@Module` records a feature's composition — its imported modules, controllers,
634
+ * providers, and exports — as reflect-metadata. It is a grouping/composition
635
+ * unit; the `@nextrush/controllers` `registerModule` registrar reads this
636
+ * metadata to wire the whole module graph in one call.
637
+ *
638
+ * This layer stores metadata only. Provider registration, route building, and
639
+ * (future) encapsulation live in the controllers layer — see
640
+ * RFC-NEXTRUSH-MODULES.
641
+ */
642
+
643
+ /**
644
+ * Marks a class as a NextRush module.
645
+ *
646
+ * @param options - The module's imports, controllers, providers, and exports.
647
+ * @returns Class decorator
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * @Module({
652
+ * imports: [BillingModule],
653
+ * controllers: [UserController],
654
+ * providers: [UserService, { provide: 'CONFIG', useValue: cfg }],
655
+ * exports: [UserService],
656
+ * })
657
+ * class UserModule {}
658
+ * ```
659
+ */
660
+ declare function Module(options?: ModuleOptions): ClassDecorator;
661
+ /**
662
+ * Check if a class carries `@Module` metadata.
663
+ */
664
+ declare function isModule(target: Function): boolean;
665
+ /**
666
+ * Read a module's metadata. Returns a defensive copy (fresh arrays) so callers
667
+ * cannot mutate the stored record. Returns `undefined` when `target` is not a
668
+ * module.
669
+ */
670
+ declare function getModuleMetadata(target: Function): ModuleMetadata | undefined;
671
+
672
+ /**
673
+ * @nextrush/decorators - @HttpCode Decorator
674
+ *
675
+ * Sets the HTTP status code returned when a controller method resolves with a
676
+ * value. Lives in its own module because `routes.ts` is already at the
677
+ * file-size ceiling.
678
+ */
679
+ /**
680
+ * Set the HTTP status code for the response when the decorated method returns.
681
+ *
682
+ * Takes precedence over the route decorator's `statusCode` option (e.g.
683
+ * `@Post('/x', { statusCode: 200 })`) when both are present. Does not affect
684
+ * responses produced by a thrown `HttpError` (those keep the error's status)
685
+ * or by `@Redirect` (the redirect status wins).
686
+ *
687
+ * @param statusCode - HTTP status code to apply (e.g. 201, 202, 204)
688
+ *
689
+ * @example
690
+ * ```typescript
691
+ * @Controller('/users')
692
+ * class UserController {
693
+ * @Post()
694
+ * @HttpCode(201)
695
+ * create(@Body() data: CreateUserDto) {
696
+ * return this.users.create(data); // → 201 Created
697
+ * }
698
+ * }
699
+ * ```
700
+ */
701
+ declare function HttpCode(statusCode: number): MethodDecorator;
702
+
703
+ /**
704
+ * @nextrush/decorators - Response Decorators
705
+ *
706
+ * Method decorators that shape the HTTP response: @SetHeader attaches response
707
+ * headers and @Redirect declares a redirect. Stored as reflect-metadata read by
708
+ * the controllers handler builder.
709
+ */
710
+ /**
711
+ * Set a response header on the decorated method.
712
+ *
713
+ * Multiple `@SetHeader()` decorators can be stacked on the same method.
714
+ *
715
+ * @param name - Header name (e.g., 'Cache-Control')
716
+ * @param value - Header value (e.g., 'no-cache')
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * @Controller('/files')
721
+ * class FileController {
722
+ * @Get('/:id')
723
+ * @SetHeader('Cache-Control', 'max-age=3600')
724
+ * @SetHeader('X-Custom', 'value')
725
+ * getFile(@Param('id') id: string) {
726
+ * return { id };
727
+ * }
728
+ * }
729
+ * ```
730
+ */
731
+ declare function SetHeader(name: string, value: string): MethodDecorator;
732
+ /**
733
+ * Redirect the response when the decorated method is called.
734
+ *
735
+ * If the method returns a string, it overrides the decorator's URL.
736
+ * If the method returns an object with `url` and/or `statusCode`, those override as well.
737
+ *
738
+ * @param url - Default redirect URL
739
+ * @param statusCode - HTTP status code (default: 302)
740
+ *
741
+ * @example
742
+ * ```typescript
743
+ * @Controller('/legacy')
744
+ * class LegacyController {
745
+ * @Get('/old-page')
746
+ * @Redirect('/new-page', 301)
747
+ * redirectOld() {
748
+ * // Optional: return a string to override the URL
749
+ * }
750
+ *
751
+ * @Get('/dynamic')
752
+ * @Redirect('/fallback')
753
+ * dynamicRedirect() {
754
+ * // Return a string to redirect elsewhere
755
+ * return '/actual-destination';
756
+ * }
757
+ * }
758
+ * ```
759
+ */
760
+ declare function Redirect(url: string, statusCode?: number): MethodDecorator;
761
+
762
+ /**
763
+ * @nextrush/decorators - Route Decorators
764
+ *
765
+ * HTTP method decorators for controller methods.
766
+ * Uses legacy decorators for compatibility with parameter decorators.
767
+ */
768
+
769
+ /**
770
+ * @Get decorator - Marks a method as handling HTTP GET requests.
771
+ *
772
+ * @example
773
+ * ```typescript
774
+ * @Controller('/users')
775
+ * class UserController {
776
+ * @Get()
777
+ * findAll() { }
778
+ *
779
+ * @Get('/:id')
780
+ * findOne(@Param('id') id: string) { }
781
+ *
782
+ * @Get('/search', { description: 'Search users' })
783
+ * search(@Query('q') query: string) { }
784
+ * }
785
+ * ```
786
+ */
787
+ declare const Get: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
788
+ /**
789
+ * @Post decorator - Marks a method as handling HTTP POST requests.
790
+ *
791
+ * @example
792
+ * ```typescript
793
+ * @Controller('/users')
794
+ * class UserController {
795
+ * @Post()
796
+ * create(@Body() data: CreateUserDto) { }
797
+ *
798
+ * @Post('/bulk', { statusCode: 201 })
799
+ * createMany(@Body() users: CreateUserDto[]) { }
800
+ * }
801
+ * ```
802
+ */
803
+ declare const Post: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
804
+ /**
805
+ * @Put decorator - Marks a method as handling HTTP PUT requests.
806
+ *
807
+ * @example
808
+ * ```typescript
809
+ * @Controller('/users')
810
+ * class UserController {
811
+ * @Put('/:id')
812
+ * update(@Param('id') id: string, @Body() data: UpdateUserDto) { }
813
+ * }
814
+ * ```
815
+ */
816
+ declare const Put: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
817
+ /**
818
+ * @Delete decorator - Marks a method as handling HTTP DELETE requests.
819
+ *
820
+ * @example
821
+ * ```typescript
822
+ * @Controller('/users')
823
+ * class UserController {
824
+ * @Delete('/:id')
825
+ * remove(@Param('id') id: string) { }
826
+ * }
827
+ * ```
828
+ */
829
+ declare const Delete: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
830
+ /**
831
+ * @Patch decorator - Marks a method as handling HTTP PATCH requests.
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * @Controller('/users')
836
+ * class UserController {
837
+ * @Patch('/:id')
838
+ * partialUpdate(@Param('id') id: string, @Body() data: Partial<User>) { }
839
+ * }
840
+ * ```
841
+ */
842
+ declare const Patch: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
843
+ /**
844
+ * @Head decorator - Marks a method as handling HTTP HEAD requests.
845
+ *
846
+ * @example
847
+ * ```typescript
848
+ * @Controller('/files')
849
+ * class FileController {
850
+ * @Head('/:id')
851
+ * checkExists(@Param('id') id: string) { }
852
+ * }
853
+ * ```
854
+ */
855
+ declare const Head: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
856
+ /**
857
+ * @Options decorator - Marks a method as handling HTTP OPTIONS requests.
858
+ *
859
+ * @example
860
+ * ```typescript
861
+ * @Controller('/api')
862
+ * class ApiController {
863
+ * @Options()
864
+ * cors() { }
865
+ * }
866
+ * ```
867
+ */
868
+ declare const Options: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
869
+ /**
870
+ * @All decorator - Marks a method as handling all HTTP methods.
871
+ * Registers a single any-method route entry (T016) — matched by every
872
+ * standard HTTP method via the router's own `Router.all()`/`GroupRouter.all()`
873
+ * ANY-method registration, rather than one explicit RouteMetadata entry per
874
+ * enumerated method. `getRoutes()`/route introspection sees one row for an
875
+ * `@All()` route, consistent with how it was actually authored.
876
+ *
877
+ * @example
878
+ * ```typescript
879
+ * @Controller('/proxy')
880
+ * class ProxyController {
881
+ * @All('/*')
882
+ * handle(@Ctx() ctx: Context) { }
883
+ * }
884
+ * ```
885
+ */
886
+ declare const All: (pathOrOptions?: string | RouteOptions, options?: RouteOptions) => MethodDecorator;
887
+
888
+ /**
889
+ * @nextrush/decorators - Standard Parameter Decorators
890
+ *
891
+ * Parameter decorators for injecting request data into controller method parameters.
892
+ * Uses legacy decorators (parameter decorators not supported in Stage 3).
893
+ */
894
+
895
+ /**
896
+ * @Body decorator - Injects the request body into the parameter.
897
+ *
898
+ * @example
899
+ * ```typescript
900
+ * @Controller('/users')
901
+ * class UserController {
902
+ * // Inject entire body
903
+ * @Post()
904
+ * create(@Body() data: CreateUserDto) { }
905
+ *
906
+ * // Inject specific property from body
907
+ * @Post('/email')
908
+ * updateEmail(@Body('email') email: string) { }
909
+ *
910
+ * // With transform
911
+ * @Post()
912
+ * create(@Body({ transform: validateCreateUser }) data: CreateUserDto) { }
913
+ * }
914
+ * ```
915
+ */
916
+ declare const Body: {
917
+ (): ParameterDecorator;
918
+ (property: string): ParameterDecorator;
919
+ (options: BodyOptions): ParameterDecorator;
920
+ (property: string, options: BodyOptions): ParameterDecorator;
921
+ };
922
+ /**
923
+ * @Param decorator - Injects route parameters into the parameter.
924
+ *
925
+ * @example
926
+ * ```typescript
927
+ * @Controller('/users')
928
+ * class UserController {
929
+ * // Inject all params
930
+ * @Get('/:id')
931
+ * findOne(@Param() params: { id: string }) { }
932
+ *
933
+ * // Inject specific param
934
+ * @Get('/:id')
935
+ * findOne(@Param('id') id: string) { }
936
+ *
937
+ * // With transform (e.g., parse to number)
938
+ * @Get('/:id')
939
+ * findOne(@Param('id', { transform: Number }) id: number) { }
940
+ * }
941
+ * ```
942
+ */
943
+ declare const Param: {
944
+ (): ParameterDecorator;
945
+ (name: string): ParameterDecorator;
946
+ (options: ParamOptions): ParameterDecorator;
947
+ (name: string, options: ParamOptions): ParameterDecorator;
948
+ };
949
+ /**
950
+ * @Query decorator - Injects query parameters into the parameter.
951
+ *
952
+ * @example
953
+ * ```typescript
954
+ * @Controller('/users')
955
+ * class UserController {
956
+ * // Inject all query params
957
+ * @Get()
958
+ * findAll(@Query() query: { page?: number; limit?: number }) { }
959
+ *
960
+ * // Inject specific query param
961
+ * @Get()
962
+ * findAll(@Query('page') page: string) { }
963
+ *
964
+ * // With default value
965
+ * @Get()
966
+ * findAll(@Query('limit', { defaultValue: 10, transform: Number }) limit: number) { }
967
+ * }
968
+ * ```
969
+ */
970
+ declare const Query: {
971
+ (): ParameterDecorator;
972
+ (name: string): ParameterDecorator;
973
+ (options: QueryOptions): ParameterDecorator;
974
+ (name: string, options: QueryOptions): ParameterDecorator;
975
+ };
976
+ /**
977
+ * @Header decorator - Injects request headers into the parameter.
978
+ *
979
+ * @example
980
+ * ```typescript
981
+ * @Controller('/api')
982
+ * class ApiController {
983
+ * // Inject all headers
984
+ * @Get()
985
+ * handle(@Header() headers: Record<string, string>) { }
986
+ *
987
+ * // Inject specific header
988
+ * @Get()
989
+ * handle(@Header('authorization') auth: string) { }
990
+ *
991
+ * // With default value
992
+ * @Get()
993
+ * handle(@Header('x-api-version', { defaultValue: 'v1' }) version: string) { }
994
+ * }
995
+ * ```
996
+ */
997
+ declare const Header: {
998
+ (): ParameterDecorator;
999
+ (name: string): ParameterDecorator;
1000
+ (options: HeaderOptions): ParameterDecorator;
1001
+ (name: string, options: HeaderOptions): ParameterDecorator;
1002
+ };
1003
+ /**
1004
+ * @Ctx decorator - Injects the full NextRush Context object.
1005
+ *
1006
+ * @example
1007
+ * ```typescript
1008
+ * @Controller('/users')
1009
+ * class UserController {
1010
+ * @Get('/:id')
1011
+ * findOne(@Ctx() ctx: Context) {
1012
+ * const id = ctx.params.id;
1013
+ * ctx.json({ id });
1014
+ * }
1015
+ * }
1016
+ * ```
1017
+ */
1018
+ declare function Ctx(): ParameterDecorator;
1019
+ /**
1020
+ * @Req decorator - Injects the raw request object (adapter-specific).
1021
+ *
1022
+ * @example
1023
+ * ```typescript
1024
+ * @Controller('/files')
1025
+ * class FileController {
1026
+ * @Post('/upload')
1027
+ * upload(@Req() req: IncomingMessage) {
1028
+ * // Access raw Node.js request for streaming
1029
+ * }
1030
+ * }
1031
+ * ```
1032
+ */
1033
+ declare function Req(): ParameterDecorator;
1034
+ /**
1035
+ * @Res decorator - Injects the raw response object (adapter-specific).
1036
+ *
1037
+ * @example
1038
+ * ```typescript
1039
+ * @Controller('/files')
1040
+ * class FileController {
1041
+ * @Get('/download/:id')
1042
+ * download(@Res() res: ServerResponse) {
1043
+ * // Access raw Node.js response for streaming
1044
+ * }
1045
+ * }
1046
+ * ```
1047
+ */
1048
+ declare function Res(): ParameterDecorator;
1049
+
1050
+ /**
1051
+ * @nextrush/decorators - Custom Parameter Decorator Factory
1052
+ *
1053
+ * User-defined parameter extractors for custom injection patterns.
1054
+ */
1055
+
1056
+ /**
1057
+ * Create a custom parameter decorator with a user-defined extraction function.
1058
+ *
1059
+ * The extractor receives the request context and returns the value to inject
1060
+ * into the handler parameter. Supports both sync and async extractors.
1061
+ *
1062
+ * @param extractor - Function that extracts the parameter value from context
1063
+ * @param options - Optional transform and required settings
1064
+ *
1065
+ * @example
1066
+ * ```typescript
1067
+ * // Extract the authenticated user from state
1068
+ * const CurrentUser = createCustomParamDecorator(
1069
+ * (ctx) => ctx.state.user
1070
+ * );
1071
+ *
1072
+ * // Extract a specific cookie
1073
+ * const Cookie = (name: string) => createCustomParamDecorator(
1074
+ * (ctx) => ctx.get('cookie')?.split(';')
1075
+ * .find(c => c.trim().startsWith(name + '='))
1076
+ * ?.split('=')[1]
1077
+ * );
1078
+ *
1079
+ * @Controller('/users')
1080
+ * class UserController {
1081
+ * @Get('/me')
1082
+ * getProfile(@CurrentUser user: User) {
1083
+ * return user;
1084
+ * }
1085
+ * }
1086
+ * ```
1087
+ */
1088
+ declare function createCustomParamDecorator(extractor: CustomParamExtractor, options?: {
1089
+ transform?: TransformFn;
1090
+ required?: boolean;
1091
+ }): ParameterDecorator;
1092
+
1093
+ /**
1094
+ * @nextrush/decorators - Guard Decorators
1095
+ *
1096
+ * Guards are functions or classes that determine if a request should be handled.
1097
+ * They run BEFORE the route handler and can prevent execution.
1098
+ *
1099
+ * Use guards for:
1100
+ * - Authentication checks
1101
+ * - Authorization/permission checks
1102
+ * - Rate limiting
1103
+ * - Feature flags
1104
+ */
1105
+
1106
+ /**
1107
+ * Apply guards to a controller or route.
1108
+ *
1109
+ * Guards run in order and must all pass for the request to proceed.
1110
+ * If any guard returns false or throws, the request is rejected.
1111
+ *
1112
+ * Supports both function-based and class-based guards:
1113
+ * - Function guards: Simple functions that receive GuardContext
1114
+ * - Class guards: Classes implementing CanActivate interface (resolved from DI)
1115
+ *
1116
+ * @param guards - Guard functions or classes to apply
1117
+ *
1118
+ * @example Controller-level guard (applies to all routes)
1119
+ * ```typescript
1120
+ * @UseGuard(AuthGuard)
1121
+ * @Controller('/users')
1122
+ * class UserController {
1123
+ * @Get()
1124
+ * findAll() { } // Protected by AuthGuard
1125
+ * }
1126
+ * ```
1127
+ *
1128
+ * @example Route-level guard (applies to specific route)
1129
+ * ```typescript
1130
+ * @Controller('/users')
1131
+ * class UserController {
1132
+ * @Get()
1133
+ * findAll() { } // Public
1134
+ *
1135
+ * @UseGuard(AdminGuard)
1136
+ * @Delete('/:id')
1137
+ * remove(@Param('id') id: string) { } // Admin only
1138
+ * }
1139
+ * ```
1140
+ *
1141
+ * @example Multiple guards (all must pass)
1142
+ * ```typescript
1143
+ * @UseGuard(AuthGuard, RoleGuard('admin'), RateLimitGuard)
1144
+ * @Controller('/admin')
1145
+ * class AdminController { }
1146
+ * ```
1147
+ *
1148
+ * @example Function-based guard
1149
+ * ```typescript
1150
+ * const AuthGuard: GuardFn = async (ctx) => {
1151
+ * const token = ctx.get('authorization');
1152
+ * if (!token) return false; // Reject
1153
+ *
1154
+ * const user = await verifyToken(token);
1155
+ * ctx.state.user = user; // Attach user to context
1156
+ * return true; // Allow
1157
+ * };
1158
+ * ```
1159
+ *
1160
+ * @example Guard factory for dynamic configuration
1161
+ * ```typescript
1162
+ * const RoleGuard = (role: string): GuardFn => async (ctx) => {
1163
+ * return ctx.state.user?.role === role;
1164
+ * };
1165
+ * ```
1166
+ *
1167
+ * @example Class-based guard with DI
1168
+ * ```typescript
1169
+ * import { Service } from '@nextrush/di';
1170
+ * import type { CanActivate, GuardContext } from 'nextrush/class';
1171
+ *
1172
+ * @Service()
1173
+ * class AuthGuard implements CanActivate {
1174
+ * constructor(private authService: AuthService) {}
1175
+ *
1176
+ * async canActivate(ctx: GuardContext): Promise<boolean> {
1177
+ * const token = ctx.get('authorization');
1178
+ * if (!token) return false;
1179
+ *
1180
+ * const user = await this.authService.verify(token);
1181
+ * ctx.state.user = user;
1182
+ * return Boolean(user);
1183
+ * }
1184
+ * }
1185
+ *
1186
+ * // Usage - class guard is resolved from DI container
1187
+ * @UseGuard(AuthGuard)
1188
+ * @Controller('/protected')
1189
+ * class ProtectedController { }
1190
+ * ```
1191
+ */
1192
+ declare function UseGuard(...guards: Guard[]): ClassDecorator & MethodDecorator;
1193
+ /**
1194
+ * Get all guards for a controller class.
1195
+ *
1196
+ * Guards are returned in bottom-to-top decorator application order,
1197
+ * matching TypeScript's native decorator execution semantics.
1198
+ *
1199
+ * @param target - Controller class
1200
+ * @returns Array of guards (functions or class constructors)
1201
+ */
1202
+ declare function getClassGuards(target: Function): Guard[];
1203
+ /**
1204
+ * Get guards for a specific method.
1205
+ *
1206
+ * Guards are returned in bottom-to-top decorator application order.
1207
+ *
1208
+ * @param target - Controller class
1209
+ * @param methodName - Method name
1210
+ * @returns Array of guards (functions or class constructors)
1211
+ */
1212
+ declare function getMethodGuards(target: Function, methodName: string | symbol): Guard[];
1213
+ /**
1214
+ * Get all guards for a route (class + method guards combined).
1215
+ *
1216
+ * Class guards run first, then method guards.
1217
+ *
1218
+ * @param target - Controller class
1219
+ * @param methodName - Method name
1220
+ * @returns Array of guards in execution order
1221
+ */
1222
+ declare function getAllGuards(target: Function, methodName: string | symbol): Guard[];
1223
+
1224
+ /**
1225
+ * @nextrush/decorators - Exception Filter Decorators
1226
+ *
1227
+ * Exception filters localize error handling to a controller or route. A filter
1228
+ * is a class implementing {@link ExceptionFilter}; it declares which errors it
1229
+ * handles with `@Catch(...)` and turns a thrown error into a response.
1230
+ *
1231
+ * Filters are opt-in and non-breaking: a controller/route with no `@UseFilter`
1232
+ * behaves exactly as before — errors propagate to the global error middleware.
1233
+ */
1234
+
1235
+ /**
1236
+ * Declare which error constructors an exception filter handles.
1237
+ *
1238
+ * `@Catch(NotFoundError)` matches `NotFoundError` and its subclasses (via
1239
+ * `instanceof`). `@Catch()` with no arguments is a **catch-all** — it matches
1240
+ * any thrown value. A filter with no `@Catch` at all is also treated as
1241
+ * catch-all.
1242
+ *
1243
+ * @param errorTypes - Error constructors this filter handles (empty = catch-all)
1244
+ *
1245
+ * @example
1246
+ * ```typescript
1247
+ * @Catch(EntityNotFoundError)
1248
+ * class NotFoundFilter implements ExceptionFilter {
1249
+ * catch(error: unknown, ctx: Context) {
1250
+ * ctx.status = 404;
1251
+ * ctx.json({ error: 'Not found' });
1252
+ * }
1253
+ * }
1254
+ * ```
1255
+ */
1256
+ declare function Catch(...errorTypes: Function[]): ClassDecorator;
1257
+ /**
1258
+ * Apply exception filters to a controller or route.
1259
+ *
1260
+ * Works as both a class decorator (covers every route on the controller) and a
1261
+ * method decorator (covers that route only), mirroring {@link UseGuard}.
1262
+ * Method-level filters take precedence over class-level filters; within a
1263
+ * level, the first matching filter wins.
1264
+ *
1265
+ * @param filters - Exception filter classes to apply
1266
+ *
1267
+ * @example Controller-level (applies to all routes)
1268
+ * ```typescript
1269
+ * @UseFilter(DomainErrorFilter)
1270
+ * @Controller('/users')
1271
+ * class UserController {}
1272
+ * ```
1273
+ *
1274
+ * @example Method-level (higher precedence)
1275
+ * ```typescript
1276
+ * @Controller('/users')
1277
+ * class UserController {
1278
+ * @UseFilter(ConflictFilter)
1279
+ * @Post()
1280
+ * create() {}
1281
+ * }
1282
+ * ```
1283
+ */
1284
+ declare function UseFilter(...filters: ExceptionFilterClass[]): ClassDecorator & MethodDecorator;
1285
+ /**
1286
+ * Get the error constructors an exception filter handles.
1287
+ *
1288
+ * @param target - Filter class
1289
+ * @returns Error constructors from `@Catch` (empty array = catch-all)
1290
+ */
1291
+ declare function getCatchTypes(target: Function): Function[];
1292
+ /**
1293
+ * Get all class-level filters for a controller.
1294
+ *
1295
+ * @param target - Controller class
1296
+ * @returns Filter classes in decorator application order
1297
+ */
1298
+ declare function getClassFilters(target: Function): ExceptionFilterClass[];
1299
+ /**
1300
+ * Get method-level filters for a specific route.
1301
+ *
1302
+ * @param target - Controller class
1303
+ * @param methodName - Method name
1304
+ * @returns Filter classes in decorator application order
1305
+ */
1306
+ declare function getMethodFilters(target: Function, methodName: string | symbol): ExceptionFilterClass[];
1307
+ /**
1308
+ * Get all filters applicable to a route, in resolution/precedence order.
1309
+ *
1310
+ * Method-level filters come first (higher precedence), then class-level
1311
+ * filters. The controllers runtime walks this list and invokes the first
1312
+ * filter whose `@Catch` types match the thrown error.
1313
+ *
1314
+ * @param target - Controller class
1315
+ * @param methodName - Method name
1316
+ * @returns Filter classes: method filters first, then class filters
1317
+ */
1318
+ declare function getAllFilters(target: Function, methodName: string | symbol): ExceptionFilterClass[];
1319
+
1320
+ /**
1321
+ * @nextrush/decorators - Interceptor Decorators
1322
+ *
1323
+ * Interceptors wrap the controller-method call (onion / around advice). An
1324
+ * interceptor runs code before calling `next()`, awaits the downstream result,
1325
+ * and may transform or replace it before it flows into response handling.
1326
+ *
1327
+ * Interceptors are opt-in and non-breaking: a controller/route with no
1328
+ * `@UseInterceptor` behaves exactly as before — the method result flows
1329
+ * straight into response handling.
1330
+ *
1331
+ * Use interceptors for:
1332
+ * - Response shaping / envelope wrapping
1333
+ * - Timing, logging, and metrics around the handler
1334
+ * - Caching (short-circuit `next()` and return a cached value)
1335
+ * - Cross-cutting error mapping (try/catch around `next()`)
1336
+ */
1337
+
1338
+ /**
1339
+ * Apply interceptors to a controller or route.
1340
+ *
1341
+ * Works as both a class decorator (wraps every route on the controller) and a
1342
+ * method decorator (wraps that route only), mirroring {@link UseGuard}. Class
1343
+ * interceptors are the outermost layers of the onion; method interceptors are
1344
+ * inner, closest to the handler. Interceptor classes are resolved from the DI
1345
+ * container at request time.
1346
+ *
1347
+ * @param interceptors - Interceptor classes to apply
1348
+ *
1349
+ * @example Controller-level (wraps all routes)
1350
+ * ```typescript
1351
+ * @UseInterceptor(TimingInterceptor)
1352
+ * @Controller('/users')
1353
+ * class UserController {}
1354
+ * ```
1355
+ *
1356
+ * @example Method-level (inner layer, closest to the handler)
1357
+ * ```typescript
1358
+ * @Controller('/users')
1359
+ * class UserController {
1360
+ * @UseInterceptor(CacheInterceptor)
1361
+ * @Get()
1362
+ * findAll() {}
1363
+ * }
1364
+ * ```
1365
+ */
1366
+ declare function UseInterceptor(...interceptors: InterceptorClass[]): ClassDecorator & MethodDecorator;
1367
+ /**
1368
+ * Get all class-level interceptors for a controller.
1369
+ *
1370
+ * Interceptors are returned in bottom-to-top decorator application order,
1371
+ * matching TypeScript's native decorator execution semantics.
1372
+ *
1373
+ * @param target - Controller class
1374
+ * @returns Interceptor classes in decorator application order
1375
+ */
1376
+ declare function getClassInterceptors(target: Function): InterceptorClass[];
1377
+ /**
1378
+ * Get method-level interceptors for a specific route.
1379
+ *
1380
+ * @param target - Controller class
1381
+ * @param methodName - Method name
1382
+ * @returns Interceptor classes in decorator application order
1383
+ */
1384
+ declare function getMethodInterceptors(target: Function, methodName: string | symbol): InterceptorClass[];
1385
+ /**
1386
+ * Get all interceptors applicable to a route, in onion (outer-to-inner) order.
1387
+ *
1388
+ * Class interceptors come first (outermost layers), then method interceptors
1389
+ * (inner, closest to the handler). The controllers runtime builds the chain so
1390
+ * the first entry runs first and returns last.
1391
+ *
1392
+ * @param target - Controller class
1393
+ * @param methodName - Method name
1394
+ * @returns Interceptor classes: class interceptors first, then method
1395
+ */
1396
+ declare function getAllInterceptors(target: Function, methodName: string | symbol): InterceptorClass[];
1397
+
1398
+ /**
1399
+ * @nextrush/decorators - Metadata Readers
1400
+ *
1401
+ * Utility functions to read decorator metadata from controller classes.
1402
+ * Used by @nextrush/controllers' registrar to build routes.
1403
+ */
1404
+
1405
+ /**
1406
+ * Check if a class has @Controller decorator.
1407
+ *
1408
+ * @example
1409
+ * ```typescript
1410
+ * @Controller('/users')
1411
+ * class UserController { }
1412
+ *
1413
+ * isController(UserController); // true
1414
+ * isController(SomeService); // false
1415
+ * ```
1416
+ */
1417
+ declare function isController(target: Function): boolean;
1418
+ /**
1419
+ * Get controller metadata from a class.
1420
+ * Returns undefined if class doesn't have @Controller decorator.
1421
+ *
1422
+ * @example
1423
+ * ```typescript
1424
+ * @Controller('/users')
1425
+ * class UserController { }
1426
+ *
1427
+ * const meta = getControllerMetadata(UserController);
1428
+ * // { path: '/users', version: undefined, middleware: undefined, tags: undefined }
1429
+ * ```
1430
+ */
1431
+ declare function getControllerMetadata(target: Function): ControllerMetadata | undefined;
1432
+ /**
1433
+ * Get all route metadata from a controller class.
1434
+ * Returns empty array if no routes are defined.
1435
+ *
1436
+ * @example
1437
+ * ```typescript
1438
+ * @Controller('/users')
1439
+ * class UserController {
1440
+ * @Get()
1441
+ * findAll() { }
1442
+ *
1443
+ * @Get('/:id')
1444
+ * findOne() { }
1445
+ * }
1446
+ *
1447
+ * const routes = getRouteMetadata(UserController);
1448
+ * // [{ method: 'GET', path: '/', ... }, { method: 'GET', path: '/:id', ... }]
1449
+ * ```
1450
+ */
1451
+ declare function getRouteMetadata(target: Function): ControllerRouteMetadata[];
1452
+ /**
1453
+ * Get parameter metadata for a specific method.
1454
+ * Returns empty array if no parameters have decorators.
1455
+ *
1456
+ * @example
1457
+ * ```typescript
1458
+ * @Controller('/users')
1459
+ * class UserController {
1460
+ * @Get('/:id')
1461
+ * findOne(@Param('id') id: string, @Query('include') include: string) { }
1462
+ * }
1463
+ *
1464
+ * const params = getParamMetadata(UserController, 'findOne');
1465
+ * // [{ source: 'param', index: 0, name: 'id' }, { source: 'query', index: 1, name: 'include' }]
1466
+ * ```
1467
+ */
1468
+ declare function getParamMetadata(target: Function, methodName: string | symbol): ParamMetadata[];
1469
+ /**
1470
+ * Get all parameter metadata for all methods in a controller.
1471
+ * Returns a Map where keys are method names.
1472
+ *
1473
+ * @example
1474
+ * ```typescript
1475
+ * const allParams = getAllParamMetadata(UserController);
1476
+ * // Map { 'findOne' => [...], 'create' => [...] }
1477
+ * ```
1478
+ */
1479
+ declare function getAllParamMetadata(target: Function): Map<string, ParamMetadata[]>;
1480
+ /**
1481
+ * Get full controller definition including metadata, routes, and params.
1482
+ * Returns undefined if class is not a controller.
1483
+ *
1484
+ * @example
1485
+ * ```typescript
1486
+ * const def = getControllerDefinition(UserController);
1487
+ * // {
1488
+ * // controller: { path: '/users', ... },
1489
+ * // routes: [{ method: 'GET', path: '/', ... }],
1490
+ * // params: Map { 'findOne' => [...] }
1491
+ * // }
1492
+ * ```
1493
+ */
1494
+ declare function getControllerDefinition(target: Function): ControllerDefinition | undefined;
1495
+ /**
1496
+ * Full controller definition with all metadata
1497
+ */
1498
+ interface ControllerDefinition {
1499
+ /** Controller class constructor */
1500
+ readonly target: Function;
1501
+ /** Controller-level metadata */
1502
+ readonly controller: ControllerMetadata;
1503
+ /** All route metadata */
1504
+ readonly routes: ControllerRouteMetadata[];
1505
+ /** Parameter metadata keyed by method name */
1506
+ readonly params: Map<string, ParamMetadata[]>;
1507
+ }
1508
+ /**
1509
+ * Get response headers metadata for a controller method.
1510
+ *
1511
+ * Returns the list of `@SetHeader()` entries for the given method,
1512
+ * or an empty array if none are defined.
1513
+ */
1514
+ declare function getResponseHeaders(target: Function, methodName: string): ResponseHeaderMetadata[];
1515
+ /**
1516
+ * Get redirect metadata for a controller method.
1517
+ *
1518
+ * Returns the `@Redirect()` configuration for the given method,
1519
+ * or `undefined` if not decorated.
1520
+ */
1521
+ declare function getRedirectMetadata(target: Function, methodName: string): RedirectMetadata | undefined;
1522
+ /**
1523
+ * Get the `@HttpCode()` status code for a controller method.
1524
+ *
1525
+ * Returns the status code stored by `@HttpCode(code)`, or `undefined` if the
1526
+ * method is not decorated.
1527
+ */
1528
+ declare function getHttpCode(target: Function, methodName: string): number | undefined;
1529
+
1530
+ /**
1531
+ * @nextrush/decorators - Reflection API Isolation
1532
+ *
1533
+ * Single point of contact for all Reflect.getMetadata, Reflect.defineMetadata,
1534
+ * and design:paramtypes reads. Isolates reflection plumbing from business logic.
1535
+ */
1536
+ /**
1537
+ * Read the constructor parameter types emitted by TypeScript's `emitDecoratorMetadata`.
1538
+ * Returns an empty array if metadata is not present (e.g., under esbuild/tsx without
1539
+ * the metadata plugin).
1540
+ *
1541
+ * This is the ONLY place in the package that reads `design:paramtypes` directly.
1542
+ * All other code requests parameter types through this helper.
1543
+ *
1544
+ * @internal For cross-package DI use, re-export from index.ts as getConstructorParamTypes.
1545
+ */
1546
+ declare function getConstructorParamTypes(target: Function): unknown[];
1547
+
1548
+ /**
1549
+ * @nextrush/controllers - Error Classes
1550
+ *
1551
+ * Production-grade error classes with actionable messages.
1552
+ * Client errors (4xx) extend HttpError for proper status codes.
1553
+ */
1554
+
1555
+ /**
1556
+ * Base error class for controller-related server errors.
1557
+ * These are 500-level errors that indicate server-side issues.
1558
+ *
1559
+ * Note: We use `declare` for name/message to help TypeScript's declaration
1560
+ * emitter recognize that these are inherited from Error via @nextrush/errors.
1561
+ */
1562
+ declare class ControllerError extends InternalServerError {
1563
+ name: string;
1564
+ message: string;
1565
+ constructor(message: string, code: string, options?: HttpErrorOptions);
1566
+ }
1567
+ /**
1568
+ * Error thrown when a class is not a valid controller.
1569
+ * This is a server configuration error (500).
1570
+ */
1571
+ declare class NotAControllerError extends ControllerError {
1572
+ constructor(className: string);
1573
+ }
1574
+ /**
1575
+ * Error thrown when controller has no routes defined.
1576
+ * This is a server configuration error (500).
1577
+ */
1578
+ declare class NoRoutesError extends ControllerError {
1579
+ constructor(className: string);
1580
+ }
1581
+ /**
1582
+ * Error thrown when file discovery fails.
1583
+ * This is a server configuration error (500).
1584
+ */
1585
+ declare class DiscoveryError extends ControllerError {
1586
+ readonly filePath: string;
1587
+ constructor(filePath: string, reason: string, cause?: Error);
1588
+ }
1589
+ /**
1590
+ * Error thrown when DI resolution fails for a controller.
1591
+ * This is a server configuration error (500).
1592
+ */
1593
+ declare class ControllerResolutionError extends ControllerError {
1594
+ readonly controllerName: string;
1595
+ constructor(controllerName: string, cause?: Error);
1596
+ }
1597
+ /**
1598
+ * Error thrown when parameter injection fails.
1599
+ * This is a CLIENT error (400) - the request is malformed.
1600
+ */
1601
+ declare class ParameterInjectionError extends BadRequestError {
1602
+ name: string;
1603
+ message: string;
1604
+ readonly controllerName: string;
1605
+ readonly methodName: string;
1606
+ readonly paramIndex: number;
1607
+ constructor(controllerName: string, methodName: string, paramIndex: number, reason: string);
1608
+ }
1609
+ /**
1610
+ * Error thrown when a required parameter is missing.
1611
+ * This is a CLIENT error (400) - the request is incomplete.
1612
+ *
1613
+ * `messageOverride` lets callers replace the generic
1614
+ * `Required <source> parameter "<name>" is missing` text with a more
1615
+ * specific message (e.g. `@Body()` appends a body-parser remediation hint
1616
+ * in `resolveParametersFromPlan` — see `binding/param-resolver.ts`) while
1617
+ * keeping `code`/`details`/`instanceof MissingParameterError` unchanged, so
1618
+ * existing error-handling code that switches on the error type is
1619
+ * unaffected.
1620
+ */
1621
+ declare class MissingParameterError extends BadRequestError {
1622
+ name: string;
1623
+ message: string;
1624
+ readonly controllerName: string;
1625
+ readonly methodName: string;
1626
+ readonly paramName: string;
1627
+ readonly source: string;
1628
+ constructor(controllerName: string, methodName: string, paramName: string, source: string, messageOverride?: string);
1629
+ }
1630
+ /**
1631
+ * Error thrown when route registration fails.
1632
+ * This is a server configuration error (500).
1633
+ */
1634
+ declare class RouteRegistrationError extends ControllerError {
1635
+ readonly controllerName: string;
1636
+ readonly method: string;
1637
+ readonly path: string;
1638
+ constructor(controllerName: string, method: string, path: string, reason: string, cause?: Error);
1639
+ }
1640
+ /**
1641
+ * Error thrown when a guard rejects the request.
1642
+ * This is a CLIENT error (403) - access denied.
1643
+ */
1644
+ declare class GuardRejectionError extends ForbiddenError {
1645
+ name: string;
1646
+ message: string;
1647
+ readonly guardName: string;
1648
+ constructor(guardName: string, message?: string);
1649
+ }
1650
+ /**
1651
+ * Error thrown when a class passed where a module is expected is not a valid
1652
+ * module. This is a server configuration error (500).
1653
+ */
1654
+ declare class NotAModuleError extends ControllerError {
1655
+ constructor(className: string);
1656
+ }
1657
+
1658
+ /**
1659
+ * DiscoverySource: Abstraction for controller class discovery.
1660
+ *
1661
+ * Two implementations:
1662
+ * - FilesystemSource: Scans the filesystem for controller files (default)
1663
+ * - MemorySource: Uses an explicit list of controller classes (programmatic/test)
1664
+ */
1665
+ /**
1666
+ * Discovers controller classes. Called by the discover stage.
1667
+ */
1668
+ interface DiscoverySource {
1669
+ discover(): ClassRef[] | Promise<ClassRef[]>;
1670
+ }
1671
+ /**
1672
+ * A controller class reference. Always a constructor function.
1673
+ */
1674
+ type ClassRef = Function;
1675
+ /**
1676
+ * FilesystemSource: Wraps the existing filesystem discovery logic.
1677
+ *
1678
+ * Scans a directory tree for controller files matching include/exclude patterns,
1679
+ * imports them, and returns the discovered controller classes.
1680
+ */
1681
+ declare class FilesystemSource implements DiscoverySource {
1682
+ private root;
1683
+ private include;
1684
+ private exclude;
1685
+ private debug;
1686
+ private _discoveryErrors;
1687
+ constructor(root: string, include: string[], exclude: string[], debug: boolean);
1688
+ discover(): Promise<ClassRef[]>;
1689
+ /**
1690
+ * Access discovery errors, if any, after discover() completes.
1691
+ * @internal
1692
+ */
1693
+ getDiscoveryErrors(): unknown[];
1694
+ }
1695
+ /**
1696
+ * MemorySource: Uses an explicit list of controller classes.
1697
+ *
1698
+ * For programmatic/test use cases where controller classes are already known
1699
+ * and no filesystem scan is needed.
1700
+ */
1701
+ declare class MemorySource implements DiscoverySource {
1702
+ private controllers;
1703
+ constructor(controllers: ClassRef[]);
1704
+ discover(): ClassRef[];
1705
+ }
1706
+
1707
+ /**
1708
+ * @nextrush/controllers - Type Definitions
1709
+ *
1710
+ * Types for the controller registrar.
1711
+ */
1712
+
1713
+ /**
1714
+ * Options for the controllers registrar
1715
+ *
1716
+ * Supports two modes:
1717
+ * 1. Auto-discovery (recommended): Scan directories for @Controller classes
1718
+ * 2. Manual: Explicitly provide controller classes
1719
+ */
1720
+ interface ControllersOptions {
1721
+ /**
1722
+ * Root directory to scan for controllers
1723
+ * When provided, enables auto-discovery mode
1724
+ * @example './src'
1725
+ */
1726
+ root?: string;
1727
+ /**
1728
+ * Glob patterns to include in auto-discovery.
1729
+ *
1730
+ * Defaults to the `*.controller.*` naming convention, so only files named
1731
+ * like `user.controller.ts` are imported. Non-controller modules (services,
1732
+ * guards, repositories) still load transitively via the controllers that
1733
+ * import them, so their `@Service`/`@Repository` side-effects still fire.
1734
+ *
1735
+ * To scan every source file instead (the pre-v3.2 behavior), pass the
1736
+ * scan-all escape hatch: `['**‍/*.ts', '**‍/*.js']`.
1737
+ *
1738
+ * Side-effect: each matched file is dynamically `import()`ed, which runs its
1739
+ * top-level module code.
1740
+ *
1741
+ * @default `['**‍/*.controller.ts', '**‍/*.controller.js']`
1742
+ */
1743
+ include?: string[];
1744
+ /**
1745
+ * Glob patterns to exclude from auto-discovery
1746
+ * @default `['**‍/*.test.ts', '**‍/*.spec.ts', '**‍/node_modules/**', '**‍/dist/**']`
1747
+ */
1748
+ exclude?: string[];
1749
+ /**
1750
+ * Explicit list of controller classes to register.
1751
+ *
1752
+ * A first-class alternative to `root`-based auto-discovery — not deprecated.
1753
+ * Prefer it when explicit wiring reads better than convention: greppable
1754
+ * registration, a deterministic registration order, or no filesystem scan at
1755
+ * all (tests, bundled or serverless builds where dynamically `import()`ing a
1756
+ * source tree is unavailable). Merged with any `root`-discovered controllers.
1757
+ */
1758
+ controllers?: Function[];
1759
+ /**
1760
+ * Custom discovery source for controller discovery.
1761
+ *
1762
+ * For programmatic/test use: supply a `DiscoverySource` that returns
1763
+ * controller classes instead of using filesystem scanning or the `controllers`
1764
+ * list. Advanced option; typically used with `MemorySource` in tests.
1765
+ *
1766
+ * Takes precedence over `root` and is incompatible with `controllers`.
1767
+ */
1768
+ source?: DiscoverySource;
1769
+ /**
1770
+ * Custom DI container to use.
1771
+ * If not provided, falls back to `app.container`, then the global container.
1772
+ */
1773
+ container?: Container;
1774
+ /**
1775
+ * Give this registration call its **own** isolated DI container so two apps in
1776
+ * the same process do not share service singletons.
1777
+ *
1778
+ * `@Service`/`@Repository`/`@Config` register their classes into the global
1779
+ * `@nextrush/di` container at import time, so by default every app that falls
1780
+ * back to the global container shares one instance of each service. With
1781
+ * `isolate: true`, `registerControllers` creates a fresh container via
1782
+ * `createContainer()` and re-registers the reachable service graph (each
1783
+ * controller's constructor dependency classes, transitively) into it with each
1784
+ * class's declared scope. Each isolated app then owns its own service
1785
+ * singletons; the controllers, their handlers, and boot-time validation all
1786
+ * resolve from this container.
1787
+ *
1788
+ * When `options.container` is provided it always wins — even under
1789
+ * `isolate: true` — because the caller has taken explicit ownership; the
1790
+ * service graph is registered into that container instead of a fresh one.
1791
+ *
1792
+ * String/symbol `@inject('TOKEN')` dependencies and any value/factory providers
1793
+ * carry no class metadata, so the graph walk cannot auto-register them. Register
1794
+ * them on the container you pass **before** calling `registerControllers` (see
1795
+ * the README). `@Optional()` dependencies that stay unregistered resolve to
1796
+ * `undefined` as usual.
1797
+ *
1798
+ * Non-breaking: defaults to `false`, preserving the current shared-container
1799
+ * behavior for every existing caller.
1800
+ *
1801
+ * @default false
1802
+ */
1803
+ isolate?: boolean;
1804
+ /**
1805
+ * Global middleware to apply to all controllers
1806
+ */
1807
+ middleware?: Middleware[];
1808
+ /**
1809
+ * Whether to enable debug logging
1810
+ * @default false
1811
+ */
1812
+ debug?: boolean;
1813
+ /**
1814
+ * Custom route prefix to apply to all controllers
1815
+ * @example '/api' or '/api/v1'
1816
+ */
1817
+ prefix?: string;
1818
+ /**
1819
+ * Whether to throw on discovery errors
1820
+ * @default false - logs warnings instead
1821
+ */
1822
+ strict?: boolean;
1823
+ /**
1824
+ * Whether to eagerly resolve every registered controller once at the end of
1825
+ * registration, so unsatisfiable or circular constructor dependencies fail at
1826
+ * boot (throwing {@link ControllerResolutionError}) instead of surfacing as a
1827
+ * 500 on the first HTTP request.
1828
+ * @default true
1829
+ */
1830
+ validate?: boolean;
1831
+ /**
1832
+ * Enable opt-in diagnostics collection from the ApplicationGraph IR.
1833
+ *
1834
+ * When true, collects routes, providers, duplicate routes, circular
1835
+ * dependencies, and bootstrap stage timings. Call getClassDiagnostics(app)
1836
+ * to retrieve the report after registration completes.
1837
+ *
1838
+ * Zero-cost when disabled: no timing measurement, no report collection,
1839
+ * no WeakMap storage. Use this for introspection, debugging, and dev tooling.
1840
+ *
1841
+ * @default false
1842
+ */
1843
+ diagnostics?: boolean;
1844
+ }
1845
+ /**
1846
+ * Resolved options with defaults applied
1847
+ */
1848
+ interface ResolvedOptions {
1849
+ readonly root: string | null;
1850
+ readonly include: string[];
1851
+ readonly exclude: string[];
1852
+ readonly controllers: Function[];
1853
+ readonly container: Container;
1854
+ readonly middleware: Middleware[];
1855
+ readonly debug: boolean;
1856
+ readonly prefix: string;
1857
+ readonly strict: boolean;
1858
+ readonly validate: boolean;
1859
+ readonly isolate: boolean;
1860
+ readonly diagnostics: boolean;
1861
+ }
1862
+ /**
1863
+ * Built route ready for registration
1864
+ */
1865
+ interface BuiltRoute {
1866
+ /** HTTP method */
1867
+ readonly method: string;
1868
+ /** Full path including controller prefix */
1869
+ readonly path: string;
1870
+ /** Route handler function */
1871
+ readonly handler: RouteHandler;
1872
+ /** Combined middleware (controller + route level) */
1873
+ readonly middleware: Middleware[];
1874
+ /** Controller class constructor */
1875
+ readonly controller: Function;
1876
+ /** Method name on controller */
1877
+ readonly methodName: string;
1878
+ /**
1879
+ * Route metadata contributed from decorators (@Controller tags, @Get/@Post
1880
+ * description/deprecated). Consumed by the router's RouteDefinition so
1881
+ * class-based routes are documented by renderers like @nextrush/openapi.
1882
+ * Undefined when the route carries no documentation.
1883
+ */
1884
+ readonly metadata?: MetadataContribution;
1885
+ }
1886
+ /**
1887
+ * Registered controller info
1888
+ */
1889
+ interface RegisteredController {
1890
+ /** Controller class */
1891
+ readonly target: Function;
1892
+ /** Controller definition with metadata */
1893
+ readonly definition: ControllerDefinition;
1894
+ /** Built routes */
1895
+ readonly routes: BuiltRoute[];
1896
+ }
1897
+ /**
1898
+ * Discovery result from file scanning
1899
+ */
1900
+ interface DiscoveryResult {
1901
+ /** Path to the source file */
1902
+ readonly filePath: string;
1903
+ /** Discovered controller classes */
1904
+ readonly controllers: Function[];
1905
+ /** Any errors during discovery */
1906
+ readonly errors: DiscoveryError[];
1907
+ }
1908
+ /**
1909
+ * Options for the discoverControllers function
1910
+ */
1911
+ interface DiscoveryOptions {
1912
+ /** Root directory to scan */
1913
+ readonly root: string;
1914
+ /** Glob patterns to include */
1915
+ readonly include?: string[];
1916
+ /** Glob patterns to exclude */
1917
+ readonly exclude?: string[];
1918
+ /** Enable debug logging */
1919
+ readonly debug?: boolean;
1920
+ }
1921
+
1922
+ /**
1923
+ * @nextrush/controllers - Controller registration
1924
+ *
1925
+ * `registerControllers(app, options)` is a **registrar**: it scans for
1926
+ * `@Controller` classes (or takes them explicitly), builds their routes, and
1927
+ * registers them on the app's router. It reads `app.router` and `app.container`
1928
+ * — no plugin lifecycle, no ignored app. Call it (awaited) before `serve()`.
1929
+ *
1930
+ * @example
1931
+ * ```typescript
1932
+ * const app = createApp();
1933
+ * await registerControllers(app, { root: './src', prefix: '/api' });
1934
+ * await serve(app, { port: 8080 });
1935
+ * ```
1936
+ */
1937
+
1938
+ /**
1939
+ * Discover and register decorator-based controllers on an application.
1940
+ *
1941
+ * Reads `app.router` (required) and `app.container` (falls back to a custom
1942
+ * container in options, then the global container). Supports auto-discovery
1943
+ * (`root`) and/or explicit `controllers`.
1944
+ *
1945
+ * @param app - The application (must have a router — use `createApp()` from `nextrush`)
1946
+ * @param options - Discovery/registration options
1947
+ */
1948
+ declare function registerControllers(app: Application, options?: ControllersOptions): Promise<void>;
1949
+
1950
+ /**
1951
+ * @nextrush/controllers - Module registrar
1952
+ *
1953
+ * `registerModule(app, RootModule, options?)` wires a whole `@Module` graph in
1954
+ * one call: it walks `imports`, registers every module's providers into the DI
1955
+ * container, then hands the flattened controller list to the existing
1956
+ * `registerControllers` pipeline (route building, eager validation, guard
1957
+ * validation, lifecycle-hook bridging, isolate/request-scope). It duplicates
1958
+ * none of that machinery. See RFC-NEXTRUSH-MODULES.
1959
+ *
1960
+ * @example
1961
+ * ```typescript
1962
+ * const app = createApp();
1963
+ * await registerModule(app, AppModule, { prefix: '/api' });
1964
+ * await serve(app, { port: 8080 });
1965
+ * ```
1966
+ */
1967
+
1968
+ /**
1969
+ * Options for {@link registerModule}. Mirrors the subset of
1970
+ * {@link ControllersOptions} that applies to module registration — module
1971
+ * composition replaces `root`/`controllers` discovery.
1972
+ */
1973
+ type ModuleRegistrationOptions = Pick<ControllersOptions, 'prefix' | 'middleware' | 'container' | 'isolate' | 'validate' | 'debug'>;
1974
+ /**
1975
+ * Register a module graph on an application.
1976
+ *
1977
+ * Selects the DI container once (an explicit `options.container` wins, else
1978
+ * `isolate` gets a fresh container, else `app.container` → the global
1979
+ * container), registers every module's providers into it, then registers all
1980
+ * controllers across the graph through {@link registerControllers}. The chosen
1981
+ * container is passed explicitly so it wins inside `registerControllers` even
1982
+ * under `isolate: true`, keeping providers and controllers on one container.
1983
+ *
1984
+ * @param app - The application (must have a router — use `createApp()`).
1985
+ * @param rootModule - The root `@Module` class.
1986
+ * @param options - Registration options (prefix, middleware, container, etc.).
1987
+ * @throws {NotAModuleError} if `rootModule` or any imported class is not a module.
1988
+ */
1989
+ declare function registerModule(app: Application, rootModule: Function, options?: ModuleRegistrationOptions): Promise<void>;
1990
+
1991
+ /**
1992
+ * @nextrush/controllers - Module graph traversal
1993
+ *
1994
+ * Walks a module's `imports` into a flat, ordered, deduplicated list. The walk
1995
+ * is post-order (imported feature modules before their importer), dedupes
1996
+ * diamond/duplicate imports, and guards import cycles. See RFC-NEXTRUSH-MODULES.
1997
+ */
1998
+ /**
1999
+ * Collect the full module graph reachable from `root` via `imports`.
2000
+ *
2001
+ * - **Post-order**: an imported module appears before the module that imports
2002
+ * it, so a feature module's providers/controllers register before the root's.
2003
+ * - **Dedupe**: a module reached through multiple paths (diamond) or listed
2004
+ * twice is included exactly once (first-completed wins).
2005
+ * - **Cycle guard**: a back-edge to an in-progress module is skipped, so a
2006
+ * mutual import (`A imports B imports A`) terminates instead of recursing
2007
+ * forever.
2008
+ *
2009
+ * @throws {NotAModuleError} if `root` or any imported class lacks `@Module`.
2010
+ */
2011
+ declare function collectModuleGraph(root: Function): Function[];
2012
+ /**
2013
+ * Collect every controller declared across an ordered module list, preserving
2014
+ * order and deduplicating a controller declared in more than one module.
2015
+ */
2016
+ declare function collectModuleControllers(modules: Function[]): Function[];
2017
+
2018
+ /**
2019
+ * @nextrush/controllers - Controller Discovery
2020
+ *
2021
+ * Automatic controller discovery by scanning directories.
2022
+ * Uses glob patterns to find files and imports them to discover controllers.
2023
+ *
2024
+ * ## Import side-effect (important)
2025
+ *
2026
+ * Discovery works by **dynamically `import()`ing every matched module**, then
2027
+ * inspecting its exports for `@Controller` classes. Importing a module runs its
2028
+ * top-level code — so any side-effects at module scope (DI registration via
2029
+ * `@Service`/`@Repository`, singleton construction, connection setup) execute
2030
+ * during discovery. This is load-bearing: services and guards register with the
2031
+ * DI container as a side-effect of being imported (transitively via the
2032
+ * controllers that import them, or directly when matched).
2033
+ */
2034
+
2035
+ /**
2036
+ * Discover all controllers in a directory.
2037
+ *
2038
+ * Scans `root` for files matching `include` (default: the `*.controller.*`
2039
+ * convention) and dynamically imports each match to find `@Controller` classes.
2040
+ *
2041
+ * @remarks
2042
+ * **Side-effect:** every matched module is `import()`ed, which runs its
2043
+ * top-level code (including DI registration). See the module-level docs. Only
2044
+ * files matching the convention are imported by default; pass
2045
+ * `include: ['**‍/*.ts', '**‍/*.js']` to scan every source file instead.
2046
+ *
2047
+ * Imports run in parallel with a bounded concurrency cap
2048
+ * ({@link IMPORT_CONCURRENCY}); results are aggregated deterministically in
2049
+ * scan order regardless of import completion order.
2050
+ *
2051
+ * @param options - Discovery options
2052
+ * @returns Array of discovery results (one per scanned file), in scan order
2053
+ *
2054
+ * @example
2055
+ * ```typescript
2056
+ * // Imports only *.controller.ts / *.controller.js files
2057
+ * const controllers = await discoverControllers({
2058
+ * root: './src',
2059
+ * });
2060
+ * ```
2061
+ */
2062
+ declare function discoverControllers(options: DiscoveryOptions): Promise<DiscoveryResult[]>;
2063
+ /**
2064
+ * Get all controllers from discovery results
2065
+ */
2066
+ declare function getControllersFromResults(results: DiscoveryResult[]): Function[];
2067
+ /**
2068
+ * Get all errors from discovery results
2069
+ */
2070
+ declare function getErrorsFromResults(results: DiscoveryResult[]): DiscoveryError[];
2071
+
2072
+ /**
2073
+ * @nextrush/controllers - ApplicationGraph IR (Immutable Intermediate Representation)
2074
+ *
2075
+ * RFC-NEXTRUSH-CLASS-CONSOLIDATION P3.4: Immutable IR that documents the
2076
+ * bootstrap read-once, freeze-then-execute pattern.
2077
+ *
2078
+ * CRITICAL PROPERTY: All metadata is read ONCE at bootstrap time via Reflect
2079
+ * and baked into the ApplicationGraph. The request-time handler execution path
2080
+ * performs ZERO Reflect metadata reads — metadata is captured in the handler
2081
+ * closure and precomputed data structures at build time.
2082
+ *
2083
+ * The graph captures per-controller:
2084
+ * - Route metadata (method/path/params/guards/filters/interceptors/httpCode/headers)
2085
+ * - Effective scope (singleton vs request-scoped) after dependency bubbling
2086
+ * - Middleware and provider graph nodes
2087
+ */
2088
+
2089
+ /**
2090
+ * ApplicationGraph IR: The immutable plan built once at bootstrap by reading
2091
+ * Reflect metadata. Request-time execution reads ONLY from this graph.
2092
+ *
2093
+ * The graph is deep-frozen to enforce immutability and prevent accidental
2094
+ * mutations that would break the boot-once guarantee.
2095
+ *
2096
+ * Structure:
2097
+ * - routes: All BuiltRoute objects with precomputed handler closures
2098
+ * - providers: DI provider metadata for request-scope bubble detection
2099
+ * - requestScopedTokens: Set of provider tokens with request scope
2100
+ */
2101
+ interface ApplicationGraph {
2102
+ /** All built routes (precomputed at bootstrap, frozen) */
2103
+ readonly routes: ReadonlyArray<BuiltRoute>;
2104
+ /** Provider dependency map (Function → Function[]) */
2105
+ readonly providers: ReadonlyMap<Function, ReadonlyArray<Function>>;
2106
+ /** Tokens marked as request-scoped (require child container per request) */
2107
+ readonly requestScopedTokens: ReadonlySet<Function>;
2108
+ }
2109
+
2110
+ /**
2111
+ * Diagnostics Report Types
2112
+ *
2113
+ * Opt-in diagnostics for @nextrush/class that capture ApplicationGraph IR
2114
+ * metadata (routes, providers, duplicates, cycles, timings) for introspection
2115
+ * and debugging.
2116
+ *
2117
+ * Zero-cost when disabled: no timing measurement, no report collection,
2118
+ * no WeakMap storage when diagnostics: false (default).
2119
+ */
2120
+ /**
2121
+ * A single timing measurement from a bootstrap stage.
2122
+ */
2123
+ interface TimingEntry {
2124
+ /** Bootstrap stage name */
2125
+ readonly stage: string;
2126
+ /** Duration in milliseconds */
2127
+ readonly ms: number;
2128
+ }
2129
+ /**
2130
+ * A single route entry in the diagnostics report.
2131
+ */
2132
+ interface RouteEntry {
2133
+ /** HTTP method (GET, POST, etc.) */
2134
+ readonly method: string;
2135
+ /** Route path (with prefix applied) */
2136
+ readonly path: string;
2137
+ /** Controller class constructor */
2138
+ readonly controller: Function;
2139
+ }
2140
+ /**
2141
+ * A single provider entry in the diagnostics report.
2142
+ */
2143
+ interface ProviderEntry {
2144
+ /** Provider token (class constructor or symbol) */
2145
+ readonly token: Function | Symbol;
2146
+ /** Dependency tokens this provider depends on */
2147
+ readonly dependencies: (Function | Symbol)[];
2148
+ }
2149
+ /**
2150
+ * A duplicate route flagged during detection.
2151
+ */
2152
+ interface DuplicateRoute {
2153
+ /** HTTP method */
2154
+ readonly method: string;
2155
+ /** Route path */
2156
+ readonly path: string;
2157
+ /** Number of controllers registering this route */
2158
+ readonly count: number;
2159
+ }
2160
+ /**
2161
+ * A circular dependency cycle detected in the provider graph.
2162
+ */
2163
+ interface CircularDependency {
2164
+ /** Cycle path as array of provider tokens */
2165
+ readonly cycle: ReadonlyArray<Function | Symbol>;
2166
+ }
2167
+ /**
2168
+ * Diagnostics Report
2169
+ *
2170
+ * Captures ApplicationGraph IR state (routes, providers, duplicates, cycles)
2171
+ * and bootstrap timings. Populated by collectDiagnostics() when
2172
+ * options.diagnostics === true.
2173
+ */
2174
+ interface DiagnosticsReport {
2175
+ /** All registered routes */
2176
+ readonly routes: ReadonlyArray<RouteEntry>;
2177
+ /** All providers in the DI graph */
2178
+ readonly providers: ReadonlyArray<ProviderEntry>;
2179
+ /** Routes registered more than once (method + path collision) */
2180
+ readonly duplicateRoutes: ReadonlyArray<DuplicateRoute>;
2181
+ /** Circular dependencies detected in provider graph */
2182
+ readonly circularDependencies: ReadonlyArray<CircularDependency>;
2183
+ /** Bootstrap stage timings */
2184
+ readonly timings: ReadonlyArray<TimingEntry>;
2185
+ }
2186
+
2187
+ /**
2188
+ * Public API for retrieving diagnostics reports
2189
+ *
2190
+ * Wrapper over the internal WeakMap storage to provide a clean public interface.
2191
+ */
2192
+
2193
+ /**
2194
+ * Retrieve the diagnostics report for an application.
2195
+ *
2196
+ * Returns undefined if diagnostics were not enabled during registration
2197
+ * (diagnostics: false or not specified in options).
2198
+ *
2199
+ * @param app The application instance
2200
+ * @returns Diagnostics report if enabled, undefined otherwise
2201
+ */
2202
+ declare function getClassDiagnostics(app: Application): DiagnosticsReport | undefined;
2203
+
2204
+ /**
2205
+ * @nextrush/controllers - Controller Registry
2206
+ *
2207
+ * Manages registration and tracking of controllers.
2208
+ */
2209
+
2210
+ /**
2211
+ * Registry for tracking and building controller routes
2212
+ */
2213
+ declare class ControllerRegistry {
2214
+ private readonly controllers;
2215
+ private readonly container;
2216
+ private readonly globalPrefix;
2217
+ private readonly globalMiddleware;
2218
+ private readonly debug;
2219
+ /**
2220
+ * Classes whose effective DI scope is `'request'` (self or dependency graph
2221
+ * declares `scope: 'request'`). A request-scoped controller is registered with
2222
+ * the request lifecycle and resolved from a per-request child on every request
2223
+ * instead of being memoized. Empty by default (pure singleton/transient graph).
2224
+ */
2225
+ private readonly requestScopedClasses;
2226
+ /**
2227
+ * Shared controller-instance cache, keyed by controller class.
2228
+ *
2229
+ * Owned by the registry so a single resolved singleton is reused across the
2230
+ * boot-time eager validation (`validateControllers`) and the per-request
2231
+ * handlers built by {@link buildRoutes}. Without a shared cache, `validate: true`
2232
+ * resolves each controller twice: once at boot and again on the first request.
2233
+ *
2234
+ * A failed resolve is never stored, so resolution retries on each request until
2235
+ * it succeeds (see `createRouteHandler` in `builder.ts`).
2236
+ */
2237
+ private readonly instanceCache;
2238
+ constructor(container: Container, globalPrefix: string, globalMiddleware: Middleware[], debug: boolean, requestScopedClasses?: ReadonlySet<Function>);
2239
+ /**
2240
+ * Register a controller class
2241
+ */
2242
+ register(controllerClass: Function): RegisteredController;
2243
+ /**
2244
+ * The shared controller-instance cache.
2245
+ *
2246
+ * Exposed so `registerControllers` can pre-seed it during eager validation
2247
+ * (`validate: true`), making the boot-time resolve and the per-request handler
2248
+ * share one singleton instead of resolving the same controller twice.
2249
+ */
2250
+ get instances(): Map<Function, unknown>;
2251
+ /**
2252
+ * Register multiple controllers
2253
+ */
2254
+ registerAll(controllers: Function[]): RegisteredController[];
2255
+ /**
2256
+ * Get all registered controllers
2257
+ */
2258
+ getAll(): RegisteredController[];
2259
+ /**
2260
+ * Get all built routes from all controllers
2261
+ */
2262
+ getAllRoutes(): BuiltRoute[];
2263
+ /**
2264
+ * Get total route count
2265
+ */
2266
+ get routeCount(): number;
2267
+ /**
2268
+ * Check if a controller is registered
2269
+ */
2270
+ has(controllerClass: Function): boolean;
2271
+ /**
2272
+ * Clear all registrations
2273
+ */
2274
+ clear(): void;
2275
+ /**
2276
+ * Register the controller in the DI container with its effective scope: a
2277
+ * request-effective controller (self or dependency graph declares
2278
+ * `scope: 'request'`) uses the request (ContainerScoped) lifecycle so a fresh
2279
+ * instance is built per request; every other controller stays a singleton.
2280
+ */
2281
+ private registerInContainer;
2282
+ /**
2283
+ * Log controller registration details
2284
+ */
2285
+ private logRegistration;
2286
+ }
2287
+
2288
+ /**
2289
+ * @nextrush/controllers - Handler Builder
2290
+ *
2291
+ * Builds route handlers from controller methods with parameter injection.
2292
+ * Orchestrates path construction, middleware resolution, and route metadata,
2293
+ * delegating per-route handler creation to {@link createRouteHandler}.
2294
+ */
2295
+
2296
+ /**
2297
+ * Build route handlers for a controller.
2298
+ *
2299
+ * @param instanceCache - Shared controller-instance cache (keyed by controller
2300
+ * class). Handlers read-or-populate it so a controller singleton is resolved
2301
+ * exactly once across boot-time validation and all requests. Defaults to a
2302
+ * fresh per-call map when omitted (standalone use), preserving lazy resolution.
2303
+ */
2304
+ declare function buildRoutes(definition: ControllerDefinition, container: Container, globalPrefix: string, globalMiddleware: Middleware[], instanceCache?: Map<Function, unknown>, isRequestScoped?: boolean): BuiltRoute[];
2305
+
2306
+ export { All, type ApplicationGraph, Body, type BodyOptions, type BuiltRoute, type CanActivate, Catch, type CircularDependency, type Constructor, Controller, type ControllerDefinition, ControllerError, type ControllerMetadata, type ControllerOptions, ControllerRegistry, ControllerResolutionError, type ControllerRouteMetadata, type ControllersOptions, Ctx, type CustomParamExtractor, DECORATOR_METADATA_KEYS, Delete, type DiagnosticsReport, DiscoveryError, type DiscoveryOptions, type DiscoveryResult, type DiscoverySource, type DuplicateRoute, type ExceptionFilter, type ExceptionFilterClass, FilesystemSource, type FilterMetadata, Get, type Guard, type GuardContext, type GuardFn, type GuardMetadata, GuardRejectionError, Head, Header, type HeaderOptions, HttpCode, type Interceptor, type InterceptorClass, type InterceptorMetadata, MemorySource, type MiddlewareRef, MissingParameterError, Module, type ModuleMetadata, type ModuleOptions, type ModuleProvider, type ModuleProviderConfig, type ModuleRegistrationOptions, NoRoutesError, NotAControllerError, NotAModuleError, type OnInit, type OnShutdown, Options, Param, type ParamMetadata, type ParamOptions, type ParamSource, ParameterInjectionError, Patch, Post, type ProviderEntry, Put, Query, type QueryOptions, Redirect, type RedirectMetadata, type RegisteredController, Req, Res, type ResolvedOptions, type ResponseHeaderMetadata, type RouteEntry, type RouteMetadata, type RouteMethods, type RouteOptions, RouteRegistrationError, SetHeader, type TimingEntry, type TransformFn, UseFilter, UseGuard, UseInterceptor, buildRoutes, collectModuleControllers, collectModuleGraph, createCustomParamDecorator, discoverControllers, getAllFilters, getAllGuards, getAllInterceptors, getAllParamMetadata, getCatchTypes, getClassDiagnostics, getClassFilters, getClassGuards, getClassInterceptors, getConstructorParamTypes, getControllerDefinition, getControllerMetadata, getControllersFromResults, getErrorsFromResults, getHttpCode, getMethodFilters, getMethodGuards, getMethodInterceptors, getModuleMetadata, getParamMetadata, getRedirectMetadata, getResponseHeaders, getRouteMetadata, isController, isGuardClass, isModule, isOnInit, isOnShutdown, isValidHttpMethod, isValidParamSource, registerControllers, registerModule };