@buenojs/bueno 0.8.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.
Files changed (120) hide show
  1. package/.env.example +109 -0
  2. package/.github/workflows/ci.yml +31 -0
  3. package/LICENSE +21 -0
  4. package/README.md +892 -0
  5. package/architecture.md +652 -0
  6. package/bun.lock +70 -0
  7. package/dist/cli/index.js +3233 -0
  8. package/dist/index.js +9014 -0
  9. package/package.json +77 -0
  10. package/src/cache/index.ts +795 -0
  11. package/src/cli/ARCHITECTURE.md +837 -0
  12. package/src/cli/bin.ts +10 -0
  13. package/src/cli/commands/build.ts +425 -0
  14. package/src/cli/commands/dev.ts +248 -0
  15. package/src/cli/commands/generate.ts +541 -0
  16. package/src/cli/commands/help.ts +55 -0
  17. package/src/cli/commands/index.ts +112 -0
  18. package/src/cli/commands/migration.ts +355 -0
  19. package/src/cli/commands/new.ts +804 -0
  20. package/src/cli/commands/start.ts +208 -0
  21. package/src/cli/core/args.ts +283 -0
  22. package/src/cli/core/console.ts +349 -0
  23. package/src/cli/core/index.ts +60 -0
  24. package/src/cli/core/prompt.ts +424 -0
  25. package/src/cli/core/spinner.ts +265 -0
  26. package/src/cli/index.ts +135 -0
  27. package/src/cli/templates/deploy.ts +295 -0
  28. package/src/cli/templates/docker.ts +307 -0
  29. package/src/cli/templates/index.ts +24 -0
  30. package/src/cli/utils/fs.ts +428 -0
  31. package/src/cli/utils/index.ts +8 -0
  32. package/src/cli/utils/strings.ts +197 -0
  33. package/src/config/env.ts +408 -0
  34. package/src/config/index.ts +506 -0
  35. package/src/config/loader.ts +329 -0
  36. package/src/config/merge.ts +285 -0
  37. package/src/config/types.ts +320 -0
  38. package/src/config/validation.ts +441 -0
  39. package/src/container/forward-ref.ts +143 -0
  40. package/src/container/index.ts +386 -0
  41. package/src/context/index.ts +360 -0
  42. package/src/database/index.ts +1142 -0
  43. package/src/database/migrations/index.ts +371 -0
  44. package/src/database/schema/index.ts +619 -0
  45. package/src/frontend/api-routes.ts +640 -0
  46. package/src/frontend/bundler.ts +643 -0
  47. package/src/frontend/console-client.ts +419 -0
  48. package/src/frontend/console-stream.ts +587 -0
  49. package/src/frontend/dev-server.ts +846 -0
  50. package/src/frontend/file-router.ts +611 -0
  51. package/src/frontend/frameworks/index.ts +106 -0
  52. package/src/frontend/frameworks/react.ts +85 -0
  53. package/src/frontend/frameworks/solid.ts +104 -0
  54. package/src/frontend/frameworks/svelte.ts +110 -0
  55. package/src/frontend/frameworks/vue.ts +92 -0
  56. package/src/frontend/hmr-client.ts +663 -0
  57. package/src/frontend/hmr.ts +728 -0
  58. package/src/frontend/index.ts +342 -0
  59. package/src/frontend/islands.ts +552 -0
  60. package/src/frontend/isr.ts +555 -0
  61. package/src/frontend/layout.ts +475 -0
  62. package/src/frontend/ssr/react.ts +446 -0
  63. package/src/frontend/ssr/solid.ts +523 -0
  64. package/src/frontend/ssr/svelte.ts +546 -0
  65. package/src/frontend/ssr/vue.ts +504 -0
  66. package/src/frontend/ssr.ts +699 -0
  67. package/src/frontend/types.ts +2274 -0
  68. package/src/health/index.ts +604 -0
  69. package/src/index.ts +410 -0
  70. package/src/lock/index.ts +587 -0
  71. package/src/logger/index.ts +444 -0
  72. package/src/logger/transports/index.ts +969 -0
  73. package/src/metrics/index.ts +494 -0
  74. package/src/middleware/built-in.ts +360 -0
  75. package/src/middleware/index.ts +94 -0
  76. package/src/modules/filters.ts +458 -0
  77. package/src/modules/guards.ts +405 -0
  78. package/src/modules/index.ts +1256 -0
  79. package/src/modules/interceptors.ts +574 -0
  80. package/src/modules/lazy.ts +418 -0
  81. package/src/modules/lifecycle.ts +478 -0
  82. package/src/modules/metadata.ts +90 -0
  83. package/src/modules/pipes.ts +626 -0
  84. package/src/router/index.ts +339 -0
  85. package/src/router/linear.ts +371 -0
  86. package/src/router/regex.ts +292 -0
  87. package/src/router/tree.ts +562 -0
  88. package/src/rpc/index.ts +1263 -0
  89. package/src/security/index.ts +436 -0
  90. package/src/ssg/index.ts +631 -0
  91. package/src/storage/index.ts +456 -0
  92. package/src/telemetry/index.ts +1097 -0
  93. package/src/testing/index.ts +1586 -0
  94. package/src/types/index.ts +236 -0
  95. package/src/types/optional-deps.d.ts +219 -0
  96. package/src/validation/index.ts +276 -0
  97. package/src/websocket/index.ts +1004 -0
  98. package/tests/integration/cli.test.ts +1016 -0
  99. package/tests/integration/fullstack.test.ts +234 -0
  100. package/tests/unit/cache.test.ts +174 -0
  101. package/tests/unit/cli-commands.test.ts +892 -0
  102. package/tests/unit/cli.test.ts +1258 -0
  103. package/tests/unit/container.test.ts +279 -0
  104. package/tests/unit/context.test.ts +221 -0
  105. package/tests/unit/database.test.ts +183 -0
  106. package/tests/unit/linear-router.test.ts +280 -0
  107. package/tests/unit/lock.test.ts +336 -0
  108. package/tests/unit/middleware.test.ts +184 -0
  109. package/tests/unit/modules.test.ts +142 -0
  110. package/tests/unit/pubsub.test.ts +257 -0
  111. package/tests/unit/regex-router.test.ts +265 -0
  112. package/tests/unit/router.test.ts +373 -0
  113. package/tests/unit/rpc.test.ts +1248 -0
  114. package/tests/unit/security.test.ts +174 -0
  115. package/tests/unit/telemetry.test.ts +371 -0
  116. package/tests/unit/test-cache.test.ts +110 -0
  117. package/tests/unit/test-database.test.ts +282 -0
  118. package/tests/unit/tree-router.test.ts +325 -0
  119. package/tests/unit/validation.test.ts +794 -0
  120. package/tsconfig.json +27 -0
