@ajke/core 0.1.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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -0
  3. package/dist/chunk-AT2R2CGV.js +234 -0
  4. package/dist/chunk-AT2R2CGV.js.map +1 -0
  5. package/dist/chunk-EUXUH3YW.js +15 -0
  6. package/dist/chunk-EUXUH3YW.js.map +1 -0
  7. package/dist/chunk-YUBEJL4T.cjs +234 -0
  8. package/dist/chunk-YUBEJL4T.cjs.map +1 -0
  9. package/dist/chunk-ZBDE64SD.cjs +15 -0
  10. package/dist/chunk-ZBDE64SD.cjs.map +1 -0
  11. package/dist/config.cjs +10 -0
  12. package/dist/config.cjs.map +1 -0
  13. package/dist/config.d.cts +13 -0
  14. package/dist/config.d.ts +13 -0
  15. package/dist/config.js +10 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/index.cjs +974 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.cts +255 -0
  20. package/dist/index.d.ts +255 -0
  21. package/dist/index.js +974 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/middleware/index.cjs +10 -0
  24. package/dist/middleware/index.cjs.map +1 -0
  25. package/dist/middleware/index.d.cts +18 -0
  26. package/dist/middleware/index.d.ts +18 -0
  27. package/dist/middleware/index.js +10 -0
  28. package/dist/middleware/index.js.map +1 -0
  29. package/package.json +56 -0
  30. package/src/README.md +285 -0
  31. package/src/config.ts +14 -0
  32. package/src/context/execution-context.ts +36 -0
  33. package/src/context/index.ts +1 -0
  34. package/src/decorators/core/exception-filters.decorator.ts +24 -0
  35. package/src/decorators/core/index.ts +6 -0
  36. package/src/decorators/core/injectable.decorator.ts +41 -0
  37. package/src/decorators/core/optional.decorator.ts +9 -0
  38. package/src/decorators/core/set-metadata.decorator.ts +20 -0
  39. package/src/decorators/core/use-guards.decorator.ts +14 -0
  40. package/src/decorators/core/use-interceptors.decorator.ts +16 -0
  41. package/src/decorators/http/controller.decorator.ts +230 -0
  42. package/src/decorators/http/header.decorator.ts +11 -0
  43. package/src/decorators/http/http-code.decorator.ts +8 -0
  44. package/src/decorators/http/index.ts +6 -0
  45. package/src/decorators/http/redirect.decorator.ts +13 -0
  46. package/src/decorators/http/route-mapping.decorator.ts +22 -0
  47. package/src/decorators/http/route-params.decorator.ts +60 -0
  48. package/src/decorators/index.ts +3 -0
  49. package/src/decorators/modules/global.decorator.ts +8 -0
  50. package/src/decorators/modules/index.ts +2 -0
  51. package/src/decorators/modules/module.decorator.ts +16 -0
  52. package/src/exceptions/http-exception.ts +17 -0
  53. package/src/exceptions/http-exceptions.ts +85 -0
  54. package/src/exceptions/index.ts +2 -0
  55. package/src/index.ts +11 -0
  56. package/src/injector/index.ts +1 -0
  57. package/src/injector/injector.ts +103 -0
  58. package/src/injector/module-compiler.ts +48 -0
  59. package/src/injector/module.factory.ts +74 -0
  60. package/src/interfaces/core/filter.interface.ts +5 -0
  61. package/src/interfaces/core/guard.interface.ts +5 -0
  62. package/src/interfaces/core/index.ts +5 -0
  63. package/src/interfaces/core/interceptor.interface.ts +9 -0
  64. package/src/interfaces/core/lifecycle.interface.ts +19 -0
  65. package/src/interfaces/core/pipe.interface.ts +9 -0
  66. package/src/interfaces/http/index.ts +1 -0
  67. package/src/interfaces/http/response.interface.ts +27 -0
  68. package/src/interfaces/index.ts +3 -0
  69. package/src/interfaces/modules/index.ts +1 -0
  70. package/src/interfaces/modules/module.interface.ts +17 -0
  71. package/src/middleware/error-handler.middleware.ts +63 -0
  72. package/src/middleware/index.ts +2 -0
  73. package/src/middleware/request-logger.middleware.ts +17 -0
  74. package/src/pipes/index.ts +3 -0
  75. package/src/pipes/validate.pipe.ts +79 -0
  76. package/src/pipes/zod-query.pipe.ts +42 -0
  77. package/src/pipes/zod-validate.pipe.ts +49 -0
  78. package/src/services/index.ts +1 -0
  79. package/src/services/reflector.service.ts +24 -0
  80. package/src/utils/apply-decorators.util.ts +17 -0
  81. package/src/utils/forward-ref.util.ts +14 -0
  82. package/src/utils/index.ts +22 -0
  83. package/src/utils/logger.util.ts +189 -0
  84. package/src/utils/response.util.ts +72 -0
