honest-node 1.0.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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/dist/app.d.ts +1 -0
  4. package/dist/app.js +36 -0
  5. package/dist/application/plugin-entries.d.ts +13 -0
  6. package/dist/application/plugin-entries.js +38 -0
  7. package/dist/application/startup-guide.d.ts +4 -0
  8. package/dist/application/startup-guide.js +53 -0
  9. package/dist/application-context.d.ts +13 -0
  10. package/dist/application-context.js +22 -0
  11. package/dist/application.d.ts +34 -0
  12. package/dist/application.js +224 -0
  13. package/dist/components/index.d.ts +1 -0
  14. package/dist/components/index.js +1 -0
  15. package/dist/components/layout.component.d.ts +31 -0
  16. package/dist/components/layout.component.js +94 -0
  17. package/dist/constants/index.d.ts +2 -0
  18. package/dist/constants/index.js +2 -0
  19. package/dist/constants/pipeline.constants.d.ts +6 -0
  20. package/dist/constants/pipeline.constants.js +6 -0
  21. package/dist/constants/version.constants.d.ts +5 -0
  22. package/dist/constants/version.constants.js +5 -0
  23. package/dist/decorators/controller.decorator.d.ts +9 -0
  24. package/dist/decorators/controller.decorator.js +16 -0
  25. package/dist/decorators/http-method.decorator.d.ts +43 -0
  26. package/dist/decorators/http-method.decorator.js +44 -0
  27. package/dist/decorators/index.d.ts +11 -0
  28. package/dist/decorators/index.js +11 -0
  29. package/dist/decorators/module.decorator.d.ts +8 -0
  30. package/dist/decorators/module.decorator.js +12 -0
  31. package/dist/decorators/mvc.decorator.d.ts +26 -0
  32. package/dist/decorators/mvc.decorator.js +36 -0
  33. package/dist/decorators/parameter.decorator.d.ts +41 -0
  34. package/dist/decorators/parameter.decorator.js +59 -0
  35. package/dist/decorators/service.decorator.d.ts +6 -0
  36. package/dist/decorators/service.decorator.js +11 -0
  37. package/dist/decorators/use-component.decorator.d.ts +10 -0
  38. package/dist/decorators/use-component.decorator.js +19 -0
  39. package/dist/decorators/use-filters.decorator.d.ts +8 -0
  40. package/dist/decorators/use-filters.decorator.js +17 -0
  41. package/dist/decorators/use-guards.decorator.d.ts +9 -0
  42. package/dist/decorators/use-guards.decorator.js +18 -0
  43. package/dist/decorators/use-middleware.decorator.d.ts +9 -0
  44. package/dist/decorators/use-middleware.decorator.js +18 -0
  45. package/dist/decorators/use-pipes.decorator.d.ts +9 -0
  46. package/dist/decorators/use-pipes.decorator.js +18 -0
  47. package/dist/di/container.d.ts +34 -0
  48. package/dist/di/container.js +114 -0
  49. package/dist/di/index.d.ts +1 -0
  50. package/dist/di/index.js +1 -0
  51. package/dist/errors/framework.error.d.ts +19 -0
  52. package/dist/errors/framework.error.js +23 -0
  53. package/dist/errors/index.d.ts +1 -0
  54. package/dist/errors/index.js +1 -0
  55. package/dist/handlers/error.handler.d.ts +28 -0
  56. package/dist/handlers/error.handler.js +17 -0
  57. package/dist/handlers/index.d.ts +2 -0
  58. package/dist/handlers/index.js +2 -0
  59. package/dist/handlers/not-found.handler.d.ts +14 -0
  60. package/dist/handlers/not-found.handler.js +17 -0
  61. package/dist/helpers/create-error-response.helper.d.ts +25 -0
  62. package/dist/helpers/create-error-response.helper.js +90 -0
  63. package/dist/helpers/create-http-method-decorator.helper.d.ts +16 -0
  64. package/dist/helpers/create-http-method-decorator.helper.js +30 -0
  65. package/dist/helpers/create-param-decorator.helper.d.ts +16 -0
  66. package/dist/helpers/create-param-decorator.helper.js +60 -0
  67. package/dist/helpers/index.d.ts +3 -0
  68. package/dist/helpers/index.js +3 -0
  69. package/dist/index.d.ts +16 -0
  70. package/dist/index.js +16 -0
  71. package/dist/interfaces/application-context.interface.d.ts +35 -0
  72. package/dist/interfaces/application-context.interface.js +1 -0
  73. package/dist/interfaces/controller-options.interface.d.ts +17 -0
  74. package/dist/interfaces/controller-options.interface.js +1 -0
  75. package/dist/interfaces/di-container.interface.d.ts +35 -0
  76. package/dist/interfaces/di-container.interface.js +1 -0
  77. package/dist/interfaces/error-response.interface.d.ts +13 -0
  78. package/dist/interfaces/error-response.interface.js +1 -0
  79. package/dist/interfaces/filter.interface.d.ts +20 -0
  80. package/dist/interfaces/filter.interface.js +1 -0
  81. package/dist/interfaces/guard.interface.d.ts +21 -0
  82. package/dist/interfaces/guard.interface.js +1 -0
  83. package/dist/interfaces/handler-invocation.interface.d.ts +10 -0
  84. package/dist/interfaces/handler-invocation.interface.js +1 -0
  85. package/dist/interfaces/honest-options.interface.d.ts +121 -0
  86. package/dist/interfaces/honest-options.interface.js +1 -0
  87. package/dist/interfaces/http-method-options.interface.d.ts +38 -0
  88. package/dist/interfaces/http-method-options.interface.js +1 -0
  89. package/dist/interfaces/index.d.ts +21 -0
  90. package/dist/interfaces/index.js +21 -0
  91. package/dist/interfaces/logger.interface.d.ts +23 -0
  92. package/dist/interfaces/logger.interface.js +1 -0
  93. package/dist/interfaces/metadata-repository.interface.d.ts +30 -0
  94. package/dist/interfaces/metadata-repository.interface.js +1 -0
  95. package/dist/interfaces/middleware.interface.d.ts +22 -0
  96. package/dist/interfaces/middleware.interface.js +1 -0
  97. package/dist/interfaces/module-options.interface.d.ts +18 -0
  98. package/dist/interfaces/module-options.interface.js +1 -0
  99. package/dist/interfaces/parameter-metadata.interface.d.ts +27 -0
  100. package/dist/interfaces/parameter-metadata.interface.js +1 -0
  101. package/dist/interfaces/parameter-resolution.interface.d.ts +14 -0
  102. package/dist/interfaces/parameter-resolution.interface.js +1 -0
  103. package/dist/interfaces/pipe.interface.d.ts +37 -0
  104. package/dist/interfaces/pipe.interface.js +1 -0
  105. package/dist/interfaces/pipeline-context.interface.d.ts +9 -0
  106. package/dist/interfaces/pipeline-context.interface.js +1 -0
  107. package/dist/interfaces/plugin.interface.d.ts +74 -0
  108. package/dist/interfaces/plugin.interface.js +1 -0
  109. package/dist/interfaces/route-definition.interface.d.ts +51 -0
  110. package/dist/interfaces/route-definition.interface.js +1 -0
  111. package/dist/interfaces/route-info.interface.d.ts +42 -0
  112. package/dist/interfaces/route-info.interface.js +1 -0
  113. package/dist/interfaces/service-registry.interface.d.ts +7 -0
  114. package/dist/interfaces/service-registry.interface.js +1 -0
  115. package/dist/loggers/console.logger.d.ts +7 -0
  116. package/dist/loggers/console.logger.js +21 -0
  117. package/dist/loggers/index.d.ts +2 -0
  118. package/dist/loggers/index.js +2 -0
  119. package/dist/loggers/noop.logger.d.ts +7 -0
  120. package/dist/loggers/noop.logger.js +8 -0
  121. package/dist/managers/component.manager.d.ts +48 -0
  122. package/dist/managers/component.manager.js +210 -0
  123. package/dist/managers/handler.invoker.d.ts +7 -0
  124. package/dist/managers/handler.invoker.js +37 -0
  125. package/dist/managers/index.d.ts +5 -0
  126. package/dist/managers/index.js +5 -0
  127. package/dist/managers/parameter.resolver.d.ts +13 -0
  128. package/dist/managers/parameter.resolver.js +58 -0
  129. package/dist/managers/pipeline.executor.d.ts +28 -0
  130. package/dist/managers/pipeline.executor.js +71 -0
  131. package/dist/managers/route.manager.d.ts +36 -0
  132. package/dist/managers/route.manager.js +149 -0
  133. package/dist/registries/index.d.ts +4 -0
  134. package/dist/registries/index.js +4 -0
  135. package/dist/registries/metadata.registry.d.ts +163 -0
  136. package/dist/registries/metadata.registry.js +250 -0
  137. package/dist/registries/metadata.repository.d.ts +30 -0
  138. package/dist/registries/metadata.repository.js +151 -0
  139. package/dist/registries/route.registry.d.ts +16 -0
  140. package/dist/registries/route.registry.js +46 -0
  141. package/dist/registries/service.registry.d.ts +8 -0
  142. package/dist/registries/service.registry.js +9 -0
  143. package/dist/testing/create-controller-test-application.d.ts +5 -0
  144. package/dist/testing/create-controller-test-application.js +11 -0
  145. package/dist/testing/create-service-test-container.d.ts +5 -0
  146. package/dist/testing/create-service-test-container.js +31 -0
  147. package/dist/testing/create-test-application.d.ts +5 -0
  148. package/dist/testing/create-test-application.js +20 -0
  149. package/dist/testing/create-testing-module.d.ts +6 -0
  150. package/dist/testing/create-testing-module.js +13 -0
  151. package/dist/testing/fixtures/application-test-fixtures.d.ts +17 -0
  152. package/dist/testing/fixtures/application-test-fixtures.js +230 -0
  153. package/dist/testing/index.d.ts +5 -0
  154. package/dist/testing/index.js +5 -0
  155. package/dist/testing/testing.interface.d.ts +96 -0
  156. package/dist/testing/testing.interface.js +1 -0
  157. package/dist/types/constructor.type.d.ts +12 -0
  158. package/dist/types/constructor.type.js +1 -0
  159. package/dist/types/index.d.ts +1 -0
  160. package/dist/types/index.js +1 -0
  161. package/dist/utils/common.util.d.ts +117 -0
  162. package/dist/utils/common.util.js +140 -0
  163. package/dist/utils/index.d.ts +1 -0
  164. package/dist/utils/index.js +1 -0
  165. package/package.json +42 -0