@@ -0,0 +1,1256 @@
1
+ /**
2
+ * Module System
3
+ *
4
+ * NestJS-inspired module system with dependency injection,
5
+ * controllers, and provider management.
6
+ */
7
+
8
+ import {
9
+ Container,
10
+ type Provider,
11
+ type Token,
12
+ type ForwardRef,
13
+ forwardRef,
14
+ isForwardRef,
15
+ resolveForwardRef,
16
+ getInjectTokens,
17
+ } from "../container";
18
+ import {
19
+ type LazyModuleLoader,
20
+ type Constructor as LazyConstructor,
21
+ type ModuleLoaderFn,
22
+ type LazyModuleMetadata,
23
+ LazyModuleLoaderImpl,
24
+ LazyModule,
25
+ ModuleLoader,
26
+ MODULE_LOADER_TOKEN,
27
+ getLazyMetadata,
28
+ isLazyModule,
29
+ LazyModuleRegistry,
30
+ } from "./lazy";
31
+ import type { Context } from "../context";
32
+ import { Router } from "../router";
33
+ import type { RouteHandler } from "../types";
34
+ import {
35
+ LifecycleHookManager,
36
+ ShutdownSignalHandler,
37
+ type OnModuleInit,
38
+ type OnApplicationBootstrap,
39
+ type OnModuleDestroy,
40
+ type BeforeApplicationShutdown,
41
+ type OnApplicationShutdown,
42
+ type OnBeforeRequest,
43
+ type OnAfterRequest,
44
+ type OnRequestError,
45
+ type ApplicationLifecycle,
46
+ type RequestLifecycle,
47
+ type FullLifecycle,
48
+ isOnModuleInit,
49
+ isOnApplicationBootstrap,
50
+ isOnModuleDestroy,
51
+ isBeforeApplicationShutdown,
52
+ isOnApplicationShutdown,
53
+ isOnBeforeRequest,
54
+ isOnAfterRequest,
55
+ isOnRequestError,
56
+ } from "./lifecycle";
57
+ import {
58
+ type Guard,
59
+ type CanActivate,
60
+ type GuardFn,
61
+ getClassGuards,
62
+ getMethodGuards,
63
+ executeGuards,
64
+ createForbiddenResponse,
65
+ } from "./guards";
66
+ import {
67
+ type Interceptor,
68
+ type NestInterceptor,
69
+ type InterceptorFn,
70
+ type CallHandler,
71
+ getClassInterceptors,
72
+ getMethodInterceptors,
73
+ executeInterceptors,
74
+ isNestInterceptor,
75
+ isInterceptorFn,
76
+ } from "./interceptors";
77
+ import {
78
+ type Pipe,
79
+ type PipeTransform,
80
+ type PipeFn,
81
+ type PipeContext,
82
+ type ParameterPipeMetadata,
83
+ getMethodPipes,
84
+ executePipes,
85
+ extractParameterValue,
86
+ createBadRequestResponse,
87
+ } from "./pipes";
88
+ import {
89
+ type Filter,
90
+ type ExceptionFilter,
91
+ type FilterFn,
92
+ type ExecuteFiltersOptions,
93
+ UseFilters,
94
+ Catch,
95
+ getClassFilters,
96
+ getMethodFilters,
97
+ getCatchType,
98
+ canHandleException,
99
+ isExceptionFilter,
100
+ isFilterFn,
101
+ executeFilter,
102
+ findAndExecuteFilter,
103
+ HttpExceptionFilter,
104
+ ValidationFilter,
105
+ NotFoundFilter,
106
+ AllExceptionsFilter,
107
+ createDefaultErrorResponse,
108
+ createInternalErrorResponse,
109
+ } from "./filters";
110
+
111
+ // ============= Types =============
112
+
113
+ // Type alias for class constructors - re-exported from metadata.ts
114
+ export type Constructor = new (...args: unknown[]) => unknown;
115
+
116
+ /**
117
+ * @deprecated Use individual lifecycle hook interfaces instead.
118
+ * Kept for backward compatibility.
119
+ */
120
+ export interface LifecycleHooks {
121
+ onModuleInit?(): void | Promise<void>;
122
+ onModuleDestroy?(): void | Promise<void>;
123
+ onApplicationBootstrap?(): void | Promise<void>;
124
+ onApplicationShutdown?(): void | Promise<void>;
125
+ }
126
+
127
+ // ============= Metadata Storage =============
128
+ // Import metadata storage and decorators from isolated module to avoid circular dependencies
129
+ import {
130
+ setMetadata,
131
+ getMetadata,
132
+ setPrototypeMetadata,
133
+ getPrototypeMetadata,
134
+ Injectable,
135
+ Controller,
136
+ Module,
137
+ type ModuleMetadata,
138
+ } from "./metadata";
139
+
140
+ // Re-export decorators and types for external use
141
+ export { Injectable, Controller, Module, type ModuleMetadata };
142
+
143
+ /**
144
+ * Inject a dependency by token.
145
+ * Supports both Token and ForwardRef<Token> for circular dependency resolution.
146
+ *
147
+ * @param token - The injection token or a forward reference to the token
148
+ * @returns A parameter decorator that registers the injection metadata
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * // Regular injection
153
+ * constructor(@Inject(MY_TOKEN) private service: MyService) {}
154
+ *
155
+ * // Forward reference for circular dependency
156
+ * constructor(@Inject(forwardRef(() => ServiceB)) private serviceB: ServiceB) {}
157
+ * ```
158
+ */
159
+ export function Inject(token: Token | ForwardRef<Token>): ParameterDecorator {
160
+ return (
161
+ target: unknown,
162
+ propertyKey: string | symbol | undefined,
163
+ parameterIndex: number,
164
+ ) => {
165
+ const targetObj = target as Constructor;
166
+ const existingTokens: Array<Token | ForwardRef<Token>> =
167
+ getMetadata(targetObj, "inject:tokens") ?? [];
168
+ existingTokens[parameterIndex] = token;
169
+ setMetadata(targetObj, "inject:tokens", existingTokens);
170
+ };
171
+ }
172
+
173
+ // ============= HTTP Method Decorators =============
174
+
175
+ function createMethodDecorator(
176
+ method: string,
177
+ ): (path?: string) => MethodDecorator {
178
+ return (path = "") => {
179
+ return (
180
+ target: unknown,
181
+ propertyKey: string | symbol,
182
+ descriptor: PropertyDescriptor,
183
+ ) => {
184
+ const targetObj = target as object;
185
+ const routes =
186
+ getPrototypeMetadata<
187
+ Array<{ method: string; path: string; handler: string | symbol }>
188
+ >(targetObj, "routes") ?? [];
189
+ routes.push({
190
+ method,
191
+ path,
192
+ handler: propertyKey,
193
+ });
194
+ setPrototypeMetadata(targetObj, "routes", routes);
195
+ return descriptor;
196
+ };
197
+ };
198
+ }
199
+
200
+ export const Get = createMethodDecorator("GET");
201
+ export const Post = createMethodDecorator("POST");
202
+ export const Put = createMethodDecorator("PUT");
203
+ export const Patch = createMethodDecorator("PATCH");
204
+ export const Delete = createMethodDecorator("DELETE");
205
+ export const Head = createMethodDecorator("HEAD");
206
+ export const Options = createMethodDecorator("OPTIONS");
207
+
208
+ // ============= AppModule Class =============
209
+
210
+ export class AppModule {
211
+ private moduleClass: Constructor;
212
+ private metadata: ModuleMetadata;
213
+ private providers: Provider[] = [];
214
+ private controllers: Constructor[] = [];
215
+ private visitedModules = new Set<Constructor>();
216
+ private lazyModules: Constructor[] = [];
217
+
218
+ constructor(moduleClass: Constructor) {
219
+ this.moduleClass = moduleClass;
220
+ this.metadata = getMetadata<ModuleMetadata>(moduleClass, "module") ?? {};
221
+ this.processModule(moduleClass);
222
+ }
223
+
224
+ /**
225
+ * Process module and its imports recursively
226
+ * Skips lazy modules during initial processing
227
+ */
228
+ private processModule(moduleClass: Constructor): void {
229
+ if (this.visitedModules.has(moduleClass)) {
230
+ return;
231
+ }
232
+ this.visitedModules.add(moduleClass);
233
+
234
+ // Skip processing lazy modules at startup
235
+ if (isLazyModule(moduleClass)) {
236
+ this.lazyModules.push(moduleClass);
237
+ return;
238
+ }
239
+
240
+ const metadata = getMetadata<ModuleMetadata>(moduleClass, "module") ?? {};
241
+
242
+ // Process imports first (so dependencies are available)
243
+ if (metadata.imports) {
244
+ for (const importedModule of metadata.imports) {
245
+ this.processModule(importedModule);
246
+ }
247
+ }
248
+
249
+ // Add providers
250
+ if (metadata.providers) {
251
+ this.providers.push(...metadata.providers);
252
+ }
253
+
254
+ // Add controllers
255
+ if (metadata.controllers) {
256
+ this.controllers.push(...metadata.controllers);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Get all collected providers
262
+ */
263
+ getProviders(): Provider[] {
264
+ return [...this.providers];
265
+ }
266
+
267
+ /**
268
+ * Get all collected controllers
269
+ */
270
+ getControllers(): Constructor[] {
271
+ return [...this.controllers];
272
+ }
273
+
274
+ /**
275
+ * Get all lazy modules that were skipped during initial processing
276
+ */
277
+ getLazyModules(): Constructor[] {
278
+ return [...this.lazyModules];
279
+ }
280
+ }
281
+
282
+ // ============= Route Metadata for Guards and Pipes =============
283
+
284
+ /**
285
+ * Metadata stored for each route to support guards
286
+ */
287
+ interface RouteGuardMetadata {
288
+ controllerClass: Constructor;
289
+ handlerName: string | symbol;
290
+ classGuards: Guard[];
291
+ methodGuards: Guard[];
292
+ }
293
+
294
+ /**
295
+ * Metadata stored for each route to support pipes
296
+ */
297
+ interface RoutePipeMetadata {
298
+ controllerClass: Constructor;
299
+ handlerName: string | symbol;
300
+ parameterPipes: ParameterPipeMetadata[];
301
+ }
302
+
303
+ /**
304
+ * Metadata stored for each route to support filters
305
+ */
306
+ interface RouteFilterMetadata {
307
+ controllerClass: Constructor;
308
+ handlerName: string | symbol;
309
+ classFilters: Filter[];
310
+ methodFilters: Filter[];
311
+ }
312
+
313
+ /**
314
+ * Metadata stored for each route to support interceptors
315
+ */
316
+ interface RouteInterceptorMetadata {
317
+ controllerClass: Constructor;
318
+ handlerName: string | symbol;
319
+ classInterceptors: Interceptor[];
320
+ methodInterceptors: Interceptor[];
321
+ }
322
+
323
+ // ============= Application Class =============
324
+
325
+ export class Application {
326
+ container: Container;
327
+ router: Router;
328
+ private appModule: AppModule;
329
+ private lifecycleManager: LifecycleHookManager;
330
+ private shutdownHandler: ShutdownSignalHandler;
331
+ private server: ReturnType<typeof Bun.serve> | null = null;
332
+ private providerInstances: Map<Token, unknown> = new Map();
333
+ private controllerInstances: unknown[] = [];
334
+ private isInitialized = false;
335
+ private isShuttingDown = false;
336
+ private globalGuards: Guard[] = [];
337
+ private globalPipes: Pipe[] = [];
338
+ private globalFilters: Filter[] = [];
339
+ private globalInterceptors: Interceptor[] = [];
340
+ private routeGuardMetadata: Map<string, RouteGuardMetadata> = new Map();
341
+ private routePipeMetadata: Map<string, RoutePipeMetadata> = new Map();
342
+ private routeFilterMetadata: Map<string, RouteFilterMetadata> = new Map();
343
+ private routeInterceptorMetadata: Map<string, RouteInterceptorMetadata> = new Map();
344
+ private moduleLoader: ModuleLoader;
345
+ private loadedLazyModules = new Set<Constructor>();
346
+
347
+ constructor(moduleClass: Constructor) {
348
+ this.container = new Container();
349
+ this.router = new Router();
350
+ this.appModule = new AppModule(moduleClass);
351
+ this.lifecycleManager = new LifecycleHookManager();
352
+ this.shutdownHandler = new ShutdownSignalHandler();
353
+ this.moduleLoader = new ModuleLoader(this.container);
354
+ }
355
+
356
+ /**
357
+ * Add global guards that apply to all routes
358
+ * Global guards run before controller and method guards
359
+ *
360
+ * @param guards - Guards to add
361
+ * @returns this (for chaining)
362
+ *
363
+ * @example
364
+ * ```typescript
365
+ * const app = createApp(AppModule);
366
+ * app.useGlobalGuards(AuthGuard);
367
+ * await app.listen(3000);
368
+ * ```
369
+ */
370
+ useGlobalGuards(...guards: Guard[]): this {
371
+ this.globalGuards.push(...guards);
372
+ return this;
373
+ }
374
+
375
+ /**
376
+ * Add global pipes that apply to all parameters
377
+ * Global pipes run before parameter decorator pipes
378
+ *
379
+ * @param pipes - Pipes to add
380
+ * @returns this (for chaining)
381
+ *
382
+ * @example
383
+ * ```typescript
384
+ * const app = createApp(AppModule);
385
+ * app.useGlobalPipes(new ValidationPipe());
386
+ * await app.listen(3000);
387
+ * ```
388
+ */
389
+ useGlobalPipes(...pipes: Pipe[]): this {
390
+ this.globalPipes.push(...pipes);
391
+ return this;
392
+ }
393
+
394
+ /**
395
+ * Add global filters that apply to all routes
396
+ * Global filters run after controller and method filters
397
+ *
398
+ * @param filters - Filters to add
399
+ * @returns this (for chaining)
400
+ *
401
+ * @example
402
+ * ```typescript
403
+ * const app = createApp(AppModule);
404
+ * app.useGlobalFilters(new AllExceptionsFilter());
405
+ * await app.listen(3000);
406
+ * ```
407
+ */
408
+ useGlobalFilters(...filters: Filter[]): this {
409
+ this.globalFilters.push(...filters);
410
+ return this;
411
+ }
412
+
413
+ /**
414
+ * Add global interceptors that apply to all routes
415
+ * Global interceptors run before controller and method interceptors
416
+ *
417
+ * @param interceptors - Interceptors to add
418
+ * @returns this (for chaining)
419
+ *
420
+ * @example
421
+ * ```typescript
422
+ * const app = createApp(AppModule);
423
+ * app.useGlobalInterceptors(new LoggingInterceptor());
424
+ * await app.listen(3000);
425
+ * ```
426
+ */
427
+ useGlobalInterceptors(...interceptors: Interceptor[]): this {
428
+ this.globalInterceptors.push(...interceptors);
429
+ return this;
430
+ }
431
+
432
+ /**
433
+ * Register all providers in the container
434
+ */
435
+ private registerProviders(): void {
436
+ const providers = this.appModule.getProviders();
437
+ this.container.registerAll(providers);
438
+ }
439
+
440
+ /**
441
+ * Resolve all providers and register them with lifecycle manager
442
+ */
443
+ private async resolveProviders(): Promise<void> {
444
+ const providers = this.appModule.getProviders();
445
+
446
+ for (const provider of providers) {
447
+ const token = provider.token;
448
+ const instance = this.container.resolve(token as import("../container").Token);
449
+ this.providerInstances.set(token as import("../container").Token, instance);
450
+ this.lifecycleManager.registerInstance(instance);
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Register all controllers and their routes
456
+ */
457
+ private registerControllers(): void {
458
+ const controllers = this.appModule.getControllers();
459
+
460
+ for (const controllerClass of controllers) {
461
+ const instance = this.registerController(controllerClass);
462
+ this.controllerInstances.push(instance);
463
+ this.lifecycleManager.registerInstance(instance);
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Register a single controller and its routes
469
+ */
470
+ private registerController(controllerClass: Constructor): unknown {
471
+ const basePath = getMetadata<string>(controllerClass, "path") ?? "";
472
+ const routes =
473
+ getPrototypeMetadata<
474
+ Array<{ method: string; path: string; handler: string | symbol }>
475
+ >(controllerClass.prototype, "routes") ?? [];
476
+
477
+ // Create controller instance
478
+ const injectTokens =
479
+ getInjectTokens<Array<Token | ForwardRef<Token>>>(controllerClass, "inject:tokens") ?? [];
480
+ const deps = injectTokens.map((tokenOrRef) => {
481
+ // Resolve forward reference if needed
482
+ const token = isForwardRef(tokenOrRef) ? resolveForwardRef(tokenOrRef) : tokenOrRef;
483
+ return this.container.resolve(token);
484
+ });
485
+ const instance = new controllerClass(...deps);
486
+
487
+ // Get class-level guards
488
+ const classGuards = getClassGuards(controllerClass) ?? [];
489
+
490
+ // Get class-level interceptors
491
+ const classInterceptors = getClassInterceptors(controllerClass) ?? [];
492
+
493
+ // Register routes
494
+ for (const route of routes) {
495
+ const fullPath = basePath + route.path;
496
+ const handler = (instance as Record<string | symbol, RouteHandler>)[
497
+ route.handler
498
+ ];
499
+
500
+ if (typeof handler === "function") {
501
+ const method = route.method.toLowerCase();
502
+ const routerMethod = method as
503
+ | "get"
504
+ | "post"
505
+ | "put"
506
+ | "patch"
507
+ | "delete"
508
+ | "head"
509
+ | "options";
510
+
511
+ // Get method-level guards
512
+ const methodGuards = getMethodGuards(controllerClass.prototype, route.handler) ?? [];
513
+
514
+ // Get method-level pipes
515
+ const parameterPipes = getMethodPipes(controllerClass.prototype, route.handler) ?? [];
516
+
517
+ // Get class-level filters
518
+ const classFilters = getClassFilters(controllerClass) ?? [];
519
+
520
+ // Get method-level filters
521
+ const methodFilters = getMethodFilters(controllerClass.prototype, route.handler) ?? [];
522
+
523
+ // Get method-level interceptors
524
+ const methodInterceptors = getMethodInterceptors(controllerClass.prototype, route.handler) ?? [];
525
+
526
+ // Store guard metadata for this route
527
+ const routeKey = `${method.toUpperCase()}:${fullPath}`;
528
+ this.routeGuardMetadata.set(routeKey, {
529
+ controllerClass,
530
+ handlerName: route.handler,
531
+ classGuards,
532
+ methodGuards,
533
+ });
534
+
535
+ // Store pipe metadata for this route
536
+ if (parameterPipes.length > 0) {
537
+ this.routePipeMetadata.set(routeKey, {
538
+ controllerClass,
539
+ handlerName: route.handler,
540
+ parameterPipes,
541
+ });
542
+ }
543
+
544
+ // Store filter metadata for this route
545
+ if (classFilters.length > 0 || methodFilters.length > 0) {
546
+ this.routeFilterMetadata.set(routeKey, {
547
+ controllerClass,
548
+ handlerName: route.handler,
549
+ classFilters,
550
+ methodFilters,
551
+ });
552
+ }
553
+
554
+ // Store interceptor metadata for this route
555
+ if (classInterceptors.length > 0 || methodInterceptors.length > 0) {
556
+ this.routeInterceptorMetadata.set(routeKey, {
557
+ controllerClass,
558
+ handlerName: route.handler,
559
+ classInterceptors,
560
+ methodInterceptors,
561
+ });
562
+ }
563
+
564
+ if (
565
+ routerMethod in this.router &&
566
+ typeof (this.router as unknown as Record<string, unknown>)[
567
+ routerMethod
568
+ ] === "function"
569
+ ) {
570
+ (
571
+ this.router as unknown as Record<
572
+ string,
573
+ (p: string, h: RouteHandler) => void
574
+ >
575
+ )[routerMethod](fullPath, ((context: Context): unknown =>
576
+ handler.call(instance, context)) as RouteHandler);
577
+ }
578
+ }
579
+ }
580
+
581
+ return instance;
582
+ }
583
+
584
+ /**
585
+ * Initialize the application
586
+ *
587
+ * Execution order:
588
+ * 1. Module Registration
589
+ * 2. Provider Resolution
590
+ * 3. onModuleInit() for each provider
591
+ * 4. Controller Registration
592
+ * 5. onApplicationBootstrap() for each provider
593
+ */
594
+ async init(): Promise<void> {
595
+ if (this.isInitialized) {
596
+ return;
597
+ }
598
+
599
+ // 1. Register providers in container
600
+ this.registerProviders();
601
+
602
+ // Register the ModuleLoader service
603
+ this.container.register({
604
+ token: MODULE_LOADER_TOKEN,
605
+ useValue: this.moduleLoader,
606
+ });
607
+
608
+ // 2. Resolve providers and register with lifecycle manager
609
+ await this.resolveProviders();
610
+
611
+ // 3. Execute onModuleInit hooks
612
+ await this.lifecycleManager.executeOnModuleInit();
613
+
614
+ // 4. Register controllers
615
+ this.registerControllers();
616
+
617
+ // 5. Execute onApplicationBootstrap hooks
618
+ await this.lifecycleManager.executeOnApplicationBootstrap();
619
+
620
+ // Setup callback for lazy module loading
621
+ this.moduleLoader.setOnModuleLoadCallback(
622
+ async (moduleClass: Constructor) => {
623
+ await this.loadLazyModule(moduleClass);
624
+ },
625
+ );
626
+
627
+ this.isInitialized = true;
628
+ }
629
+
630
+ /**
631
+ * Load a lazy module dynamically
632
+ * This is called by the ModuleLoader service when a lazy module is loaded
633
+ */
634
+ private async loadLazyModule(moduleClass: Constructor): Promise<void> {
635
+ if (this.loadedLazyModules.has(moduleClass)) {
636
+ return;
637
+ }
638
+
639
+ const metadata = getMetadata<ModuleMetadata>(moduleClass, "module") ?? {};
640
+
641
+ // Register and resolve providers
642
+ if (metadata.providers) {
643
+ for (const provider of metadata.providers) {
644
+ this.container.register(provider);
645
+ const instance = this.container.resolve(provider.token as import("../container").Token);
646
+ this.providerInstances.set(provider.token as import("../container").Token, instance);
647
+ this.lifecycleManager.registerInstance(instance);
648
+ }
649
+
650
+ // Execute onModuleInit for new providers
651
+ await this.lifecycleManager.executeOnModuleInit();
652
+ }
653
+
654
+ // Register controllers
655
+ if (metadata.controllers) {
656
+ for (const controllerClass of metadata.controllers) {
657
+ const instance = this.registerController(controllerClass);
658
+ this.controllerInstances.push(instance);
659
+ this.lifecycleManager.registerInstance(instance);
660
+ }
661
+ }
662
+
663
+ // Execute onApplicationBootstrap for new instances
664
+ await this.lifecycleManager.executeOnApplicationBootstrap();
665
+
666
+ this.loadedLazyModules.add(moduleClass);
667
+ }
668
+
669
+ /**
670
+ * Get the ModuleLoader service for loading lazy modules
671
+ */
672
+ getModuleLoader(): ModuleLoader {
673
+ return this.moduleLoader;
674
+ }
675
+
676
+ /**
677
+ * Setup graceful shutdown handlers
678
+ */
679
+ private setupShutdownHandlers(): void {
680
+ this.shutdownHandler.onSignal(async (signal) => {
681
+ await this.shutdown(signal);
682
+ });
683
+ this.shutdownHandler.startListening();
684
+ }
685
+
686
+ /**
687
+ * Perform graceful shutdown
688
+ *
689
+ * Execution order:
690
+ * 1. Stop accepting new requests
691
+ * 2. beforeApplicationShutdown(signal)
692
+ * 3. Drain existing requests
693
+ * 4. onModuleDestroy() for each provider
694
+ * 5. onApplicationShutdown(signal)
695
+ */
696
+ async shutdown(signal?: string): Promise<void> {
697
+ if (this.isShuttingDown) {
698
+ return;
699
+ }
700
+ this.isShuttingDown = true;
701
+
702
+ console.log("Starting graceful shutdown...");
703
+
704
+ // 1. Stop accepting new requests
705
+ if (this.server) {
706
+ this.server.stop();
707
+ console.log("Server stopped accepting new connections");
708
+ }
709
+
710
+ // 2. Execute beforeApplicationShutdown hooks
711
+ await this.lifecycleManager.executeBeforeApplicationShutdown(signal);
712
+
713
+ // 3. Wait for existing requests to drain (with timeout)
714
+ // In a real implementation, you would track active requests
715
+ // For now, we just add a small delay
716
+ await new Promise((resolve) => setTimeout(resolve, 100));
717
+
718
+ // 4. Execute onModuleDestroy hooks
719
+ await this.lifecycleManager.executeOnModuleDestroy();
720
+
721
+ // 5. Execute onApplicationShutdown hooks
722
+ await this.lifecycleManager.executeOnApplicationShutdown(signal);
723
+
724
+ console.log("Graceful shutdown complete");
725
+ }
726
+
727
+ /**
728
+ * Start the HTTP server
729
+ */
730
+ async listen(port = 3000, hostname = "localhost"): Promise<void> {
731
+ // Initialize if not already done
732
+ await this.init();
733
+
734
+ // Setup shutdown handlers
735
+ this.setupShutdownHandlers();
736
+
737
+ const { Context } = await import("../context");
738
+ const { compose } = await import("../middleware");
739
+
740
+ this.server = Bun.serve({
741
+ port,
742
+ hostname,
743
+ fetch: async (request: Request) => {
744
+ // Reject new requests during shutdown
745
+ if (this.isShuttingDown) {
746
+ return new Response("Service Unavailable", { status: 503 });
747
+ }
748
+
749
+ const url = new URL(request.url);
750
+ const match = this.router.match(request.method as "GET", url.pathname);
751
+
752
+ if (!match) {
753
+ return new Response("Not Found", { status: 404 });
754
+ }
755
+
756
+ // Create context
757
+ const context = new Context(request, match.params);
758
+
759
+ // Execute onBeforeRequest hooks
760
+ try {
761
+ await this.lifecycleManager.executeOnBeforeRequest(context);
762
+ } catch (error) {
763
+ console.error("Error in onBeforeRequest hook:", error);
764
+ }
765
+
766
+ // Execute guards (before interceptors and pipes)
767
+ const routeKey = `${request.method}:${url.pathname}`;
768
+ const guardMetadata = this.routeGuardMetadata.get(routeKey);
769
+
770
+ if (guardMetadata || this.globalGuards.length > 0) {
771
+ const guardsPassed = await executeGuards(context, {
772
+ globalGuards: this.globalGuards,
773
+ classGuards: guardMetadata?.classGuards ?? [],
774
+ methodGuards: guardMetadata?.methodGuards ?? [],
775
+ resolveGuard: (guard: Guard) => {
776
+ // Try to resolve from container if it's a token
777
+ if (typeof guard === "object" && guard !== null && !("canActivate" in guard)) {
778
+ try {
779
+ return this.container.resolve(guard as Token) as CanActivate;
780
+ } catch {
781
+ return null;
782
+ }
783
+ }
784
+ return null;
785
+ },
786
+ });
787
+
788
+ if (!guardsPassed) {
789
+ return createForbiddenResponse();
790
+ }
791
+ }
792
+
793
+ // Get interceptor metadata
794
+ const interceptorMetadata = this.routeInterceptorMetadata.get(routeKey);
795
+
796
+ // Create the handler function that executes pipes and middleware
797
+ const executeHandler = async (): Promise<Response> => {
798
+ // Execute pipes (after guards, before handler)
799
+ const pipeMetadata = this.routePipeMetadata.get(routeKey);
800
+ if (pipeMetadata || this.globalPipes.length > 0) {
801
+ try {
802
+ // Process each parameter with pipes
803
+ const params = pipeMetadata?.parameterPipes ?? [];
804
+ for (const paramMeta of params) {
805
+ // Extract the initial value for this parameter
806
+ const initialValue = await extractParameterValue(context, paramMeta);
807
+
808
+ // Create pipe context
809
+ const pipeContext: PipeContext = {
810
+ context,
811
+ metadata: {
812
+ index: paramMeta.index,
813
+ name: paramMeta.key,
814
+ decorator: paramMeta.decorator,
815
+ },
816
+ };
817
+
818
+ // Execute pipes for this parameter
819
+ const transformedValue = await executePipes(initialValue, pipeContext, {
820
+ globalPipes: this.globalPipes,
821
+ parameterPipes: paramMeta.pipes,
822
+ resolvePipe: (pipe: Pipe) => {
823
+ // Try to resolve from container if it's a token
824
+ if (typeof pipe === "object" && pipe !== null && !("transform" in pipe)) {
825
+ try {
826
+ return this.container.resolve(pipe as Token) as PipeTransform;
827
+ } catch {
828
+ return null;
829
+ }
830
+ }
831
+ return null;
832
+ },
833
+ });
834
+
835
+ // Store the transformed value in context for handler access
836
+ context.set(`pipe:param:${paramMeta.index}`, transformedValue);
837
+ }
838
+ } catch (error) {
839
+ // Pipe transformation failed - return 400 Bad Request
840
+ if (error instanceof Error) {
841
+ return createBadRequestResponse(error);
842
+ }
843
+ return createBadRequestResponse(new Error("Pipe transformation failed"));
844
+ }
845
+ }
846
+
847
+ // Execute middleware and handler
848
+ const pipeline = compose((match.middleware ?? []) as import("../middleware").Middleware[]);
849
+ return pipeline(context, match.handler as import("../middleware").Handler);
850
+ };
851
+
852
+ // Execute interceptors wrapping around the handler
853
+ // Interceptors run after guards, before pipes
854
+ try {
855
+ const response = await executeInterceptors(context, executeHandler, {
856
+ globalInterceptors: this.globalInterceptors,
857
+ classInterceptors: interceptorMetadata?.classInterceptors ?? [],
858
+ methodInterceptors: interceptorMetadata?.methodInterceptors ?? [],
859
+ resolveInterceptor: (interceptor: Interceptor): NestInterceptor | InterceptorFn | null => {
860
+ // Try to resolve from container if it's a token
861
+ if (typeof interceptor === "object" && interceptor !== null && !isNestInterceptor(interceptor) && !isInterceptorFn(interceptor)) {
862
+ try {
863
+ return this.container.resolve(interceptor as Token) as NestInterceptor;
864
+ } catch {
865
+ return null;
866
+ }
867
+ }
868
+ // Try to instantiate if it's a class constructor
869
+ if (typeof interceptor === "function" && !isInterceptorFn(interceptor)) {
870
+ try {
871
+ const Constructor = interceptor as new () => NestInterceptor;
872
+ const instance = new Constructor();
873
+ if (isNestInterceptor(instance)) {
874
+ return instance;
875
+ }
876
+ } catch {
877
+ // Cannot instantiate
878
+ }
879
+ }
880
+ return null;
881
+ },
882
+ });
883
+
884
+ // Execute onAfterRequest hooks
885
+ try {
886
+ await this.lifecycleManager.executeOnAfterRequest(context, response as Response);
887
+ } catch (error) {
888
+ console.error("Error in onAfterRequest hook:", error);
889
+ }
890
+
891
+ return response as Response;
892
+ } catch (error) {
893
+ // Execute onRequestError hooks
894
+ try {
895
+ await this.lifecycleManager.executeOnRequestError(
896
+ context,
897
+ error as Error,
898
+ );
899
+ } catch (hookError) {
900
+ console.error("Error in onRequestError hook:", hookError);
901
+ }
902
+
903
+ // Handle exception with filters
904
+ return this.handleException(error as Error, context, routeKey);
905
+ }
906
+ },
907
+ });
908
+
909
+ console.log(`Server running at http://${hostname}:${port}`);
910
+ }
911
+
912
+ /**
913
+ * Handle request directly (for testing)
914
+ */
915
+ async handle(request: Request): Promise<Response> {
916
+ const { Context } = await import("../context");
917
+ const { compose } = await import("../middleware");
918
+
919
+ const url = new URL(request.url);
920
+ const match = this.router.match(request.method as "GET", url.pathname);
921
+
922
+ if (!match) {
923
+ return new Response("Not Found", { status: 404 });
924
+ }
925
+
926
+ const context = new Context(request, match.params);
927
+
928
+ // Execute guards (before interceptors and pipes)
929
+ const routeKey = `${request.method}:${url.pathname}`;
930
+ const guardMetadata = this.routeGuardMetadata.get(routeKey);
931
+
932
+ if (guardMetadata || this.globalGuards.length > 0) {
933
+ const guardsPassed = await executeGuards(context, {
934
+ globalGuards: this.globalGuards,
935
+ classGuards: guardMetadata?.classGuards ?? [],
936
+ methodGuards: guardMetadata?.methodGuards ?? [],
937
+ resolveGuard: (guard: Guard) => {
938
+ // Try to resolve from container if it's a token
939
+ if (typeof guard === "object" && guard !== null && !("canActivate" in guard)) {
940
+ try {
941
+ return this.container.resolve(guard as Token) as CanActivate;
942
+ } catch {
943
+ return null;
944
+ }
945
+ }
946
+ return null;
947
+ },
948
+ });
949
+
950
+ if (!guardsPassed) {
951
+ return createForbiddenResponse();
952
+ }
953
+ }
954
+
955
+ // Get interceptor metadata
956
+ const interceptorMetadata = this.routeInterceptorMetadata.get(routeKey);
957
+
958
+ // Create the handler function that executes pipes and middleware
959
+ const executeHandler = async (): Promise<Response> => {
960
+ // Execute pipes (after guards, before handler)
961
+ const pipeMetadata = this.routePipeMetadata.get(routeKey);
962
+ if (pipeMetadata || this.globalPipes.length > 0) {
963
+ try {
964
+ // Process each parameter with pipes
965
+ const params = pipeMetadata?.parameterPipes ?? [];
966
+ for (const paramMeta of params) {
967
+ // Extract the initial value for this parameter
968
+ const initialValue = await extractParameterValue(context, paramMeta);
969
+
970
+ // Create pipe context
971
+ const pipeContext: PipeContext = {
972
+ context,
973
+ metadata: {
974
+ index: paramMeta.index,
975
+ name: paramMeta.key,
976
+ decorator: paramMeta.decorator,
977
+ },
978
+ };
979
+
980
+ // Execute pipes for this parameter
981
+ const transformedValue = await executePipes(initialValue, pipeContext, {
982
+ globalPipes: this.globalPipes,
983
+ parameterPipes: paramMeta.pipes,
984
+ resolvePipe: (pipe: Pipe) => {
985
+ // Try to resolve from container if it's a token
986
+ if (typeof pipe === "object" && pipe !== null && !("transform" in pipe)) {
987
+ try {
988
+ return this.container.resolve(pipe as Token) as PipeTransform;
989
+ } catch {
990
+ return null;
991
+ }
992
+ }
993
+ return null;
994
+ },
995
+ });
996
+
997
+ // Store the transformed value in context for handler access
998
+ context.set(`pipe:param:${paramMeta.index}`, transformedValue);
999
+ }
1000
+ } catch (error) {
1001
+ // Pipe transformation failed - return 400 Bad Request
1002
+ if (error instanceof Error) {
1003
+ return createBadRequestResponse(error);
1004
+ }
1005
+ return createBadRequestResponse(new Error("Pipe transformation failed"));
1006
+ }
1007
+ }
1008
+
1009
+ // Execute middleware and handler
1010
+ const pipeline = compose((match.middleware ?? []) as import("../middleware").Middleware[]);
1011
+ return pipeline(context, match.handler as import("../middleware").Handler);
1012
+ };
1013
+
1014
+ // Execute interceptors wrapping around the handler
1015
+ // Interceptors run after guards, before pipes
1016
+ try {
1017
+ const response = await executeInterceptors(context, executeHandler, {
1018
+ globalInterceptors: this.globalInterceptors,
1019
+ classInterceptors: interceptorMetadata?.classInterceptors ?? [],
1020
+ methodInterceptors: interceptorMetadata?.methodInterceptors ?? [],
1021
+ resolveInterceptor: (interceptor: Interceptor): NestInterceptor | InterceptorFn | null => {
1022
+ // Try to resolve from container if it's a token
1023
+ if (typeof interceptor === "object" && interceptor !== null && !isNestInterceptor(interceptor) && !isInterceptorFn(interceptor)) {
1024
+ try {
1025
+ return this.container.resolve(interceptor as Token) as NestInterceptor;
1026
+ } catch {
1027
+ return null;
1028
+ }
1029
+ }
1030
+ // Try to instantiate if it's a class constructor
1031
+ if (typeof interceptor === "function" && !isInterceptorFn(interceptor)) {
1032
+ try {
1033
+ const Constructor = interceptor as new () => NestInterceptor;
1034
+ const instance = new Constructor();
1035
+ if (isNestInterceptor(instance)) {
1036
+ return instance;
1037
+ }
1038
+ } catch {
1039
+ // Cannot instantiate
1040
+ }
1041
+ }
1042
+ return null;
1043
+ },
1044
+ });
1045
+
1046
+ return response as Response;
1047
+ } catch (error) {
1048
+ // Handle exception with filters
1049
+ return this.handleException(error as Error, context, routeKey);
1050
+ }
1051
+ }
1052
+
1053
+ /**
1054
+ * Get the lifecycle manager for this application
1055
+ */
1056
+ getLifecycleManager(): LifecycleHookManager {
1057
+ return this.lifecycleManager;
1058
+ }
1059
+
1060
+ /**
1061
+ * Check if the application is shutting down
1062
+ */
1063
+ isShuttingDownNow(): boolean {
1064
+ return this.isShuttingDown;
1065
+ }
1066
+
1067
+ /**
1068
+ * Handle an exception using the filters system
1069
+ * Filters are checked in order: method → class → global
1070
+ */
1071
+ private async handleException(
1072
+ exception: Error,
1073
+ context: Context,
1074
+ routeKey: string,
1075
+ ): Promise<Response> {
1076
+ const filterMetadata = this.routeFilterMetadata.get(routeKey);
1077
+
1078
+ return findAndExecuteFilter(exception, context, {
1079
+ globalFilters: this.globalFilters,
1080
+ classFilters: filterMetadata?.classFilters ?? [],
1081
+ methodFilters: filterMetadata?.methodFilters ?? [],
1082
+ resolveFilter: (filter: Filter): ExceptionFilter | null => {
1083
+ // Try to resolve from container if it's a token
1084
+ if (typeof filter === "object" && filter !== null && !isExceptionFilter(filter)) {
1085
+ try {
1086
+ return this.container.resolve(filter as Token) as ExceptionFilter;
1087
+ } catch {
1088
+ return null;
1089
+ }
1090
+ }
1091
+ // Try to instantiate if it's a class constructor
1092
+ if (typeof filter === "function" && !isFilterFn(filter)) {
1093
+ try {
1094
+ const Constructor = filter as new () => ExceptionFilter;
1095
+ const instance = new Constructor();
1096
+ if (isExceptionFilter(instance)) {
1097
+ return instance;
1098
+ }
1099
+ } catch {
1100
+ // Cannot instantiate
1101
+ }
1102
+ }
1103
+ return null;
1104
+ },
1105
+ });
1106
+ }
1107
+ }
1108
+
1109
+ /**
1110
+ * Create an application from a module
1111
+ */
1112
+ export function createApp(moduleClass: Constructor): Application {
1113
+ return new Application(moduleClass);
1114
+ }
1115
+
1116
+ // Re-export lifecycle types and utilities
1117
+ export {
1118
+ LifecycleHookManager,
1119
+ ShutdownSignalHandler,
1120
+ OnModuleInit,
1121
+ OnApplicationBootstrap,
1122
+ OnModuleDestroy,
1123
+ BeforeApplicationShutdown,
1124
+ OnApplicationShutdown,
1125
+ OnBeforeRequest,
1126
+ OnAfterRequest,
1127
+ OnRequestError,
1128
+ ApplicationLifecycle,
1129
+ RequestLifecycle,
1130
+ FullLifecycle,
1131
+ isOnModuleInit,
1132
+ isOnApplicationBootstrap,
1133
+ isOnModuleDestroy,
1134
+ isBeforeApplicationShutdown,
1135
+ isOnApplicationShutdown,
1136
+ isOnBeforeRequest,
1137
+ isOnAfterRequest,
1138
+ isOnRequestError,
1139
+ };
1140
+
1141
+ // Re-export guards types and utilities
1142
+ export {
1143
+ type CanActivate,
1144
+ type GuardFn,
1145
+ type Guard,
1146
+ type User,
1147
+ UseGuards,
1148
+ AuthGuard,
1149
+ RolesGuard,
1150
+ Roles,
1151
+ getClassGuards,
1152
+ getMethodGuards,
1153
+ getMethodRoles,
1154
+ executeGuards,
1155
+ createForbiddenResponse,
1156
+ } from "./guards";
1157
+
1158
+ // Re-export pipes types and utilities
1159
+ export {
1160
+ type PipeTransform,
1161
+ type PipeFn,
1162
+ type Pipe,
1163
+ type PipeContext,
1164
+ type ParameterMetadata,
1165
+ type ParameterPipeMetadata,
1166
+ UsePipes,
1167
+ Body,
1168
+ Query,
1169
+ Param,
1170
+ ValidationPipe,
1171
+ ParseIntPipe,
1172
+ ParseFloatPipe,
1173
+ ParseBoolPipe,
1174
+ DefaultValuePipe,
1175
+ TrimPipe,
1176
+ ParseJsonPipe,
1177
+ ParseArrayPipe,
1178
+ getMethodPipes,
1179
+ executePipes,
1180
+ extractParameterValue,
1181
+ createBadRequestResponse,
1182
+ isPipeTransform,
1183
+ isPipeFn,
1184
+ } from "./pipes";
1185
+
1186
+ // Re-export filters types and utilities
1187
+ export {
1188
+ type ExceptionFilter,
1189
+ type FilterFn,
1190
+ type Filter,
1191
+ type ExecuteFiltersOptions,
1192
+ UseFilters,
1193
+ Catch,
1194
+ getClassFilters,
1195
+ getMethodFilters,
1196
+ getCatchType,
1197
+ canHandleException,
1198
+ isExceptionFilter,
1199
+ isFilterFn,
1200
+ executeFilter,
1201
+ findAndExecuteFilter,
1202
+ HttpExceptionFilter,
1203
+ ValidationFilter,
1204
+ NotFoundFilter,
1205
+ AllExceptionsFilter,
1206
+ createDefaultErrorResponse,
1207
+ createInternalErrorResponse,
1208
+ } from "./filters";
1209
+
1210
+ // Re-export interceptors types and utilities
1211
+ export {
1212
+ type NestInterceptor,
1213
+ type InterceptorFn,
1214
+ type Interceptor,
1215
+ type CallHandler,
1216
+ type TransformResponse,
1217
+ type InterceptorExecutorOptions,
1218
+ UseInterceptors,
1219
+ LoggingInterceptor,
1220
+ TransformInterceptor,
1221
+ TimeoutInterceptor,
1222
+ CacheInterceptor,
1223
+ HeaderInterceptor,
1224
+ getClassInterceptors,
1225
+ getMethodInterceptors,
1226
+ executeInterceptors,
1227
+ isNestInterceptor,
1228
+ isInterceptorFn,
1229
+ } from "./interceptors";
1230
+
1231
+ // Re-export lazy loading types and utilities
1232
+ export {
1233
+ type LazyModuleLoader,
1234
+ type Constructor as LazyModuleConstructor,
1235
+ type ModuleLoaderFn,
1236
+ type LazyModuleMetadata,
1237
+ type LoadModuleOptions,
1238
+ LazyModuleLoaderImpl,
1239
+ LazyModule,
1240
+ ModuleLoader,
1241
+ MODULE_LOADER_TOKEN,
1242
+ getLazyMetadata,
1243
+ isLazyModule,
1244
+ LazyModuleRegistry,
1245
+ createLazyLoader,
1246
+ areAllLazyModulesLoaded,
1247
+ getUnloadedLazyModules,
1248
+ } from "./lazy";
1249
+
1250
+ // Re-export forward reference utilities for circular dependencies
1251
+ export {
1252
+ type ForwardRef,
1253
+ forwardRef,
1254
+ isForwardRef,
1255
+ resolveForwardRef,
1256
+ } from "../container";