@@ -0,0 +1,103 @@
1
+ import { INJECT_CUSTOM_TOKENS_KEY } from "../decorators/core/injectable.decorator";
2
+ import { OPTIONAL_METADATA } from "../decorators/core/optional.decorator";
3
+ import { isForwardRef } from "../utils/forward-ref.util";
4
+ import { logger } from "../utils/logger.util";
5
+
6
+ function createCircularProxy(registry: Map<any, any>, tokenClass: any): any {
7
+ return new Proxy(
8
+ {},
9
+ {
10
+ get(_target, prop) {
11
+ const instance = registry.get(tokenClass);
12
+ if (!instance) {
13
+ throw new Error(
14
+ `[Wilt DI] Circular dependency proxy for "${tokenClass.name}" ` +
15
+ `was accessed before the real instance was created. ` +
16
+ `Make sure both sides use @Inject(forwardRef(() => ...)).`
17
+ );
18
+ }
19
+ const val = (instance as any)[prop];
20
+ return typeof val === "function" ? val.bind(instance) : val;
21
+ },
22
+ set(_target, prop, value) {
23
+ const instance = registry.get(tokenClass);
24
+ if (instance) (instance as any)[prop] = value;
25
+ return true;
26
+ },
27
+ }
28
+ );
29
+ }
30
+
31
+ export function resolveInstance(
32
+ ProviderClass: any,
33
+ instanceRegistry: Map<any, any>,
34
+ inProgress: Set<any>
35
+ ): any {
36
+ if (instanceRegistry.has(ProviderClass)) {
37
+ return instanceRegistry.get(ProviderClass);
38
+ }
39
+
40
+ if (inProgress.has(ProviderClass)) {
41
+ logger.warn(
42
+ `Circular dependency detected for "${ProviderClass.name}". ` +
43
+ `Injecting a lazy proxy — ensure forwardRef() is used on both sides.`,
44
+ "ModuleFactory"
45
+ );
46
+ return createCircularProxy(instanceRegistry, ProviderClass);
47
+ }
48
+
49
+ inProgress.add(ProviderClass);
50
+
51
+ const paramTypes: any[] =
52
+ Reflect.getMetadata("design:paramtypes", ProviderClass) || [];
53
+ const customTokens: Record<number, any> =
54
+ Reflect.getMetadata(INJECT_CUSTOM_TOKENS_KEY, ProviderClass) || {};
55
+ const optionalIndices: number[] =
56
+ Reflect.getMetadata(OPTIONAL_METADATA, ProviderClass) || [];
57
+
58
+ const customIndices = Object.keys(customTokens).map(Number);
59
+ const paramCount = Math.max(
60
+ paramTypes.length,
61
+ customIndices.length > 0 ? Math.max(...customIndices) + 1 : 0
62
+ );
63
+
64
+ const deps = Array.from({ length: paramCount }, (_, i) => {
65
+ const customToken = customTokens[i];
66
+ const paramType = paramTypes[i];
67
+ const isOptional = optionalIndices.includes(i);
68
+
69
+ let actualClass: any;
70
+ if (customToken) {
71
+ actualClass = isForwardRef(customToken)
72
+ ? customToken.forwardRef()
73
+ : customToken;
74
+ } else {
75
+ actualClass = paramType;
76
+ }
77
+
78
+ if (!actualClass || actualClass === Object || actualClass === Function) {
79
+ if (!isOptional) {
80
+ logger.warn(
81
+ `Cannot resolve param[${i}] for "${ProviderClass.name}": ` +
82
+ `no type info. Use @Inject(TheClass) to specify it explicitly.`,
83
+ "ModuleFactory"
84
+ );
85
+ }
86
+ return undefined;
87
+ }
88
+
89
+ try {
90
+ return resolveInstance(actualClass, instanceRegistry, inProgress);
91
+ } catch (err) {
92
+ if (isOptional) return undefined;
93
+ throw err;
94
+ }
95
+ });
96
+
97
+ const instance = new ProviderClass(...deps);
98
+ instanceRegistry.set(ProviderClass, instance);
99
+ inProgress.delete(ProviderClass);
100
+
101
+ logger.debug(`Created instance: ${ProviderClass.name}`, "ModuleFactory");
102
+ return instance;
103
+ }
@@ -0,0 +1,48 @@
1
+ import { GLOBAL_MODULE_METADATA } from "../decorators/modules/global.decorator";
2
+ import { isForwardRef } from "../utils/forward-ref.util";
3
+
4
+ export function collectModuleTree(
5
+ moduleClass: any,
6
+ visiting: Set<any>,
7
+ visited: Set<any>,
8
+ controllers: any[],
9
+ providers: any[],
10
+ globalProviders: any[] = []
11
+ ): void {
12
+ if (visited.has(moduleClass)) return;
13
+
14
+ visiting.add(moduleClass);
15
+
16
+ const instance = new moduleClass();
17
+ const config = instance.moduleConfig || {};
18
+ const isGlobal = Reflect.getMetadata(GLOBAL_MODULE_METADATA, moduleClass) === true;
19
+
20
+ for (const c of config.controllers ?? []) {
21
+ if (!controllers.includes(c)) controllers.push(c);
22
+ }
23
+ for (const p of config.providers ?? []) {
24
+ if (!providers.includes(p)) providers.push(p);
25
+ if (isGlobal && !globalProviders.includes(p)) globalProviders.push(p);
26
+ }
27
+
28
+ for (const importRef of config.imports ?? []) {
29
+ const isRef = isForwardRef(importRef);
30
+ const ImportedClass = isRef ? importRef.forwardRef() : importRef;
31
+
32
+ if (visiting.has(ImportedClass)) {
33
+ if (!isRef) {
34
+ throw new Error(
35
+ `[Wilt DI] Circular module dependency detected: "${moduleClass.name}" imports "${ImportedClass.name}" ` +
36
+ `without forwardRef. Wrap it with forwardRef(() => ${ImportedClass.name}) ` +
37
+ `in "${moduleClass.name}" imports array, and do the same in "${ImportedClass.name}".`
38
+ );
39
+ }
40
+ continue;
41
+ }
42
+
43
+ collectModuleTree(ImportedClass, visiting, visited, controllers, providers, globalProviders);
44
+ }
45
+
46
+ visiting.delete(moduleClass);
47
+ visited.add(moduleClass);
48
+ }
@@ -0,0 +1,74 @@
1
+ import { Hono } from "hono";
2
+ import { registerControllerRoutes } from "../decorators/http/controller.decorator";
3
+ import { GLOBAL_MODULE_METADATA } from "../decorators/modules/global.decorator";
4
+ import { logger } from "../utils/logger.util";
5
+ import { collectModuleTree } from "./module-compiler";
6
+ import { resolveInstance } from "./injector";
7
+
8
+ export function createModule<B extends object = Record<string, unknown>>(
9
+ moduleClass: any,
10
+ { middlewares = [] }: { middlewares?: any[] } = {}
11
+ ): Hono<{ Bindings: B }> {
12
+ const router = new Hono<{ Bindings: B }>();
13
+
14
+ logger.info(`Creating module: ${moduleClass.name}`, "ModuleFactory");
15
+
16
+ middlewares.forEach((middleware) => router.use("*", middleware));
17
+
18
+ const controllers: any[] = [];
19
+ const providers: any[] = [];
20
+ const globalProviders: any[] = [];
21
+
22
+ collectModuleTree(moduleClass, new Set(), new Set(), controllers, providers, globalProviders);
23
+
24
+ logger.info(
25
+ `Resolved ${providers.length} providers, ${controllers.length} controllers`,
26
+ "ModuleFactory"
27
+ );
28
+
29
+ const instanceRegistry = new Map<any, any>();
30
+ const inProgress = new Set<any>();
31
+
32
+ // Global providers are resolved first so they're available to all modules
33
+ for (const ProviderClass of globalProviders) {
34
+ resolveInstance(ProviderClass, instanceRegistry, inProgress);
35
+ }
36
+
37
+ for (const ProviderClass of providers) {
38
+ resolveInstance(ProviderClass, instanceRegistry, inProgress);
39
+ }
40
+
41
+ for (const ControllerClass of controllers) {
42
+ try {
43
+ resolveInstance(ControllerClass, instanceRegistry, inProgress);
44
+ const controller = instanceRegistry.get(ControllerClass);
45
+ const prefix = (controller.constructor as any).prototype.prefix || "";
46
+ registerControllerRoutes(router, controller, prefix, instanceRegistry);
47
+ logger.debug(
48
+ `Registered controller: ${ControllerClass.name} at "${prefix}"`,
49
+ "ModuleFactory"
50
+ );
51
+ } catch (error) {
52
+ logger.error(
53
+ `Failed to create controller "${ControllerClass.name}": ${error}`,
54
+ "ModuleFactory"
55
+ );
56
+ throw error;
57
+ }
58
+ }
59
+
60
+ // Call onModuleInit on all instances that implement it
61
+ for (const instance of instanceRegistry.values()) {
62
+ if (typeof instance?.onModuleInit === "function") {
63
+ const result = instance.onModuleInit();
64
+ if (result instanceof Promise) {
65
+ result.catch((err) =>
66
+ logger.error(`onModuleInit failed for ${instance.constructor?.name}: ${err}`, "ModuleFactory")
67
+ );
68
+ }
69
+ }
70
+ }
71
+
72
+ logger.info(`Module "${moduleClass.name}" created successfully`, "ModuleFactory");
73
+ return router;
74
+ }
@@ -0,0 +1,5 @@
1
+ import type { ArgumentsHost } from "../../context/execution-context";
2
+
3
+ export interface ExceptionFilter<T = any> {
4
+ catch(exception: T, host: ArgumentsHost): Response | Promise<Response> | void;
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { ExecutionContext } from "../../context/execution-context";
2
+
3
+ export interface CanActivate {
4
+ canActivate(context: ExecutionContext): boolean | Promise<boolean>;
5
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./guard.interface";
2
+ export * from "./interceptor.interface";
3
+ export * from "./filter.interface";
4
+ export * from "./pipe.interface";
5
+ export * from "./lifecycle.interface";
@@ -0,0 +1,9 @@
1
+ import type { ExecutionContext } from "../../context/execution-context";
2
+
3
+ export interface CallHandler<T = any> {
4
+ handle(): Promise<T>;
5
+ }
6
+
7
+ export interface NestInterceptor<T = any, R = any> {
8
+ intercept(context: ExecutionContext, next: CallHandler<T>): Promise<R>;
9
+ }
@@ -0,0 +1,19 @@
1
+ export interface OnModuleInit {
2
+ onModuleInit(): void | Promise<void>;
3
+ }
4
+
5
+ export interface OnModuleDestroy {
6
+ onModuleDestroy(): void | Promise<void>;
7
+ }
8
+
9
+ export interface OnApplicationBootstrap {
10
+ onApplicationBootstrap(): void | Promise<void>;
11
+ }
12
+
13
+ export interface BeforeApplicationShutdown {
14
+ beforeApplicationShutdown(signal?: string): void | Promise<void>;
15
+ }
16
+
17
+ export interface OnApplicationShutdown {
18
+ onApplicationShutdown(signal?: string): void | Promise<void>;
19
+ }
@@ -0,0 +1,9 @@
1
+ export interface ArgumentMetadata {
2
+ type: "body" | "query" | "param" | "custom";
3
+ metatype?: new (...args: any[]) => any;
4
+ data?: string;
5
+ }
6
+
7
+ export interface PipeTransform<T = any, R = any> {
8
+ transform(value: T, metadata: ArgumentMetadata): R | Promise<R>;
9
+ }
@@ -0,0 +1 @@
1
+ export * from "./response.interface";
@@ -0,0 +1,27 @@
1
+ export type HttpStatusCode = 200 | 201 | 202 | 400 | 401 | 403 | 404 | 409 | 500;
2
+
3
+ export interface BaseResponse<T = any> {
4
+ success: boolean;
5
+ data?: T;
6
+ message?: string;
7
+ timestamp: string;
8
+ }
9
+
10
+ export interface PaginatedResponse<T = any> extends BaseResponse<T[]> {
11
+ pagination: {
12
+ page: number;
13
+ limit: number;
14
+ total: number;
15
+ totalPages: number;
16
+ };
17
+ }
18
+
19
+ export interface ErrorResponse {
20
+ success: false;
21
+ error: {
22
+ code: string;
23
+ message: string;
24
+ stack?: string;
25
+ };
26
+ timestamp: string;
27
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./http";
2
+ export * from "./modules";
3
+ export * from "./core";
@@ -0,0 +1 @@
1
+ export * from "./module.interface";
@@ -0,0 +1,17 @@
1
+ export interface ForwardReference<T = any> {
2
+ forwardRef: () => T;
3
+ }
4
+
5
+ export interface ModuleMetadata {
6
+ imports?: any[];
7
+ controllers?: any[];
8
+ providers?: any[];
9
+ exports?: any[];
10
+ entities?: any[];
11
+ }
12
+
13
+ export interface RouteMetadata {
14
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
15
+ path: string;
16
+ handler: string;
17
+ }
@@ -0,0 +1,63 @@
1
+ import type { Context, Next } from "hono";
2
+ import { HttpException } from "../exceptions/http-exception";
3
+
4
+ function isHttpException(err: unknown): err is HttpException {
5
+ return (
6
+ err instanceof HttpException ||
7
+ (err instanceof Error &&
8
+ typeof (err as any).getStatus === "function" &&
9
+ typeof (err as any).getResponse === "function")
10
+ );
11
+ }
12
+
13
+ function isZodError(err: unknown): err is Error & { issues: Array<{ path: (string | number)[]; message: string; code: string }> } {
14
+ return (
15
+ err instanceof Error &&
16
+ (err as any).name === "ZodError" &&
17
+ Array.isArray((err as any).issues)
18
+ );
19
+ }
20
+
21
+ export async function errorHandler(c: Context, next: Next) {
22
+ try {
23
+ await next();
24
+ } catch (error) {
25
+ if (isHttpException(error)) {
26
+ const response = error.getResponse();
27
+ const body =
28
+ typeof response === "string"
29
+ ? { success: false, error: { code: error.name, message: response }, timestamp: new Date().toISOString() }
30
+ : { success: false, ...response, timestamp: new Date().toISOString() };
31
+ return c.json(body, error.getStatus() as any);
32
+ }
33
+
34
+ if (isZodError(error)) {
35
+ const details = error.issues.map((i) => ({
36
+ field: i.path.join("."),
37
+ message: i.message,
38
+ code: i.code,
39
+ }));
40
+ return c.json(
41
+ {
42
+ success: false,
43
+ error: { code: "VALIDATION_ERROR", message: "Validation failed", details },
44
+ timestamp: new Date().toISOString(),
45
+ },
46
+ 400,
47
+ );
48
+ }
49
+
50
+ console.error("Unhandled error:", error);
51
+ return c.json(
52
+ {
53
+ success: false,
54
+ error: {
55
+ code: "INTERNAL_ERROR",
56
+ message: error instanceof Error ? error.message : "Internal server error",
57
+ },
58
+ timestamp: new Date().toISOString(),
59
+ },
60
+ 500
61
+ );
62
+ }
63
+ }
@@ -0,0 +1,2 @@
1
+ export { errorHandler } from "./error-handler.middleware";
2
+ export { requestLogger } from "./request-logger.middleware";
@@ -0,0 +1,17 @@
1
+ import type { Context, Next } from "hono";
2
+ import { logger } from "../utils/logger.util";
3
+
4
+ export async function requestLogger(c: Context, next: Next) {
5
+ const start = Date.now();
6
+ const method = c.req.method;
7
+ const path = c.req.path;
8
+ const userAgent = c.req.header("User-Agent");
9
+
10
+ await next();
11
+
12
+ const end = Date.now();
13
+ const duration = end - start;
14
+ const status = c.res.status;
15
+
16
+ logger.http(method, path, status, duration, userAgent);
17
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./validate.pipe";
2
+ export * from "./zod-validate.pipe";
3
+ export * from "./zod-query.pipe";
@@ -0,0 +1,79 @@
1
+ import type { Context } from "hono";
2
+
3
+ export interface ValidationRule {
4
+ field: string;
5
+ required?: boolean;
6
+ type?: "string" | "number" | "boolean" | "object" | "array";
7
+ minLength?: number;
8
+ maxLength?: number;
9
+ pattern?: RegExp;
10
+ custom?: (value: any) => boolean;
11
+ }
12
+
13
+ export function Validate(rules: ValidationRule[]) {
14
+ return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
15
+ const originalMethod = descriptor.value;
16
+
17
+ descriptor.value = async function (...args: any[]) {
18
+ const c: Context = args.find((a: any) => a != null && typeof a.json === "function" && a.req != null) ?? args[0];
19
+ const body = await c.req.json().catch(() => ({}));
20
+ const errors: string[] = [];
21
+
22
+ for (const rule of rules) {
23
+ const value = body[rule.field];
24
+
25
+ if (rule.required && (value === undefined || value === null || value === "")) {
26
+ errors.push(`${rule.field} is required`);
27
+ continue;
28
+ }
29
+
30
+ if (value === undefined || value === null) {
31
+ continue;
32
+ }
33
+
34
+ if (rule.type) {
35
+ const actualType = Array.isArray(value) ? "array" : typeof value;
36
+ if (actualType !== rule.type) {
37
+ errors.push(`${rule.field} must be of type ${rule.type}`);
38
+ }
39
+ }
40
+
41
+ if (rule.type === "string" || typeof value === "string") {
42
+ if (rule.minLength && value.length < rule.minLength) {
43
+ errors.push(`${rule.field} must be at least ${rule.minLength} characters long`);
44
+ }
45
+ if (rule.maxLength && value.length > rule.maxLength) {
46
+ errors.push(`${rule.field} must be at most ${rule.maxLength} characters long`);
47
+ }
48
+ }
49
+
50
+ if (rule.pattern && typeof value === "string" && !rule.pattern.test(value)) {
51
+ errors.push(`${rule.field} format is invalid`);
52
+ }
53
+
54
+ if (rule.custom && !rule.custom(value)) {
55
+ errors.push(`${rule.field} validation failed`);
56
+ }
57
+ }
58
+
59
+ if (errors.length > 0) {
60
+ return c.json(
61
+ {
62
+ success: false,
63
+ error: {
64
+ code: "VALIDATION_ERROR",
65
+ message: "Validation failed",
66
+ details: errors,
67
+ },
68
+ timestamp: new Date().toISOString(),
69
+ },
70
+ 400,
71
+ );
72
+ }
73
+
74
+ return originalMethod.call(this, ...args);
75
+ };
76
+
77
+ return descriptor;
78
+ };
79
+ }
@@ -0,0 +1,42 @@
1
+ import type { Context } from "hono";
2
+ import { z } from "zod";
3
+
4
+ export function QueryValidate(schema: z.ZodSchema) {
5
+ return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
6
+ const originalMethod = descriptor.value;
7
+
8
+ descriptor.value = async function (...args: any[]) {
9
+ const c: Context = args.find((a: any) => a != null && typeof a.json === "function" && a.req != null) ?? args[0];
10
+ try {
11
+ const queryParams = c.req.query();
12
+ const validatedData = schema.parse(queryParams);
13
+ c.set("validatedQuery", validatedData);
14
+ return originalMethod.call(this, ...args);
15
+ } catch (error) {
16
+ if (error instanceof z.ZodError) {
17
+ const errors = error.issues.map((err: z.ZodIssue) => ({
18
+ field: err.path.join("."),
19
+ message: err.message,
20
+ code: err.code,
21
+ }));
22
+ return c.json(
23
+ {
24
+ success: false,
25
+ error: {
26
+ code: "VALIDATION_ERROR",
27
+ message: "Query validation failed",
28
+ details: errors,
29
+ },
30
+ message: errors[0].message ?? "Validation failed",
31
+ timestamp: new Date().toISOString(),
32
+ },
33
+ 400,
34
+ );
35
+ }
36
+ throw error;
37
+ }
38
+ };
39
+
40
+ return descriptor;
41
+ };
42
+ }
@@ -0,0 +1,49 @@
1
+ import type { Context } from "hono";
2
+ import { z } from "zod";
3
+
4
+ export function ZodValidate(schema: z.ZodSchema) {
5
+ return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
6
+ const originalMethod = descriptor.value;
7
+
8
+ descriptor.value = async function (...args: any[]) {
9
+ const c: Context = args.find((a: any) => a != null && typeof a.json === "function" && a.req != null) ?? args[0];
10
+ try {
11
+ const contentType = c.req.header("content-type") || "";
12
+ let input: any = {};
13
+
14
+ if (contentType.includes("multipart/form-data")) {
15
+ const formData = await c.req.formData();
16
+ formData.forEach((val, key) => {
17
+ input[key] = val;
18
+ });
19
+ } else {
20
+ input = await c.req.json().catch(() => ({}));
21
+ }
22
+
23
+ const validatedData = schema.parse(input);
24
+ c.set("validatedData", validatedData);
25
+ return originalMethod.call(this, ...args);
26
+ } catch (error) {
27
+ if (error instanceof z.ZodError) {
28
+ const errors = error.issues.map((err) => ({
29
+ field: err.path.join("."),
30
+ message: err.message,
31
+ code: err.code,
32
+ }));
33
+ return c.json(
34
+ {
35
+ success: false,
36
+ error: { code: "VALIDATION_ERROR", message: "Validation failed", details: errors },
37
+ message: errors[0].message ?? "Validation failed",
38
+ timestamp: new Date().toISOString(),
39
+ },
40
+ 400,
41
+ );
42
+ }
43
+ throw error;
44
+ }
45
+ };
46
+
47
+ return descriptor;
48
+ };
49
+ }
@@ -0,0 +1 @@
1
+ export * from "./reflector.service";
@@ -0,0 +1,24 @@
1
+ import { Injectable } from "../decorators/core/injectable.decorator";
2
+
3
+ @Injectable()
4
+ export class Reflector {
5
+ get<T = any>(metadataKey: string, target: Function): T {
6
+ return Reflect.getMetadata(metadataKey, target) as T;
7
+ }
8
+
9
+ getAllAndOverride<T = any>(metadataKey: string, targets: Function[]): T {
10
+ for (const target of targets) {
11
+ const value = Reflect.getMetadata(metadataKey, target);
12
+ if (value !== undefined) return value as T;
13
+ }
14
+ return undefined as unknown as T;
15
+ }
16
+
17
+ getAllAndMerge<T extends any[] = any[]>(metadataKey: string, targets: Function[]): T {
18
+ return targets.reduce<any[]>((acc, target) => {
19
+ const value = Reflect.getMetadata(metadataKey, target);
20
+ if (Array.isArray(value)) return [...acc, ...value];
21
+ return acc;
22
+ }, []) as T;
23
+ }
24
+ }
@@ -0,0 +1,17 @@
1
+ export function applyDecorators(
2
+ ...decorators: (ClassDecorator | MethodDecorator | PropertyDecorator)[]
3
+ ): (...args: any[]) => any {
4
+ return (target: any, key?: any, descriptor?: any): any => {
5
+ for (const decorator of decorators.reverse()) {
6
+ const result = (decorator as any)(target, key, descriptor);
7
+ if (result !== undefined) {
8
+ if (descriptor !== undefined) {
9
+ descriptor = result as PropertyDescriptor;
10
+ } else {
11
+ target = result;
12
+ }
13
+ }
14
+ }
15
+ return descriptor ?? target;
16
+ };
17
+ }
@@ -0,0 +1,14 @@
1
+ import type { ForwardReference } from "../interfaces/modules/module.interface";
2
+
3
+ export function forwardRef<T = any>(fn: () => T): ForwardReference<T> {
4
+ return { forwardRef: fn };
5
+ }
6
+
7
+ export function isForwardRef(val: any): val is ForwardReference {
8
+ return (
9
+ val !== null &&
10
+ val !== undefined &&
11
+ typeof val === "object" &&
12
+ typeof val.forwardRef === "function"
13
+ );
14
+ }