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.
- package/LICENSE +21 -0
- package/README.md +277 -0
- package/dist/app.d.ts +1 -0
- package/dist/app.js +36 -0
- package/dist/application/plugin-entries.d.ts +13 -0
- package/dist/application/plugin-entries.js +38 -0
- package/dist/application/startup-guide.d.ts +4 -0
- package/dist/application/startup-guide.js +53 -0
- package/dist/application-context.d.ts +13 -0
- package/dist/application-context.js +22 -0
- package/dist/application.d.ts +34 -0
- package/dist/application.js +224 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/layout.component.d.ts +31 -0
- package/dist/components/layout.component.js +94 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.js +2 -0
- package/dist/constants/pipeline.constants.d.ts +6 -0
- package/dist/constants/pipeline.constants.js +6 -0
- package/dist/constants/version.constants.d.ts +5 -0
- package/dist/constants/version.constants.js +5 -0
- package/dist/decorators/controller.decorator.d.ts +9 -0
- package/dist/decorators/controller.decorator.js +16 -0
- package/dist/decorators/http-method.decorator.d.ts +43 -0
- package/dist/decorators/http-method.decorator.js +44 -0
- package/dist/decorators/index.d.ts +11 -0
- package/dist/decorators/index.js +11 -0
- package/dist/decorators/module.decorator.d.ts +8 -0
- package/dist/decorators/module.decorator.js +12 -0
- package/dist/decorators/mvc.decorator.d.ts +26 -0
- package/dist/decorators/mvc.decorator.js +36 -0
- package/dist/decorators/parameter.decorator.d.ts +41 -0
- package/dist/decorators/parameter.decorator.js +59 -0
- package/dist/decorators/service.decorator.d.ts +6 -0
- package/dist/decorators/service.decorator.js +11 -0
- package/dist/decorators/use-component.decorator.d.ts +10 -0
- package/dist/decorators/use-component.decorator.js +19 -0
- package/dist/decorators/use-filters.decorator.d.ts +8 -0
- package/dist/decorators/use-filters.decorator.js +17 -0
- package/dist/decorators/use-guards.decorator.d.ts +9 -0
- package/dist/decorators/use-guards.decorator.js +18 -0
- package/dist/decorators/use-middleware.decorator.d.ts +9 -0
- package/dist/decorators/use-middleware.decorator.js +18 -0
- package/dist/decorators/use-pipes.decorator.d.ts +9 -0
- package/dist/decorators/use-pipes.decorator.js +18 -0
- package/dist/di/container.d.ts +34 -0
- package/dist/di/container.js +114 -0
- package/dist/di/index.d.ts +1 -0
- package/dist/di/index.js +1 -0
- package/dist/errors/framework.error.d.ts +19 -0
- package/dist/errors/framework.error.js +23 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/handlers/error.handler.d.ts +28 -0
- package/dist/handlers/error.handler.js +17 -0
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +2 -0
- package/dist/handlers/not-found.handler.d.ts +14 -0
- package/dist/handlers/not-found.handler.js +17 -0
- package/dist/helpers/create-error-response.helper.d.ts +25 -0
- package/dist/helpers/create-error-response.helper.js +90 -0
- package/dist/helpers/create-http-method-decorator.helper.d.ts +16 -0
- package/dist/helpers/create-http-method-decorator.helper.js +30 -0
- package/dist/helpers/create-param-decorator.helper.d.ts +16 -0
- package/dist/helpers/create-param-decorator.helper.js +60 -0
- package/dist/helpers/index.d.ts +3 -0
- package/dist/helpers/index.js +3 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/dist/interfaces/application-context.interface.d.ts +35 -0
- package/dist/interfaces/application-context.interface.js +1 -0
- package/dist/interfaces/controller-options.interface.d.ts +17 -0
- package/dist/interfaces/controller-options.interface.js +1 -0
- package/dist/interfaces/di-container.interface.d.ts +35 -0
- package/dist/interfaces/di-container.interface.js +1 -0
- package/dist/interfaces/error-response.interface.d.ts +13 -0
- package/dist/interfaces/error-response.interface.js +1 -0
- package/dist/interfaces/filter.interface.d.ts +20 -0
- package/dist/interfaces/filter.interface.js +1 -0
- package/dist/interfaces/guard.interface.d.ts +21 -0
- package/dist/interfaces/guard.interface.js +1 -0
- package/dist/interfaces/handler-invocation.interface.d.ts +10 -0
- package/dist/interfaces/handler-invocation.interface.js +1 -0
- package/dist/interfaces/honest-options.interface.d.ts +121 -0
- package/dist/interfaces/honest-options.interface.js +1 -0
- package/dist/interfaces/http-method-options.interface.d.ts +38 -0
- package/dist/interfaces/http-method-options.interface.js +1 -0
- package/dist/interfaces/index.d.ts +21 -0
- package/dist/interfaces/index.js +21 -0
- package/dist/interfaces/logger.interface.d.ts +23 -0
- package/dist/interfaces/logger.interface.js +1 -0
- package/dist/interfaces/metadata-repository.interface.d.ts +30 -0
- package/dist/interfaces/metadata-repository.interface.js +1 -0
- package/dist/interfaces/middleware.interface.d.ts +22 -0
- package/dist/interfaces/middleware.interface.js +1 -0
- package/dist/interfaces/module-options.interface.d.ts +18 -0
- package/dist/interfaces/module-options.interface.js +1 -0
- package/dist/interfaces/parameter-metadata.interface.d.ts +27 -0
- package/dist/interfaces/parameter-metadata.interface.js +1 -0
- package/dist/interfaces/parameter-resolution.interface.d.ts +14 -0
- package/dist/interfaces/parameter-resolution.interface.js +1 -0
- package/dist/interfaces/pipe.interface.d.ts +37 -0
- package/dist/interfaces/pipe.interface.js +1 -0
- package/dist/interfaces/pipeline-context.interface.d.ts +9 -0
- package/dist/interfaces/pipeline-context.interface.js +1 -0
- package/dist/interfaces/plugin.interface.d.ts +74 -0
- package/dist/interfaces/plugin.interface.js +1 -0
- package/dist/interfaces/route-definition.interface.d.ts +51 -0
- package/dist/interfaces/route-definition.interface.js +1 -0
- package/dist/interfaces/route-info.interface.d.ts +42 -0
- package/dist/interfaces/route-info.interface.js +1 -0
- package/dist/interfaces/service-registry.interface.d.ts +7 -0
- package/dist/interfaces/service-registry.interface.js +1 -0
- package/dist/loggers/console.logger.d.ts +7 -0
- package/dist/loggers/console.logger.js +21 -0
- package/dist/loggers/index.d.ts +2 -0
- package/dist/loggers/index.js +2 -0
- package/dist/loggers/noop.logger.d.ts +7 -0
- package/dist/loggers/noop.logger.js +8 -0
- package/dist/managers/component.manager.d.ts +48 -0
- package/dist/managers/component.manager.js +210 -0
- package/dist/managers/handler.invoker.d.ts +7 -0
- package/dist/managers/handler.invoker.js +37 -0
- package/dist/managers/index.d.ts +5 -0
- package/dist/managers/index.js +5 -0
- package/dist/managers/parameter.resolver.d.ts +13 -0
- package/dist/managers/parameter.resolver.js +58 -0
- package/dist/managers/pipeline.executor.d.ts +28 -0
- package/dist/managers/pipeline.executor.js +71 -0
- package/dist/managers/route.manager.d.ts +36 -0
- package/dist/managers/route.manager.js +149 -0
- package/dist/registries/index.d.ts +4 -0
- package/dist/registries/index.js +4 -0
- package/dist/registries/metadata.registry.d.ts +163 -0
- package/dist/registries/metadata.registry.js +250 -0
- package/dist/registries/metadata.repository.d.ts +30 -0
- package/dist/registries/metadata.repository.js +151 -0
- package/dist/registries/route.registry.d.ts +16 -0
- package/dist/registries/route.registry.js +46 -0
- package/dist/registries/service.registry.d.ts +8 -0
- package/dist/registries/service.registry.js +9 -0
- package/dist/testing/create-controller-test-application.d.ts +5 -0
- package/dist/testing/create-controller-test-application.js +11 -0
- package/dist/testing/create-service-test-container.d.ts +5 -0
- package/dist/testing/create-service-test-container.js +31 -0
- package/dist/testing/create-test-application.d.ts +5 -0
- package/dist/testing/create-test-application.js +20 -0
- package/dist/testing/create-testing-module.d.ts +6 -0
- package/dist/testing/create-testing-module.js +13 -0
- package/dist/testing/fixtures/application-test-fixtures.d.ts +17 -0
- package/dist/testing/fixtures/application-test-fixtures.js +230 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.js +5 -0
- package/dist/testing/testing.interface.d.ts +96 -0
- package/dist/testing/testing.interface.js +1 -0
- package/dist/types/constructor.type.d.ts +12 -0
- package/dist/types/constructor.type.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/common.util.d.ts +117 -0
- package/dist/utils/common.util.js +140 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { HONEST_PIPELINE_BODY_CACHE_KEY } from '../constants';
|
|
2
|
+
import { createParamDecorator } from '../helpers';
|
|
3
|
+
/**
|
|
4
|
+
* Decorator that binds the request body to a parameter
|
|
5
|
+
* @param data - Optional property name to extract from the body
|
|
6
|
+
*/
|
|
7
|
+
export const Body = createParamDecorator('body', async (data, ctx) => {
|
|
8
|
+
let body = ctx.get(HONEST_PIPELINE_BODY_CACHE_KEY);
|
|
9
|
+
if (body === undefined) {
|
|
10
|
+
body = await ctx.req.json();
|
|
11
|
+
ctx.set(HONEST_PIPELINE_BODY_CACHE_KEY, body);
|
|
12
|
+
}
|
|
13
|
+
if (data && body && typeof body === 'object') {
|
|
14
|
+
return body[String(data)];
|
|
15
|
+
}
|
|
16
|
+
return body;
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Decorator that binds a route parameter to a parameter
|
|
20
|
+
* @param data - The parameter name in the route
|
|
21
|
+
*/
|
|
22
|
+
export const Param = createParamDecorator('param', (data, ctx) => {
|
|
23
|
+
return data ? ctx.req.param(String(data)) : ctx.req.param();
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Decorator that binds a query parameter to a parameter
|
|
27
|
+
* @param data - The query parameter name
|
|
28
|
+
*/
|
|
29
|
+
export const Query = createParamDecorator('query', (data, ctx) => {
|
|
30
|
+
return data ? ctx.req.query(String(data)) : ctx.req.query();
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Decorator that binds a header value to a parameter
|
|
34
|
+
* @param data - The header name
|
|
35
|
+
*/
|
|
36
|
+
export const Header = createParamDecorator('header', (data, ctx) => {
|
|
37
|
+
return data ? ctx.req.header(String(data)) : ctx.req.header();
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Decorator that binds the request object to a parameter
|
|
41
|
+
*/
|
|
42
|
+
export const Req = createParamDecorator('request', (_, ctx) => ctx.req);
|
|
43
|
+
export const Request = createParamDecorator('request', (_, ctx) => ctx.req);
|
|
44
|
+
/**
|
|
45
|
+
* Decorator that binds the response object to a parameter
|
|
46
|
+
*/
|
|
47
|
+
export const Res = createParamDecorator('response', (_, ctx) => ctx.res);
|
|
48
|
+
export const Response = createParamDecorator('response', (_, ctx) => ctx.res);
|
|
49
|
+
/**
|
|
50
|
+
* Decorator that binds the context object to a parameter
|
|
51
|
+
*/
|
|
52
|
+
export const Ctx = createParamDecorator('context', (_, ctx) => ctx);
|
|
53
|
+
export const Context = createParamDecorator('context', (_, ctx) => ctx);
|
|
54
|
+
/**
|
|
55
|
+
* Decorator that binds a context variable to a parameter
|
|
56
|
+
* @param data - The variable name to retrieve from context
|
|
57
|
+
*/
|
|
58
|
+
export const Var = createParamDecorator('variable', (data, ctx) => data === undefined ? undefined : ctx.get(String(data)));
|
|
59
|
+
export const Variable = createParamDecorator('variable', (data, ctx) => data === undefined ? undefined : ctx.get(String(data)));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MetadataRegistry } from '../registries';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that marks a class as a service
|
|
4
|
+
* Services are singleton classes that can be injected as dependencies
|
|
5
|
+
* @returns A class decorator function
|
|
6
|
+
*/
|
|
7
|
+
export function Service() {
|
|
8
|
+
return (target) => {
|
|
9
|
+
MetadataRegistry.addService(target);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ComponentType, ComponentTypeMap } from '../registries';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Generic decorator that applies components of a specific type to a controller class or method
|
|
5
|
+
* @template T - The type of component being applied
|
|
6
|
+
* @param type - The component type identifier
|
|
7
|
+
* @param components - Array of components to apply
|
|
8
|
+
* @returns A decorator function that can be used at class or method level
|
|
9
|
+
*/
|
|
10
|
+
export declare function UseComponent<T extends ComponentType>(type: T, ...components: ComponentTypeMap[T][]): (target: Constructor | object, propertyKey?: string | symbol) => void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MetadataRegistry } from '../registries';
|
|
2
|
+
/**
|
|
3
|
+
* Generic decorator that applies components of a specific type to a controller class or method
|
|
4
|
+
* @template T - The type of component being applied
|
|
5
|
+
* @param type - The component type identifier
|
|
6
|
+
* @param components - Array of components to apply
|
|
7
|
+
* @returns A decorator function that can be used at class or method level
|
|
8
|
+
*/
|
|
9
|
+
export function UseComponent(type, ...components) {
|
|
10
|
+
return (target, propertyKey) => {
|
|
11
|
+
if (propertyKey) {
|
|
12
|
+
const controllerClass = target.constructor;
|
|
13
|
+
components.forEach((component) => MetadataRegistry.registerHandler(type, controllerClass, propertyKey, component));
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
components.forEach((component) => MetadataRegistry.registerController(type, target, component));
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FilterType } from '../interfaces';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Decorator that applies exception filters to a controller class or method
|
|
5
|
+
* @param filters - Array of exception filters to apply
|
|
6
|
+
* @returns A decorator function that can be used at class or method level
|
|
7
|
+
*/
|
|
8
|
+
export declare function UseFilters(...filters: FilterType[]): (target: Constructor | object, propertyKey?: string | symbol) => void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MetadataRegistry } from '../registries';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that applies exception filters to a controller class or method
|
|
4
|
+
* @param filters - Array of exception filters to apply
|
|
5
|
+
* @returns A decorator function that can be used at class or method level
|
|
6
|
+
*/
|
|
7
|
+
export function UseFilters(...filters) {
|
|
8
|
+
return (target, propertyKey) => {
|
|
9
|
+
if (propertyKey) {
|
|
10
|
+
const controllerClass = target.constructor;
|
|
11
|
+
filters.forEach((filter) => MetadataRegistry.registerHandler('filter', controllerClass, propertyKey, filter));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
filters.forEach((filter) => MetadataRegistry.registerController('filter', target, filter));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GuardType } from '../interfaces';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Decorator that applies guards to a controller class or method
|
|
5
|
+
* Guards determine whether a request should be handled by the route handler
|
|
6
|
+
* @param guards - Array of guards to apply
|
|
7
|
+
* @returns A decorator function that can be used at class or method level
|
|
8
|
+
*/
|
|
9
|
+
export declare function UseGuards(...guards: GuardType[]): (target: Constructor | object, propertyKey?: string | symbol) => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MetadataRegistry } from '../registries';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that applies guards to a controller class or method
|
|
4
|
+
* Guards determine whether a request should be handled by the route handler
|
|
5
|
+
* @param guards - Array of guards to apply
|
|
6
|
+
* @returns A decorator function that can be used at class or method level
|
|
7
|
+
*/
|
|
8
|
+
export function UseGuards(...guards) {
|
|
9
|
+
return (target, propertyKey) => {
|
|
10
|
+
if (propertyKey) {
|
|
11
|
+
const controllerClass = target.constructor;
|
|
12
|
+
guards.forEach((guard) => MetadataRegistry.registerHandler('guard', controllerClass, propertyKey, guard));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
guards.forEach((guard) => MetadataRegistry.registerController('guard', target, guard));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MiddlewareType } from '../interfaces';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Decorator that applies middleware to a controller class or method
|
|
5
|
+
* Middleware functions run before the route handler and can modify the request/response
|
|
6
|
+
* @param middleware - Array of middleware functions to apply
|
|
7
|
+
* @returns A decorator function that can be used at class or method level
|
|
8
|
+
*/
|
|
9
|
+
export declare function UseMiddleware(...middleware: MiddlewareType[]): (target: Constructor | object, propertyKey?: string | symbol) => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MetadataRegistry } from '../registries';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that applies middleware to a controller class or method
|
|
4
|
+
* Middleware functions run before the route handler and can modify the request/response
|
|
5
|
+
* @param middleware - Array of middleware functions to apply
|
|
6
|
+
* @returns A decorator function that can be used at class or method level
|
|
7
|
+
*/
|
|
8
|
+
export function UseMiddleware(...middleware) {
|
|
9
|
+
return (target, propertyKey) => {
|
|
10
|
+
if (propertyKey) {
|
|
11
|
+
const controllerClass = target.constructor;
|
|
12
|
+
middleware.forEach((mw) => MetadataRegistry.registerHandler('middleware', controllerClass, propertyKey, mw));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
middleware.forEach((mw) => MetadataRegistry.registerController('middleware', target, mw));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PipeType } from '../interfaces';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Decorator that applies transformation pipes to a controller class or method
|
|
5
|
+
* Pipes transform input data before it reaches the route handler
|
|
6
|
+
* @param pipes - Array of pipes to apply
|
|
7
|
+
* @returns A decorator function that can be used at class or method level
|
|
8
|
+
*/
|
|
9
|
+
export declare function UsePipes(...pipes: PipeType[]): (target: Constructor | object, propertyKey?: string | symbol) => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MetadataRegistry } from '../registries';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that applies transformation pipes to a controller class or method
|
|
4
|
+
* Pipes transform input data before it reaches the route handler
|
|
5
|
+
* @param pipes - Array of pipes to apply
|
|
6
|
+
* @returns A decorator function that can be used at class or method level
|
|
7
|
+
*/
|
|
8
|
+
export function UsePipes(...pipes) {
|
|
9
|
+
return (target, propertyKey) => {
|
|
10
|
+
if (propertyKey) {
|
|
11
|
+
const controllerClass = target.constructor;
|
|
12
|
+
pipes.forEach((pipe) => MetadataRegistry.registerHandler('pipe', controllerClass, propertyKey, pipe));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
pipes.forEach((pipe) => MetadataRegistry.registerController('pipe', target, pipe));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DiContainer, ILogger, IServiceRegistry } from '../interfaces';
|
|
2
|
+
import type { Constructor } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Dependency Injection container that manages class instances and their dependencies
|
|
5
|
+
*/
|
|
6
|
+
export declare class Container implements DiContainer {
|
|
7
|
+
private readonly serviceRegistry;
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private readonly debugDi;
|
|
10
|
+
constructor(serviceRegistry?: IServiceRegistry, logger?: ILogger, debugDi?: boolean);
|
|
11
|
+
/**
|
|
12
|
+
* Map of class constructors to their instances
|
|
13
|
+
*/
|
|
14
|
+
private instances;
|
|
15
|
+
private emitLog;
|
|
16
|
+
/**
|
|
17
|
+
* Resolves a class instance, creating it if necessary and injecting its dependencies
|
|
18
|
+
* @param target - The class constructor to resolve
|
|
19
|
+
* @returns An instance of the target class
|
|
20
|
+
*/
|
|
21
|
+
resolve<T>(target: Constructor<T>): T;
|
|
22
|
+
/**
|
|
23
|
+
* Internal recursive resolver with circular dependency tracking
|
|
24
|
+
*/
|
|
25
|
+
private resolveWithTracking;
|
|
26
|
+
/**
|
|
27
|
+
* Registers a pre-created instance for a class
|
|
28
|
+
* @param target - The class constructor to register
|
|
29
|
+
* @param instance - The instance to register
|
|
30
|
+
*/
|
|
31
|
+
register<T>(target: Constructor<T>, instance: T): void;
|
|
32
|
+
has<T>(target: Constructor<T>): boolean;
|
|
33
|
+
clear(): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { NoopLogger } from '../loggers';
|
|
2
|
+
import { StaticServiceRegistry } from '../registries';
|
|
3
|
+
/**
|
|
4
|
+
* Dependency Injection container that manages class instances and their dependencies
|
|
5
|
+
*/
|
|
6
|
+
export class Container {
|
|
7
|
+
serviceRegistry;
|
|
8
|
+
logger;
|
|
9
|
+
debugDi;
|
|
10
|
+
constructor(serviceRegistry = new StaticServiceRegistry(), logger = new NoopLogger(), debugDi = false) {
|
|
11
|
+
this.serviceRegistry = serviceRegistry;
|
|
12
|
+
this.logger = logger;
|
|
13
|
+
this.debugDi = debugDi;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Map of class constructors to their instances
|
|
17
|
+
*/
|
|
18
|
+
instances = new Map();
|
|
19
|
+
emitLog(event) {
|
|
20
|
+
if (!this.debugDi) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.logger.emit(event);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolves a class instance, creating it if necessary and injecting its dependencies
|
|
27
|
+
* @param target - The class constructor to resolve
|
|
28
|
+
* @returns An instance of the target class
|
|
29
|
+
*/
|
|
30
|
+
resolve(target) {
|
|
31
|
+
return this.resolveWithTracking(target, new Set());
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Internal recursive resolver with circular dependency tracking
|
|
35
|
+
*/
|
|
36
|
+
resolveWithTracking(target, resolving) {
|
|
37
|
+
if (this.instances.has(target)) {
|
|
38
|
+
this.emitLog({
|
|
39
|
+
level: 'debug',
|
|
40
|
+
category: 'di',
|
|
41
|
+
message: `Resolved ${target.name} from DI cache`
|
|
42
|
+
});
|
|
43
|
+
return this.instances.get(target);
|
|
44
|
+
}
|
|
45
|
+
if (resolving.has(target)) {
|
|
46
|
+
const cycle = [...resolving.keys(), target].map((t) => t.name).join(' -> ');
|
|
47
|
+
this.emitLog({
|
|
48
|
+
level: 'error',
|
|
49
|
+
category: 'di',
|
|
50
|
+
message: `Circular dependency detected while resolving ${target.name}`,
|
|
51
|
+
details: { cycle }
|
|
52
|
+
});
|
|
53
|
+
throw new Error(`Circular dependency detected: ${cycle}`);
|
|
54
|
+
}
|
|
55
|
+
resolving.add(target);
|
|
56
|
+
this.emitLog({
|
|
57
|
+
level: 'debug',
|
|
58
|
+
category: 'di',
|
|
59
|
+
message: `Resolving ${target.name}`,
|
|
60
|
+
details: { resolving: [...resolving].map((constructor) => constructor.name) }
|
|
61
|
+
});
|
|
62
|
+
const paramTypes = Reflect.getMetadata('design:paramtypes', target) || [];
|
|
63
|
+
if (target.length > 0 && paramTypes.length === 0) {
|
|
64
|
+
if (!this.serviceRegistry.isService(target)) {
|
|
65
|
+
this.emitLog({
|
|
66
|
+
level: 'error',
|
|
67
|
+
category: 'di',
|
|
68
|
+
message: `Cannot resolve ${target.name}: missing @Service() decorator`
|
|
69
|
+
});
|
|
70
|
+
throw new Error(`Cannot resolve ${target.name}: it is not decorated with @Service(). Did you forget to add @Service() to the class?`);
|
|
71
|
+
}
|
|
72
|
+
this.emitLog({
|
|
73
|
+
level: 'error',
|
|
74
|
+
category: 'di',
|
|
75
|
+
message: `Cannot resolve ${target.name}: missing constructor metadata`
|
|
76
|
+
});
|
|
77
|
+
throw new Error(`Cannot resolve dependencies for ${target.name}: constructor metadata is missing. Ensure 'reflect-metadata' is imported and 'emitDecoratorMetadata' is enabled.`);
|
|
78
|
+
}
|
|
79
|
+
const dependencies = paramTypes.map((paramType, index) => {
|
|
80
|
+
if (!paramType || paramType === Object || paramType === Array || paramType === Function) {
|
|
81
|
+
this.emitLog({
|
|
82
|
+
level: 'error',
|
|
83
|
+
category: 'di',
|
|
84
|
+
message: `Cannot resolve dependency at index ${index} of ${target.name}`
|
|
85
|
+
});
|
|
86
|
+
throw new Error(`Cannot resolve dependency at index ${index} of ${target.name}. Use concrete class types for constructor dependencies.`);
|
|
87
|
+
}
|
|
88
|
+
return this.resolveWithTracking(paramType, new Set(resolving));
|
|
89
|
+
});
|
|
90
|
+
const instance = new target(...dependencies);
|
|
91
|
+
this.instances.set(target, instance);
|
|
92
|
+
this.emitLog({
|
|
93
|
+
level: 'debug',
|
|
94
|
+
category: 'di',
|
|
95
|
+
message: `Created ${target.name} instance`,
|
|
96
|
+
details: { dependencyCount: dependencies.length }
|
|
97
|
+
});
|
|
98
|
+
return instance;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Registers a pre-created instance for a class
|
|
102
|
+
* @param target - The class constructor to register
|
|
103
|
+
* @param instance - The instance to register
|
|
104
|
+
*/
|
|
105
|
+
register(target, instance) {
|
|
106
|
+
this.instances.set(target, instance);
|
|
107
|
+
}
|
|
108
|
+
has(target) {
|
|
109
|
+
return this.instances.has(target);
|
|
110
|
+
}
|
|
111
|
+
clear() {
|
|
112
|
+
this.instances.clear();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './container';
|
package/dist/di/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './container';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FrameworkErrorOptions {
|
|
2
|
+
status?: number;
|
|
3
|
+
code: string;
|
|
4
|
+
category: string;
|
|
5
|
+
remediation?: string;
|
|
6
|
+
details?: Record<string, unknown>;
|
|
7
|
+
cause?: unknown;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Structured framework-level error with machine-readable metadata.
|
|
11
|
+
*/
|
|
12
|
+
export declare class FrameworkError extends Error {
|
|
13
|
+
readonly status?: number;
|
|
14
|
+
readonly code: string;
|
|
15
|
+
readonly category: string;
|
|
16
|
+
readonly remediation?: string;
|
|
17
|
+
readonly details?: Record<string, unknown>;
|
|
18
|
+
constructor(message: string, options: FrameworkErrorOptions);
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured framework-level error with machine-readable metadata.
|
|
3
|
+
*/
|
|
4
|
+
export class FrameworkError extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
category;
|
|
8
|
+
remediation;
|
|
9
|
+
details;
|
|
10
|
+
constructor(message, options) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'FrameworkError';
|
|
13
|
+
this.status = options.status;
|
|
14
|
+
this.code = options.code;
|
|
15
|
+
this.category = options.category;
|
|
16
|
+
this.remediation = options.remediation;
|
|
17
|
+
this.details = options.details;
|
|
18
|
+
if (options.cause !== undefined) {
|
|
19
|
+
;
|
|
20
|
+
this.cause = options.cause;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './framework.error';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './framework.error';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Handler for managing application-wide error responses
|
|
4
|
+
* Provides a consistent way to handle and format error responses across the application
|
|
5
|
+
*/
|
|
6
|
+
export declare class ErrorHandler {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a middleware function that handles error responses
|
|
9
|
+
* @returns A middleware function that formats and returns error responses using createErrorResponse
|
|
10
|
+
*/
|
|
11
|
+
static handle(): (err: unknown, c: Context) => Promise<Response & import("hono").TypedResponse<{
|
|
12
|
+
status: number;
|
|
13
|
+
message: string;
|
|
14
|
+
timestamp: string;
|
|
15
|
+
path: string;
|
|
16
|
+
requestId?: string | undefined;
|
|
17
|
+
code?: string | undefined;
|
|
18
|
+
details?: {
|
|
19
|
+
[x: string]: any;
|
|
20
|
+
} | undefined;
|
|
21
|
+
errors?: {
|
|
22
|
+
property: string;
|
|
23
|
+
constraints: {
|
|
24
|
+
[x: string]: string;
|
|
25
|
+
};
|
|
26
|
+
}[] | undefined;
|
|
27
|
+
}, -1 | 100 | 102 | 103 | 200 | 201 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "json">>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createErrorResponse } from '../helpers';
|
|
2
|
+
/**
|
|
3
|
+
* Handler for managing application-wide error responses
|
|
4
|
+
* Provides a consistent way to handle and format error responses across the application
|
|
5
|
+
*/
|
|
6
|
+
export class ErrorHandler {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a middleware function that handles error responses
|
|
9
|
+
* @returns A middleware function that formats and returns error responses using createErrorResponse
|
|
10
|
+
*/
|
|
11
|
+
static handle() {
|
|
12
|
+
return async (err, c) => {
|
|
13
|
+
const { response, status } = createErrorResponse(err, c);
|
|
14
|
+
return c.json(response, status);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Handler for managing 404 Not Found responses
|
|
4
|
+
* Provides a consistent way to handle requests to non-existent routes
|
|
5
|
+
*/
|
|
6
|
+
export declare class NotFoundHandler {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a middleware function that handles 404 Not Found responses
|
|
9
|
+
* @returns A middleware function that returns a JSON response with a 404 status
|
|
10
|
+
*/
|
|
11
|
+
static handle(): (c: Context) => Promise<Response & import("hono").TypedResponse<{
|
|
12
|
+
message: string;
|
|
13
|
+
}, 404, "json">>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for managing 404 Not Found responses
|
|
3
|
+
* Provides a consistent way to handle requests to non-existent routes
|
|
4
|
+
*/
|
|
5
|
+
export class NotFoundHandler {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a middleware function that handles 404 Not Found responses
|
|
8
|
+
* @returns A middleware function that returns a JSON response with a 404 status
|
|
9
|
+
*/
|
|
10
|
+
static handle() {
|
|
11
|
+
return async (c) => {
|
|
12
|
+
return c.json({
|
|
13
|
+
message: `Not Found - ${c.req.path}`
|
|
14
|
+
}, 404);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import type { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
3
|
+
import type { ErrorResponse } from '../interfaces';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a standardized error response object
|
|
6
|
+
* @param exception - The error or exception object to process
|
|
7
|
+
* @param context - The Hono context object containing request information
|
|
8
|
+
* @param options - Optional configuration for the error response
|
|
9
|
+
* @param options.status - HTTP status code to override the default
|
|
10
|
+
* @param options.title - Custom error message to override the default
|
|
11
|
+
* @param options.detail - Additional error details
|
|
12
|
+
* @param options.code - Custom error code
|
|
13
|
+
* @param options.additionalDetails - Extra information to include in the response
|
|
14
|
+
* @returns Object containing the formatted error response and HTTP status code
|
|
15
|
+
*/
|
|
16
|
+
export declare function createErrorResponse(exception: unknown, context: Context, options?: {
|
|
17
|
+
status?: number;
|
|
18
|
+
title?: string;
|
|
19
|
+
detail?: string;
|
|
20
|
+
code?: string;
|
|
21
|
+
additionalDetails?: Record<string, unknown>;
|
|
22
|
+
}): {
|
|
23
|
+
response: ErrorResponse;
|
|
24
|
+
status: ContentfulStatusCode;
|
|
25
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { HTTPException } from 'hono/http-exception';
|
|
2
|
+
import { FrameworkError } from '../errors';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a standardized error response object
|
|
5
|
+
* @param exception - The error or exception object to process
|
|
6
|
+
* @param context - The Hono context object containing request information
|
|
7
|
+
* @param options - Optional configuration for the error response
|
|
8
|
+
* @param options.status - HTTP status code to override the default
|
|
9
|
+
* @param options.title - Custom error message to override the default
|
|
10
|
+
* @param options.detail - Additional error details
|
|
11
|
+
* @param options.code - Custom error code
|
|
12
|
+
* @param options.additionalDetails - Extra information to include in the response
|
|
13
|
+
* @returns Object containing the formatted error response and HTTP status code
|
|
14
|
+
*/
|
|
15
|
+
export function createErrorResponse(exception, context, options) {
|
|
16
|
+
const normalizedException = exception instanceof Error ? exception : new Error(String(exception));
|
|
17
|
+
const timestamp = new Date().toISOString();
|
|
18
|
+
const requestId = context.get('requestId');
|
|
19
|
+
const path = context.req.path;
|
|
20
|
+
// Handle HTTPException (Hono's built-in exception)
|
|
21
|
+
if (normalizedException instanceof HTTPException) {
|
|
22
|
+
const response = {
|
|
23
|
+
status: options?.status || normalizedException.status,
|
|
24
|
+
message: options?.title || normalizedException.message,
|
|
25
|
+
timestamp,
|
|
26
|
+
path,
|
|
27
|
+
requestId,
|
|
28
|
+
code: options?.code,
|
|
29
|
+
details: options?.additionalDetails,
|
|
30
|
+
...(options?.detail && { detail: options.detail })
|
|
31
|
+
};
|
|
32
|
+
return { response, status: (options?.status || normalizedException.status) };
|
|
33
|
+
}
|
|
34
|
+
if (normalizedException instanceof FrameworkError) {
|
|
35
|
+
const status = (options?.status || normalizedException.status || 500);
|
|
36
|
+
const response = {
|
|
37
|
+
status,
|
|
38
|
+
message: options?.title || normalizedException.message,
|
|
39
|
+
timestamp,
|
|
40
|
+
path,
|
|
41
|
+
requestId,
|
|
42
|
+
code: options?.code || normalizedException.code,
|
|
43
|
+
details: {
|
|
44
|
+
category: normalizedException.category,
|
|
45
|
+
remediation: normalizedException.remediation,
|
|
46
|
+
...normalizedException.details,
|
|
47
|
+
...options?.additionalDetails
|
|
48
|
+
},
|
|
49
|
+
...(options?.detail && { detail: options.detail })
|
|
50
|
+
};
|
|
51
|
+
return { response, status };
|
|
52
|
+
}
|
|
53
|
+
// Combined status handling
|
|
54
|
+
if (normalizedException.statusCode ||
|
|
55
|
+
normalizedException.status) {
|
|
56
|
+
const defaultStatus = normalizedException.statusCode ||
|
|
57
|
+
normalizedException.status ||
|
|
58
|
+
500;
|
|
59
|
+
const status = options?.status || defaultStatus;
|
|
60
|
+
const response = {
|
|
61
|
+
status,
|
|
62
|
+
message: options?.title || normalizedException.message,
|
|
63
|
+
timestamp,
|
|
64
|
+
path,
|
|
65
|
+
requestId,
|
|
66
|
+
code: options?.code || normalizedException.name,
|
|
67
|
+
details: options?.additionalDetails,
|
|
68
|
+
...(options?.detail && { detail: options.detail })
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
response,
|
|
72
|
+
status: status
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Handle unexpected errors
|
|
76
|
+
const status = (options?.status || 500);
|
|
77
|
+
const response = {
|
|
78
|
+
status,
|
|
79
|
+
message: options?.title ||
|
|
80
|
+
(process.env.NODE_ENV === 'production' ? 'Internal Server Error' : normalizedException.message),
|
|
81
|
+
timestamp,
|
|
82
|
+
path,
|
|
83
|
+
requestId,
|
|
84
|
+
code: options?.code || normalizedException.name,
|
|
85
|
+
details: options?.additionalDetails ||
|
|
86
|
+
(process.env.NODE_ENV === 'development' ? { stack: normalizedException.stack } : undefined),
|
|
87
|
+
...(options?.detail && { detail: options.detail })
|
|
88
|
+
};
|
|
89
|
+
return { response, status };
|
|
90
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HttpMethodOptions } from '../interfaces';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a decorator factory for HTTP method handlers
|
|
4
|
+
* @param method - The HTTP method type (GET, POST, PUT, etc.)
|
|
5
|
+
* @returns A method decorator factory that accepts a path and options
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const Get = createHttpMethodDecorator(HttpMethod.GET);
|
|
9
|
+
*
|
|
10
|
+
* class Controller {
|
|
11
|
+
* @Get('/users')
|
|
12
|
+
* getUsers() { }
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function createHttpMethodDecorator(method: string): (path?: string, options?: HttpMethodOptions) => MethodDecorator;
|