@@ -0,0 +1,13 @@
1
+ import type { ParameterResolutionInput } from '../interfaces';
2
+ import type { ILogger } from '../interfaces';
3
+ import { ComponentManager } from './component.manager';
4
+ /**
5
+ * Resolves route handler arguments from parameter decorator metadata.
6
+ */
7
+ export declare class ParameterResolver {
8
+ private readonly componentManager;
9
+ private readonly logger;
10
+ private readonly debugPipeline;
11
+ constructor(componentManager: ComponentManager, logger?: ILogger, debugPipeline?: boolean);
12
+ resolveArguments(input: ParameterResolutionInput): Promise<unknown[]>;
13
+ }
@@ -0,0 +1,58 @@
1
+ import { NoopLogger } from '../loggers';
2
+ import { ComponentManager } from './component.manager';
3
+ /**
4
+ * Resolves route handler arguments from parameter decorator metadata.
5
+ */
6
+ export class ParameterResolver {
7
+ componentManager;
8
+ logger;
9
+ debugPipeline;
10
+ constructor(componentManager, logger = new NoopLogger(), debugPipeline = false) {
11
+ this.componentManager = componentManager;
12
+ this.logger = logger;
13
+ this.debugPipeline = debugPipeline;
14
+ }
15
+ async resolveArguments(input) {
16
+ const { controllerName, handlerName, handlerArity, handlerParams, handlerPipes, context } = input;
17
+ const maxDecoratorIndex = handlerParams.length > 0 ? Math.max(...handlerParams.map((parameter) => parameter.index)) : -1;
18
+ const args = new Array(Math.max(handlerArity, maxDecoratorIndex + 1));
19
+ const decoratedIndices = new Set(handlerParams.map((parameter) => parameter.index));
20
+ if (this.debugPipeline && maxDecoratorIndex >= 0) {
21
+ const sparseIndices = [];
22
+ for (let i = 0; i <= maxDecoratorIndex; i++) {
23
+ if (!decoratedIndices.has(i)) {
24
+ sparseIndices.push(i);
25
+ }
26
+ }
27
+ const hasOutOfRangeDecoratorIndex = maxDecoratorIndex >= handlerArity;
28
+ if (sparseIndices.length > 0 || hasOutOfRangeDecoratorIndex) {
29
+ this.logger.emit({
30
+ level: 'warn',
31
+ category: 'pipeline',
32
+ message: `Potential parameter binding mismatch at ${controllerName}.${String(handlerName)}`,
33
+ details: {
34
+ handlerArity,
35
+ maxDecoratorIndex,
36
+ sparseIndices,
37
+ handlerParamCount: handlerParams.length
38
+ }
39
+ });
40
+ }
41
+ }
42
+ for (const parameter of handlerParams) {
43
+ if (typeof parameter.factory !== 'function') {
44
+ throw new Error(`Invalid parameter decorator metadata for ${controllerName}.${String(handlerName)}`);
45
+ }
46
+ const rawValue = await parameter.factory(parameter.data, context);
47
+ const transformedValue = await this.componentManager.executePipes(rawValue, {
48
+ type: parameter.name,
49
+ metatype: parameter.metatype,
50
+ data: typeof parameter.data === 'string' || typeof parameter.data === 'undefined'
51
+ ? parameter.data
52
+ : String(parameter.data)
53
+ }, handlerPipes);
54
+ args[parameter.index] = transformedValue;
55
+ }
56
+ return args;
57
+ }
58
+ }
@@ -0,0 +1,28 @@
1
+ import type { Context } from 'hono';
2
+ import type { ILogger, ParameterMetadata } from '../interfaces';
3
+ import type { IPipe } from '../interfaces';
4
+ import { ComponentManager } from './component.manager';
5
+ import { HandlerInvoker } from './handler.invoker';
6
+ import { ParameterResolver } from './parameter.resolver';
7
+ import type { Constructor } from '../types';
8
+ export interface PipelineExecutionInput {
9
+ controllerClass: Constructor;
10
+ handlerName: string | symbol;
11
+ handler: (...args: unknown[]) => Promise<unknown> | unknown;
12
+ handlerParams: ReadonlyArray<ParameterMetadata>;
13
+ handlerPipes: ReadonlyArray<IPipe>;
14
+ contextIndex?: number;
15
+ context: Context;
16
+ }
17
+ /**
18
+ * Executes guard, parameter-resolution, and handler invocation stages.
19
+ */
20
+ export declare class PipelineExecutor {
21
+ private readonly componentManager;
22
+ private readonly parameterResolver;
23
+ private readonly handlerInvoker;
24
+ private readonly logger;
25
+ private readonly debugPipeline;
26
+ constructor(componentManager: ComponentManager, parameterResolver: ParameterResolver, handlerInvoker: HandlerInvoker, logger?: ILogger, debugPipeline?: boolean);
27
+ execute(input: PipelineExecutionInput): Promise<unknown>;
28
+ }
@@ -0,0 +1,71 @@
1
+ import { HTTPException } from 'hono/http-exception';
2
+ import { HONEST_PIPELINE_CONTROLLER_KEY, HONEST_PIPELINE_HANDLER_KEY } from '../constants';
3
+ import { NoopLogger } from '../loggers';
4
+ import { ComponentManager } from './component.manager';
5
+ import { HandlerInvoker } from './handler.invoker';
6
+ import { ParameterResolver } from './parameter.resolver';
7
+ /**
8
+ * Executes guard, parameter-resolution, and handler invocation stages.
9
+ */
10
+ export class PipelineExecutor {
11
+ componentManager;
12
+ parameterResolver;
13
+ handlerInvoker;
14
+ logger;
15
+ debugPipeline;
16
+ constructor(componentManager, parameterResolver, handlerInvoker, logger = new NoopLogger(), debugPipeline = false) {
17
+ this.componentManager = componentManager;
18
+ this.parameterResolver = parameterResolver;
19
+ this.handlerInvoker = handlerInvoker;
20
+ this.logger = logger;
21
+ this.debugPipeline = debugPipeline;
22
+ }
23
+ async execute(input) {
24
+ const { controllerClass, handlerName, handler, handlerParams, handlerPipes, contextIndex, context } = input;
25
+ context.set(HONEST_PIPELINE_CONTROLLER_KEY, controllerClass);
26
+ context.set(HONEST_PIPELINE_HANDLER_KEY, String(handlerName));
27
+ const guards = this.componentManager.getHandlerGuards(controllerClass, handlerName);
28
+ for (const guard of guards) {
29
+ const canActivate = await guard.canActivate(context);
30
+ if (!canActivate) {
31
+ if (this.debugPipeline) {
32
+ this.logger.emit({
33
+ level: 'warn',
34
+ category: 'pipeline',
35
+ message: `Guard rejected request at ${controllerClass.name}.${String(handlerName)}`,
36
+ details: { guard: guard.constructor?.name || 'UnknownGuard' }
37
+ });
38
+ }
39
+ throw new HTTPException(403, {
40
+ message: `Forbidden by ${guard.constructor?.name || 'UnknownGuard'} at ${controllerClass.name}.${String(handlerName)}`
41
+ });
42
+ }
43
+ }
44
+ const args = await this.parameterResolver.resolveArguments({
45
+ controllerName: controllerClass.name,
46
+ handlerName,
47
+ handlerArity: handler.length,
48
+ handlerParams,
49
+ handlerPipes,
50
+ context
51
+ });
52
+ if (this.debugPipeline) {
53
+ this.logger.emit({
54
+ level: 'debug',
55
+ category: 'pipeline',
56
+ message: `Resolved handler arguments for ${controllerClass.name}.${String(handlerName)}`,
57
+ details: {
58
+ guardCount: guards.length,
59
+ parameterCount: handlerParams.length,
60
+ pipeCount: handlerPipes.length
61
+ }
62
+ });
63
+ }
64
+ return this.handlerInvoker.invoke({
65
+ handler,
66
+ args,
67
+ context,
68
+ contextIndex
69
+ });
70
+ }
71
+ }
@@ -0,0 +1,36 @@
1
+ import type { Hono } from 'hono';
2
+ import { VERSION_NEUTRAL } from '../constants';
3
+ import type { DiContainer, ILogger, IMetadataRepository } from '../interfaces';
4
+ import { ComponentManager } from './component.manager';
5
+ import { RouteRegistry } from '../registries/route.registry';
6
+ import type { Constructor } from '../types';
7
+ /**
8
+ * Manager class for handling route registration in the Honest framework.
9
+ *
10
+ * Receives all per-app dependencies (Hono, Container, RouteRegistry,
11
+ * ComponentManager) via constructor — no static state.
12
+ */
13
+ export declare class RouteManager {
14
+ private hono;
15
+ private container;
16
+ private routeRegistry;
17
+ private componentManager;
18
+ private parameterResolver;
19
+ private pipelineExecutor;
20
+ private metadataRepository;
21
+ private logger;
22
+ private globalPrefix?;
23
+ private globalVersion?;
24
+ constructor(hono: Hono, container: DiContainer, routeRegistry: RouteRegistry, componentManager: ComponentManager, metadataRepository: IMetadataRepository, logger?: ILogger, options?: {
25
+ prefix?: string;
26
+ version?: number | typeof VERSION_NEUTRAL | number[];
27
+ debugPipeline?: boolean;
28
+ });
29
+ private applyGlobalMiddleware;
30
+ private normalizePath;
31
+ private registerRouteHandler;
32
+ private buildRoutePath;
33
+ private formatVersionSegment;
34
+ registerController(controllerClass: Constructor): Promise<void>;
35
+ private registerRoute;
36
+ }
@@ -0,0 +1,149 @@
1
+ import { VERSION_NEUTRAL } from '../constants';
2
+ import { NoopLogger } from '../loggers';
3
+ import { ComponentManager } from './component.manager';
4
+ import { HandlerInvoker } from './handler.invoker';
5
+ import { ParameterResolver } from './parameter.resolver';
6
+ import { PipelineExecutor } from './pipeline.executor';
7
+ import { RouteRegistry } from '../registries/route.registry';
8
+ import { isNil, isString, normalizePath } from '../utils';
9
+ /**
10
+ * Manager class for handling route registration in the Honest framework.
11
+ *
12
+ * Receives all per-app dependencies (Hono, Container, RouteRegistry,
13
+ * ComponentManager) via constructor — no static state.
14
+ */
15
+ export class RouteManager {
16
+ hono;
17
+ container;
18
+ routeRegistry;
19
+ componentManager;
20
+ parameterResolver;
21
+ pipelineExecutor;
22
+ metadataRepository;
23
+ logger;
24
+ globalPrefix;
25
+ globalVersion;
26
+ constructor(hono, container, routeRegistry, componentManager, metadataRepository, logger = new NoopLogger(), options = {}) {
27
+ this.hono = hono;
28
+ this.container = container;
29
+ this.routeRegistry = routeRegistry;
30
+ this.componentManager = componentManager;
31
+ this.logger = logger;
32
+ this.parameterResolver = new ParameterResolver(this.componentManager, this.logger, Boolean(options.debugPipeline));
33
+ this.pipelineExecutor = new PipelineExecutor(this.componentManager, this.parameterResolver, new HandlerInvoker(), this.logger, Boolean(options.debugPipeline));
34
+ this.metadataRepository = metadataRepository;
35
+ this.globalPrefix = options.prefix !== undefined ? this.normalizePath(options.prefix) : undefined;
36
+ this.globalVersion = options.version;
37
+ this.applyGlobalMiddleware();
38
+ }
39
+ applyGlobalMiddleware() {
40
+ const globalMiddleware = this.componentManager.getGlobalMiddleware();
41
+ for (const middleware of globalMiddleware) {
42
+ this.hono.use('*', middleware);
43
+ }
44
+ }
45
+ normalizePath(path) {
46
+ if (!isString(path)) {
47
+ throw new Error(`Invalid path: expected a string but received ${typeof path}. Check your @Controller() and route decorator arguments.`);
48
+ }
49
+ return normalizePath(path);
50
+ }
51
+ registerRouteHandler(method, path, handlerMiddleware, wrapperHandler) {
52
+ if (handlerMiddleware.length > 0) {
53
+ this.hono.on(method.toUpperCase(), [path], ...handlerMiddleware, wrapperHandler);
54
+ }
55
+ else {
56
+ this.hono.on(method.toUpperCase(), [path], wrapperHandler);
57
+ }
58
+ }
59
+ buildRoutePath(prefix, version, controllerPath, methodPath) {
60
+ return normalizePath(`${prefix}${version}${controllerPath}${methodPath}`);
61
+ }
62
+ formatVersionSegment(version) {
63
+ if (isNil(version)) {
64
+ return '';
65
+ }
66
+ return version === VERSION_NEUTRAL ? '' : `/v${String(version)}`;
67
+ }
68
+ async registerController(controllerClass) {
69
+ if (!this.metadataRepository.hasController(controllerClass)) {
70
+ throw new Error(`Controller ${controllerClass.name} is not decorated with @Controller()`);
71
+ }
72
+ const controllerPath = this.metadataRepository.getControllerPath(controllerClass) || '';
73
+ const controllerOptions = this.metadataRepository.getControllerOptions(controllerClass) || {};
74
+ const routes = this.metadataRepository.getRoutes(controllerClass) || [];
75
+ const parameterMetadata = this.metadataRepository.getParameters(controllerClass) || new Map();
76
+ const contextIndices = this.metadataRepository.getContextIndices(controllerClass) || new Map();
77
+ const controllerSegment = this.normalizePath(controllerPath);
78
+ const controllerInstance = this.container.resolve(controllerClass);
79
+ const effectiveControllerPrefix = controllerOptions.prefix !== undefined ? controllerOptions.prefix : this.globalPrefix;
80
+ const effectiveControllerVersion = controllerOptions.version !== undefined ? controllerOptions.version : this.globalVersion;
81
+ if (routes.length === 0) {
82
+ throw new Error(`Controller ${controllerClass.name} has no route handlers. Add HTTP method decorators like @Get()`);
83
+ }
84
+ for (const route of routes) {
85
+ const { path, method, version: routeVersion, prefix: routePrefix } = route;
86
+ const effectivePrefix = routePrefix !== undefined ? routePrefix : effectiveControllerPrefix;
87
+ const prefixSegment = !isNil(effectivePrefix) ? this.normalizePath(effectivePrefix) : '';
88
+ const effectiveVersion = routeVersion !== undefined ? routeVersion : effectiveControllerVersion;
89
+ const methodSegment = this.normalizePath(path);
90
+ if (isNil(effectiveVersion)) {
91
+ this.registerRoute(controllerInstance, route, parameterMetadata, contextIndices, controllerClass, prefixSegment, '', controllerSegment, methodSegment, method);
92
+ continue;
93
+ }
94
+ if (effectiveVersion === VERSION_NEUTRAL) {
95
+ this.registerRoute(controllerInstance, route, parameterMetadata, contextIndices, controllerClass, prefixSegment, '', controllerSegment, methodSegment, method);
96
+ this.registerRoute(controllerInstance, route, parameterMetadata, contextIndices, controllerClass, prefixSegment, '/:version{v[0-9]+}', controllerSegment, methodSegment, method);
97
+ continue;
98
+ }
99
+ if (Array.isArray(effectiveVersion)) {
100
+ for (const version of effectiveVersion) {
101
+ const versionSegment = this.formatVersionSegment(version);
102
+ this.registerRoute(controllerInstance, route, parameterMetadata, contextIndices, controllerClass, prefixSegment, versionSegment, controllerSegment, methodSegment, method);
103
+ }
104
+ continue;
105
+ }
106
+ const versionSegment = this.formatVersionSegment(effectiveVersion);
107
+ this.registerRoute(controllerInstance, route, parameterMetadata, contextIndices, controllerClass, prefixSegment, versionSegment, controllerSegment, methodSegment, method);
108
+ }
109
+ }
110
+ registerRoute(controllerInstance, route, parameterMetadata, contextIndices, controllerClass, prefixSegment, versionSegment, controllerSegment, methodSegment, method) {
111
+ const { handlerName } = route;
112
+ const fullPath = this.buildRoutePath(prefixSegment, versionSegment, controllerSegment, methodSegment);
113
+ const handler = controllerInstance[handlerName].bind(controllerInstance);
114
+ const handlerParams = parameterMetadata.get(handlerName) || [];
115
+ const contextIndex = contextIndices.get(handlerName);
116
+ const handlerMiddleware = this.componentManager.getHandlerMiddleware(controllerClass, handlerName);
117
+ const handlerPipes = this.componentManager.getHandlerPipes(controllerClass, handlerName);
118
+ this.routeRegistry.registerRoute({
119
+ controller: controllerClass.name,
120
+ handler: handlerName,
121
+ method,
122
+ prefix: prefixSegment,
123
+ version: versionSegment,
124
+ route: controllerSegment,
125
+ path: methodSegment,
126
+ fullPath,
127
+ parameters: handlerParams
128
+ });
129
+ const componentManager = this.componentManager;
130
+ const pipelineExecutor = this.pipelineExecutor;
131
+ const wrapperHandler = async (c) => {
132
+ try {
133
+ return await pipelineExecutor.execute({
134
+ controllerClass,
135
+ handlerName,
136
+ handler,
137
+ handlerParams,
138
+ handlerPipes,
139
+ contextIndex,
140
+ context: c
141
+ });
142
+ }
143
+ catch (error) {
144
+ return componentManager.handleException(error, c);
145
+ }
146
+ };
147
+ this.registerRouteHandler(method, fullPath, handlerMiddleware, wrapperHandler);
148
+ }
149
+ }
@@ -0,0 +1,4 @@
1
+ export * from './metadata.registry';
2
+ export * from './metadata.repository';
3
+ export * from './route.registry';
4
+ export * from './service.registry';
@@ -0,0 +1,4 @@
1
+ export * from './metadata.registry';
2
+ export * from './metadata.repository';
3
+ export * from './route.registry';
4
+ export * from './service.registry';
@@ -0,0 +1,163 @@
1
+ import type { ControllerOptions, FilterType, GuardType, MiddlewareType, ModuleOptions, ParameterMetadata, PipeType, RouteDefinition } from '../interfaces';
2
+ import type { Constructor } from '../types';
3
+ export type ComponentType = 'middleware' | 'guard' | 'pipe' | 'filter';
4
+ export type ComponentInstance = MiddlewareType | GuardType | PipeType | FilterType;
5
+ export interface ComponentTypeMap {
6
+ middleware: MiddlewareType;
7
+ guard: GuardType;
8
+ pipe: PipeType;
9
+ filter: FilterType;
10
+ }
11
+ /**
12
+ * Central registry for managing application metadata
13
+ * Stores and provides access to:
14
+ * - Route definitions and controller configurations
15
+ * - Service and module registrations
16
+ * - Parameter metadata and context indices
17
+ * - Component registrations at global, controller, and handler levels
18
+ */
19
+ export declare class MetadataRegistry {
20
+ /**
21
+ * Stores route definitions for each controller
22
+ * Maps controller classes to their route configurations
23
+ */
24
+ private static readonly routes;
25
+ /**
26
+ * Stores base paths for controllers
27
+ * Maps controller classes to their route prefixes
28
+ */
29
+ private static readonly controllers;
30
+ /**
31
+ * Stores configuration options for controllers
32
+ * Includes settings like versioning and prefix options
33
+ */
34
+ private static readonly controllerOptions;
35
+ /**
36
+ * Registry of service classes
37
+ * Used for dependency injection and lifecycle management
38
+ */
39
+ private static readonly services;
40
+ /**
41
+ * Stores configuration options for modules
42
+ * Includes imports, exports, providers, and controllers
43
+ */
44
+ private static readonly modules;
45
+ /**
46
+ * Stores parameter metadata for controller methods
47
+ * Used for parameter transformation and validation
48
+ */
49
+ private static readonly parameters;
50
+ /**
51
+ * Stores indices of context parameters in controller methods
52
+ * Used for optimizing context injection
53
+ */
54
+ private static readonly contextIndices;
55
+ /**
56
+ * Registry for controller-level components
57
+ * Components registered here apply to all routes in a specific controller
58
+ */
59
+ private static readonly controller;
60
+ /**
61
+ * Registry for handler-level components
62
+ * Components registered here apply to specific route handlers
63
+ * Keyed by controller constructor then handler name for collision-safe lookups
64
+ */
65
+ private static readonly handler;
66
+ /**
67
+ * Gets all route definitions for a controller
68
+ * @param controller - The controller class to get routes for
69
+ * @returns Array of route definitions for the controller
70
+ */
71
+ static getRoutes(controller: Constructor): RouteDefinition[];
72
+ /**
73
+ * Set routes for a controller
74
+ */
75
+ static setRoutes(controller: Constructor, routes: RouteDefinition[]): void;
76
+ /**
77
+ * Add a route to a controller
78
+ */
79
+ static addRoute(controller: Constructor, route: RouteDefinition): void;
80
+ /**
81
+ * Get controller path
82
+ */
83
+ static getControllerPath(controller: Constructor): string;
84
+ /**
85
+ * Check if a class is registered as a controller.
86
+ */
87
+ static hasController(controller: Constructor): boolean;
88
+ /**
89
+ * Set controller path
90
+ */
91
+ static setControllerPath(controller: Constructor, path: string): void;
92
+ /**
93
+ * Get controller options
94
+ */
95
+ static getControllerOptions(controller: Constructor): ControllerOptions;
96
+ /**
97
+ * Set controller options
98
+ */
99
+ static setControllerOptions(controller: Constructor, options: ControllerOptions): void;
100
+ /**
101
+ * Check if class is a service
102
+ */
103
+ static isService(service: Constructor): boolean;
104
+ /**
105
+ * Add a service
106
+ */
107
+ static addService(service: Constructor): void;
108
+ /**
109
+ * Get all services
110
+ */
111
+ static getAllServices(): Set<Constructor>;
112
+ /**
113
+ * Get module options
114
+ */
115
+ static getModuleOptions(module: Constructor): ModuleOptions | undefined;
116
+ /**
117
+ * Set module options
118
+ */
119
+ static setModuleOptions(module: Constructor, options: ModuleOptions): void;
120
+ /**
121
+ * Get parameter metadata
122
+ */
123
+ static getParameters(controller: Constructor): Map<string | symbol, ParameterMetadata[]>;
124
+ /**
125
+ * Set parameter metadata
126
+ */
127
+ static setParameterMap(controller: Constructor, params: Map<string | symbol, ParameterMetadata[]>): void;
128
+ /**
129
+ * Get context indices
130
+ */
131
+ static getContextIndices(controller: Constructor): Map<string | symbol, number>;
132
+ /**
133
+ * Set context indices
134
+ */
135
+ static setContextIndices(controller: Constructor, indices: Map<string | symbol, number>): void;
136
+ /**
137
+ * Register a component at the controller level
138
+ */
139
+ static registerController<T extends ComponentType>(type: T, controller: Constructor, component: ComponentTypeMap[T]): void;
140
+ /**
141
+ * Get all controller-level components of a specific type for a controller
142
+ */
143
+ static getController<T extends ComponentType>(type: T, controller: Constructor): ComponentTypeMap[T][];
144
+ /**
145
+ * Register a component at the handler level
146
+ */
147
+ static registerHandler<T extends ComponentType>(type: T, controller: Constructor, handlerName: string | symbol, component: ComponentTypeMap[T]): void;
148
+ /**
149
+ * Get all handler-level components of a specific type for a handler
150
+ */
151
+ static getHandler<T extends ComponentType>(type: T, controller: Constructor, handlerName: string | symbol): ComponentTypeMap[T][];
152
+ /**
153
+ * Clears handler-level component registrations created via {@link registerHandler}.
154
+ * Does not remove decorator-defined routes, controllers, or modules.
155
+ */
156
+ static clearHandlerComponents(): void;
157
+ /**
158
+ * Clears all registered decorator metadata.
159
+ * Primarily used for testing. Warning: clearing after importing decorated classes
160
+ * (e.g. shared fixtures) removes their metadata until those modules are re-evaluated.
161
+ */
162
+ static clear(): void;
163
+ }