honestjs 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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -0
  3. package/dist/application.d.ts +124 -0
  4. package/dist/constants/index.d.ts +1 -0
  5. package/dist/constants/version.constants.d.ts +5 -0
  6. package/dist/decorators/controller.decorator.d.ts +9 -0
  7. package/dist/decorators/http-method.decorator.d.ts +43 -0
  8. package/dist/decorators/index.d.ts +10 -0
  9. package/dist/decorators/module.decorator.d.ts +8 -0
  10. package/dist/decorators/parameter.decorator.d.ts +41 -0
  11. package/dist/decorators/service.decorator.d.ts +6 -0
  12. package/dist/decorators/use-component.decorator.d.ts +10 -0
  13. package/dist/decorators/use-filters.decorator.d.ts +8 -0
  14. package/dist/decorators/use-guards.decorator.d.ts +9 -0
  15. package/dist/decorators/use-middleware.decorator.d.ts +9 -0
  16. package/dist/decorators/use-pipes.decorator.d.ts +9 -0
  17. package/dist/di/contrainer.d.ts +23 -0
  18. package/dist/di/index.d.ts +1 -0
  19. package/dist/handlers/error.handler.d.ts +31 -0
  20. package/dist/handlers/index.d.ts +2 -0
  21. package/dist/handlers/not-found.handler.d.ts +14 -0
  22. package/dist/helpers/create-error-response.helper.d.ts +25 -0
  23. package/dist/helpers/create-http-method-decorator.helper.d.ts +16 -0
  24. package/dist/helpers/create-param-decorator.helper.d.ts +16 -0
  25. package/dist/helpers/index.d.ts +3 -0
  26. package/dist/index.d.ts +19 -0
  27. package/dist/index.js +1 -0
  28. package/dist/interfaces/controller-options.interface.d.ts +17 -0
  29. package/dist/interfaces/di-container.interface.d.ts +24 -0
  30. package/dist/interfaces/error-response.interface.d.ts +13 -0
  31. package/dist/interfaces/filter.interface.d.ts +20 -0
  32. package/dist/interfaces/guard.interface.d.ts +21 -0
  33. package/dist/interfaces/honest-options.interface.d.ts +78 -0
  34. package/dist/interfaces/http-method-options.interface.d.ts +13 -0
  35. package/dist/interfaces/index.d.ts +14 -0
  36. package/dist/interfaces/middleware.interface.d.ts +22 -0
  37. package/dist/interfaces/module-options.interface.d.ts +18 -0
  38. package/dist/interfaces/parameter-metadata.interface.d.ts +27 -0
  39. package/dist/interfaces/pipe.interface.d.ts +37 -0
  40. package/dist/interfaces/plugin.interface.d.ts +31 -0
  41. package/dist/interfaces/route-definition.interface.d.ts +30 -0
  42. package/dist/interfaces/route-info.interface.d.ts +42 -0
  43. package/dist/managers/component.manager.d.ts +143 -0
  44. package/dist/managers/index.d.ts +2 -0
  45. package/dist/managers/route.manager.d.ts +109 -0
  46. package/dist/registries/index.d.ts +2 -0
  47. package/dist/registries/metadata.registry.d.ts +172 -0
  48. package/dist/registries/route.registry.d.ts +63 -0
  49. package/dist/types/constructor.type.d.ts +12 -0
  50. package/dist/types/index.d.ts +1 -0
  51. package/dist/utils/common.util.d.ts +116 -0
  52. package/dist/utils/index.d.ts +1 -0
  53. package/package.json +51 -0
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import"reflect-metadata";import{Hono as s}from"hono";class w{instances=new Map;resolve(Q){if(this.instances.has(Q))return this.instances.get(Q);let X=(Reflect.getMetadata("design:paramtypes",Q)||[]).map((Z)=>{return this.resolve(Z)}),Y=new Q(...X);return this.instances.set(Q,Y),Y}register(Q,W){this.instances.set(Q,W)}}import{HTTPException as i}from"hono/http-exception";function P(Q,W,X){let Y=new Date().toISOString(),Z=W.get("requestId"),$=W.req.path;if(Q instanceof i)return{response:{status:X?.status||Q.status,message:X?.title||Q.message,timestamp:Y,path:$,requestId:Z,code:X?.code,details:X?.additionalDetails,...X?.detail&&{detail:X.detail}},status:X?.status||Q.status};if(Q.statusCode||Q.status){let j=Q.statusCode||Q.status,z=X?.status||j;return{response:{status:z,message:X?.title||Q.message,timestamp:Y,path:$,requestId:Z,code:X?.code||Q.name,details:X?.additionalDetails,...X?.detail&&{detail:X.detail}},status:z}}let J=X?.status||500;return{response:{status:J,message:X?.title||Q.message,timestamp:Y,path:$,requestId:Z,code:X?.code||Q.name,details:X?.additionalDetails||{stack:Q.stack},...X?.detail&&{detail:X.detail}},status:J}}class B{static routes=new Map;static controllers=new Map;static controllerOptions=new Map;static services=new Set;static modules=new Map;static parameters=new Map;static contextIndices=new Map;static global=new Map([["middleware",new Set],["guard",new Set],["pipe",new Set],["filter",new Set]]);static controller=new Map([["middleware",new Map],["guard",new Map],["pipe",new Map],["filter",new Map]]);static handler=new Map([["middleware",new Map],["guard",new Map],["pipe",new Map],["filter",new Map]]);static getRoutes(Q){return this.routes.get(Q)||[]}static setRoutes(Q,W){this.routes.set(Q,W)}static addRoute(Q,W){if(!this.routes.has(Q))this.routes.set(Q,[]);this.routes.get(Q).push(W)}static getControllerPath(Q){return this.controllers.get(Q)||""}static setControllerPath(Q,W){this.controllers.set(Q,W)}static getControllerOptions(Q){return this.controllerOptions.get(Q)||{}}static setControllerOptions(Q,W){this.controllerOptions.set(Q,W)}static isService(Q){return this.services.has(Q)}static addService(Q){this.services.add(Q)}static getAllServices(){return this.services}static getModuleOptions(Q){return this.modules.get(Q)}static setModuleOptions(Q,W){this.modules.set(Q,W)}static getParameters(Q){return this.parameters.get(Q)||new Map}static setParameterMap(Q,W){this.parameters.set(Q,W)}static getContextIndices(Q){return this.contextIndices.get(Q)||new Map}static setContextIndices(Q,W){this.contextIndices.set(Q,W)}static registerGlobal(Q,W){this.global.get(Q).add(W)}static getGlobal(Q){return this.global.get(Q)}static registerController(Q,W,X){let Y=this.controller.get(Q);if(!Y.has(W))Y.set(W,[]);Y.get(W).push(X)}static getController(Q,W){return this.controller.get(Q).get(W)||[]}static registerHandler(Q,W,X){let Y=this.handler.get(Q);if(!Y.has(W))Y.set(W,[]);Y.get(W).push(X)}static getHandler(Q,W){return this.handler.get(Q).get(W)||[]}}class N{static routes=[];static registerRoute(Q){this.routes.push(Q)}static getRoutes(){return this.routes}static getRoutesByController(Q){return this.routes.filter((W)=>W.controller===Q)}static getRoutesByMethod(Q){return this.routes.filter((W)=>W.method.toUpperCase()===Q.toUpperCase())}static getRoutesByPath(Q){return this.routes.filter((W)=>Q.test(W.fullPath))}static clear(){this.routes.length=0}}function E(Q){return(W="",X={})=>{return(Y,Z,$)=>{let J=Y.constructor;B.addRoute(J,{path:W,method:Q,handlerName:Z,parameterMetadata:[],version:X.version})}}}function _(Q,W){return(X)=>{return(Y,Z,$)=>{let J=Y.constructor;if(!B.getParameters(J).size)B.setParameterMap(J,new Map);let U=B.getParameters(J);if(!U.has(Z))U.set(Z,[]);let z=Reflect.getMetadata("design:paramtypes",Y,Z)?.[$];if(U.get(Z).push({index:$,name:Q,data:X,factory:W,metatype:z}),Q==="context"){if(!B.getContextIndices(J).size)B.setContextIndices(J,new Map);B.getContextIndices(J).set(Z,$)}}}}class f{static handle(){return async(Q,W)=>{return W.json(P(Q,W))}}}class M{static handle(){return async(Q)=>{return Q.json({message:`Not Found - ${Q.req.path}`},404)}}}var S=(Q)=>Q!==null&&typeof Q==="object";class q{static container;static init(Q){this.container=Q}static setupGlobalComponents(Q){let W=Q.components||{};if(W.middleware)this.registerGlobal("middleware",...W.middleware);if(W.guards)this.registerGlobal("guard",...W.guards);if(W.pipes)this.registerGlobal("pipe",...W.pipes);if(W.filters)this.registerGlobal("filter",...W.filters)}static registerGlobal(Q,...W){W.forEach((X)=>{B.registerGlobal(Q,X)})}static registerController(Q,W,...X){X.forEach((Y)=>{B.registerController(Q,W,Y)})}static registerHandler(Q,W,X,...Y){let Z=`${W.name}:${String(X)}`;Y.forEach(($)=>{B.registerHandler(Q,Z,$)})}static getComponents(Q,W,X){let Y=`${W.name}:${String(X)}`,Z=B.getHandler(Q,Y),$=B.getController(Q,W);return[...Array.from(B.getGlobal(Q)),...$,...Z]}static resolveMiddleware(Q){return Q.map((W)=>{if(S(W)&&"use"in W)return W.use.bind(W);let X=this.container.resolve(W);return X.use.bind(X)})}static getHandlerMiddleware(Q,W){let X=this.getComponents("middleware",Q,W);return this.resolveMiddleware(X)}static getGlobalMiddleware(){let Q=Array.from(B.getGlobal("middleware"));return this.resolveMiddleware(Q)}static resolveGuards(Q){return Q.map((W)=>{if(S(W)&&"canActivate"in W)return W;return this.container.resolve(W)})}static getHandlerGuards(Q,W){let X=this.getComponents("guard",Q,W);return this.resolveGuards(X)}static resolvePipes(Q){return Q.map((W)=>{if(S(W)&&"transform"in W)return W;return this.container.resolve(W)})}static getHandlerPipes(Q,W){let X=this.getComponents("pipe",Q,W);return this.resolvePipes(X)}static async executePipes(Q,W,X){let Y=Q;for(let Z of X)Y=await Z.transform(Y,W);return Y}static async handleException(Q,W){let X=W.get("controllerClass"),Y=W.get("handlerName");if(X&&Y){let $=B.getHandler("filter",`${X.name}:${Y}`);if($.length>0){let J=await this.executeFilters($,Q,W);if(J)return J}}if(X){let $=B.getController("filter",X);if($.length>0){let J=await this.executeFilters($,Q,W);if(J)return J}}let Z=Array.from(B.getGlobal("filter"));if(Z.length>0){let $=await this.executeFilters(Z,Q,W);if($)return $}return console.log("No filter handled the exception, creating default response"),W.json(P(Q,W))}static async executeFilters(Q,W,X){for(let Y of Q){let Z;if(S(Y)&&"catch"in Y)Z=Y;else Z=this.container.resolve(Y);try{let $=await Z.catch(W,X);if($!==void 0)return $}catch($){console.error("Error in exception filter:",$)}}return}static async registerModule(Q,W){let X=B.getModuleOptions(Q);if(!X)throw new Error(`Module ${Q.name} is not properly decorated with @Module()`);let Y=[];if(X.imports&&X.imports.length>0)for(let Z of X.imports){let $=await this.registerModule(Z,W);Y.push(...$)}if(X.services&&X.services.length>0)for(let Z of X.services)W.resolve(Z);if(X.controllers&&X.controllers.length>0)Y.push(...X.controllers);return Y}}import{HTTPException as p}from"hono/http-exception";var x=Symbol("VERSION_NEUTRAL");var bQ=(Q)=>typeof Q==="undefined",O=(Q)=>Q===null||typeof Q==="undefined",I=(Q)=>Q!==null&&typeof Q==="object",NQ=(Q)=>{if(!I(Q))return!1;let W=Object.getPrototypeOf(Q);if(W===null)return!0;let X=Object.prototype.hasOwnProperty.call(W,"constructor")&&W.constructor;return typeof X==="function"&&X instanceof X&&Function.prototype.toString.call(X)===Function.prototype.toString.call(Object)},h=(Q)=>typeof Q==="function",C=(Q)=>typeof Q==="string",KQ=(Q)=>typeof Q==="number",RQ=(Q)=>Q.length===0,TQ=(Q)=>typeof Q==="symbol",PQ=(Q)=>typeof Q==="string"?Q.charAt(0)!=="/"?"/"+Q:Q:"",v=(Q)=>Q?Q.startsWith("/")?("/"+Q.replace(/\/+$/,"")).replace(/\/+/g,"/"):"/"+Q.replace(/\/+$/,""):"/",SQ=(Q)=>Q.endsWith("/")?Q.slice(0,-1):Q,m=(Q)=>{return h(Q)&&!O(Q.prototype)&&!h(Q.prototype)&&Object.getOwnPropertyNames(Q.prototype).length>1};class y{hono;container;globalPrefix;globalVersion;constructor(Q,W,X={}){this.hono=Q,this.container=W,this.globalPrefix=X.prefix!==void 0?this.normalizePath(X.prefix):void 0,this.globalVersion=X.version,this.applyGlobalMiddleware()}applyGlobalMiddleware(){let Q=q.getGlobalMiddleware();for(let W of Q)this.hono.use("*",W)}normalizePath(Q){if(C(Q))return v(Q);return Q?`/${Q}`:""}registerRouteHandler(Q,W,X,Y){if(X.length>0)this.hono.on(Q.toUpperCase(),W,...X,Y);else this.hono.on(Q.toUpperCase(),W,Y)}buildRoutePath(Q,W,X,Y){return v(`${Q}${W}${X}${Y}`)}formatVersionSegment(Q){if(O(Q))return"";return Q===x?"":`/v${String(Q)}`}async registerController(Q){let W=B.getControllerPath(Q)||"",X=B.getControllerOptions(Q)||{},Y=B.getRoutes(Q)||[],Z=B.getParameters(Q)||new Map,$=B.getContextIndices(Q)||new Map,J=this.container.resolve(Q),U=!O(X.prefix)?X.prefix:this.globalPrefix,j=!O(U)?this.normalizePath(U):"",z=this.normalizePath(W),L=X.version!==void 0?X.version:this.globalVersion;for(let G of Y){let{path:K,method:F,handlerName:u,version:R}=G,A=R!==void 0?R:L,D=this.normalizePath(K);if(O(A)){this.registerRoute(J,G,Z,$,Q,j,"",z,D,F);continue}if(A===x){this.registerRoute(J,G,Z,$,Q,j,"",z,D,F),this.registerRoute(J,G,Z,$,Q,j,"/:version{v[0-9]+}",z,D,F);continue}if(Array.isArray(A)){for(let H of A){let T=this.formatVersionSegment(H);this.registerRoute(J,G,Z,$,Q,j,T,z,D,F)}continue}let k=this.formatVersionSegment(A);this.registerRoute(J,G,Z,$,Q,j,k,z,D,F)}}registerRoute(Q,W,X,Y,Z,$,J,U,j,z){let{handlerName:L}=W,G=this.buildRoutePath($,J,U,j),K=Q[L].bind(Q),F=X.get(L)||[],u=Y.get(L),R=q.getHandlerMiddleware(Z,L),A=q.getHandlerPipes(Z,L);N.registerRoute({controller:Z.name,handler:L,method:z,prefix:$,version:J,route:U,path:j,fullPath:G,parameters:F});let D=async(k)=>{try{k.set("controllerClass",Z),k.set("handlerName",String(L));let H=q.getHandlerGuards(Z,L);for(let V of H)if(!await V.canActivate(k))throw new p(403,{message:"Forbidden"});let T=new Array(K.length);for(let V of F){let g=V.factory(V.data,k),c=await q.executePipes(g,{type:V.type,metatype:V.metatype,data:V.data},A);T[V.index]=c}let b=await K(...T);if(u!==void 0)return b;if(O(b))return k.json(null);if(C(b))return k.text(b);return k.json(b)}catch(H){return q.handleException(H,k)}};this.registerRouteHandler(z,G,R,D)}}class d{hono;container;routeManager;options;constructor(Q={}){this.options=I(Q)?Q:{},this.hono=new s(this.options.hono),this.container=this.options.container||new w,this.routeManager=new y(this.hono,this.container,{prefix:this.options.routing?.prefix,version:this.options.routing?.version}),this.setupComponents(),this.setupErrorHandlers()}setupComponents(){q.init(this.container),q.setupGlobalComponents(this.options)}setupErrorHandlers(){this.hono.notFound(this.options.notFound||M.handle()),this.hono.onError(this.options.onError||f.handle())}resolvePlugin(Q){if(m(Q))return new Q;return Q}async register(Q){let W=await q.registerModule(Q,this.container);for(let X of W)await this.routeManager.registerController(X);return this}static async create(Q,W={}){let X=new d(W),Y=(W.plugins||[]).map((Z)=>X.resolvePlugin(Z));for(let Z of Y)if(Z.beforeModulesRegistered)await Z.beforeModulesRegistered(X,X.hono);await X.register(Q);for(let Z of Y)if(Z.afterModulesRegistered)await Z.afterModulesRegistered(X,X.hono);return{app:X,hono:X.getApp()}}getApp(){return this.hono}getRoutes(){return N.getRoutes()}}function rQ(Q="",W={}){return(X)=>{B.setControllerPath(X,Q),B.setControllerOptions(X,W)}}var eQ=E("get"),QW=E("post"),WW=E("put"),XW=E("delete"),YW=E("patch"),ZW=E("options"),$W=E("all");function qW(Q={}){return(W)=>{B.setModuleOptions(W,Q)}}var jW=_("body",async(Q,W)=>{let X=await W.req.json();return Q?X[Q]:X}),LW=_("param",(Q,W)=>{return Q?W.req.param(Q):W.req.param()}),UW=_("query",(Q,W)=>{return Q?W.req.query(Q):W.req.query()}),GW=_("header",(Q,W)=>{return Q?W.req.header(Q):W.req.header()}),kW=_("request",(Q,W)=>W.req),FW=_("request",(Q,W)=>W.req),VW=_("response",(Q,W)=>W.res),EW=_("response",(Q,W)=>W.res),AW=_("context",(Q,W)=>W),DW=_("context",(Q,W)=>W),OW=_("variable",(Q,W)=>W.get(Q)),HW=_("variable",(Q,W)=>W.get(Q));function KW(){return(Q)=>{B.addService(Q)}}function PW(Q,...W){return(X,Y)=>{if(Y){let Z=X.constructor;q.registerHandler(Q,Z,Y,...W)}else q.registerController(Q,X,...W)}}function fW(...Q){return(W,X)=>{if(X){let Y=W.constructor;q.registerHandler("filter",Y,X,...Q)}else q.registerController("filter",W,...Q)}}function IW(...Q){return(W,X)=>{if(X){let Y=W.constructor;q.registerHandler("guard",Y,X,...Q)}else q.registerController("guard",W,...Q)}}function yW(...Q){return(W,X)=>{if(X){let Y=W.constructor;q.registerHandler("middleware",Y,X,...Q)}else q.registerController("middleware",W,...Q)}}function hW(...Q){return(W,X)=>{if(X){let Y=W.constructor;q.registerHandler("pipe",Y,X,...Q)}else q.registerController("pipe",W,...Q)}}export{SQ as stripEndSlash,v as normalizePath,bQ as isUndefined,TQ as isSymbol,C as isString,NQ as isPlainObject,I as isObject,KQ as isNumber,O as isNil,h as isFunction,RQ as isEmpty,m as isConstructor,_ as createParamDecorator,E as createHttpMethodDecorator,P as createErrorResponse,PQ as addLeadingSlash,HW as Variable,OW as Var,x as VERSION_NEUTRAL,hW as UsePipes,yW as UseMiddleware,IW as UseGuards,fW as UseFilters,PW as UseComponent,KW as Service,N as RouteRegistry,y as RouteManager,EW as Response,VW as Res,FW as Request,kW as Req,UW as Query,WW as Put,QW as Post,YW as Patch,LW as Param,ZW as Options,M as NotFoundHandler,qW as Module,B as MetadataRegistry,GW as Header,eQ as Get,f as ErrorHandler,XW as Delete,AW as Ctx,rQ as Controller,DW as Context,w as Container,q as ComponentManager,jW as Body,d as Application,$W as All};
@@ -0,0 +1,17 @@
1
+ import type { VERSION_NEUTRAL } from '../constants';
2
+ /**
3
+ * Interface for controller configuration options
4
+ */
5
+ export interface ControllerOptions {
6
+ /**
7
+ * API prefix for this controller's routes, overrides global prefix
8
+ */
9
+ prefix?: string | null;
10
+ /**
11
+ * API version for this controller's routes (e.g. 1 becomes /v1), overrides global version
12
+ * Set to null to explicitly opt out of versioning even when global version is set
13
+ * Set to VERSION_NEUTRAL to make routes accessible both with and without version prefix
14
+ * Set to an array of numbers to make routes available at multiple versions
15
+ */
16
+ version?: number | null | typeof VERSION_NEUTRAL | number[];
17
+ }
@@ -0,0 +1,24 @@
1
+ import type { Constructor } from '../types';
2
+ /**
3
+ * Interface for dependency injection containers
4
+ * Defines the contract that DI containers must implement to work with the Honest framework
5
+ * Handles the creation and management of dependency instances
6
+ */
7
+ export interface DiContainer {
8
+ /**
9
+ * Resolves a dependency from the container
10
+ * Creates a new instance or returns an existing one based on the container's configuration
11
+ * @param target - The class constructor to resolve
12
+ * @returns An instance of the requested class with all dependencies injected
13
+ * @throws {Error} If the dependency cannot be resolved
14
+ */
15
+ resolve<T>(target: Constructor<T>): T;
16
+ /**
17
+ * Registers a pre-created instance in the container
18
+ * Used for singleton instances or mocks in testing
19
+ * @param target - The class constructor to register the instance for
20
+ * @param instance - The pre-created instance to use
21
+ * @throws {Error} If registration fails
22
+ */
23
+ register<T>(target: Constructor<T>, instance: T): void;
24
+ }
@@ -0,0 +1,13 @@
1
+ export interface ErrorResponse {
2
+ status: number;
3
+ message: string;
4
+ timestamp: string;
5
+ path: string;
6
+ requestId?: string;
7
+ code?: string;
8
+ details?: Record<string, any>;
9
+ errors?: Array<{
10
+ property: string;
11
+ constraints: Record<string, string>;
12
+ }>;
13
+ }
@@ -0,0 +1,20 @@
1
+ import type { Context } from 'hono';
2
+ import type { Constructor } from '../types';
3
+ /**
4
+ * Interface for exception filters
5
+ * Filters handle and transform exceptions thrown during request processing
6
+ */
7
+ export interface IFilter {
8
+ /**
9
+ * Method to catch and handle exceptions
10
+ * @param exception - The exception that was thrown
11
+ * @param context - The Hono context object
12
+ * @returns A Response object or undefined if the exception should be passed to the next filter
13
+ */
14
+ catch(exception: Error, context: Context): Promise<Response | undefined> | Response | undefined;
15
+ }
16
+ /**
17
+ * Type for exception filters
18
+ * Can be either a class implementing IFilter or an instance of IFilter
19
+ */
20
+ export type FilterType = Constructor<IFilter> | IFilter;
@@ -0,0 +1,21 @@
1
+ import type { Constructor } from '../types';
2
+ import type { Context } from 'hono';
3
+ /**
4
+ * Interface defining a guard.
5
+ * Guards determine whether a request should be handled by the route handler or not.
6
+ */
7
+ export interface IGuard {
8
+ /**
9
+ * Method to implement the guard logic.
10
+ * Return true to allow the request to proceed, false to deny.
11
+ *
12
+ * @param context - The Hono context object
13
+ * @returns A boolean or Promise<boolean> indicating if the request is allowed
14
+ */
15
+ canActivate(context: Context): boolean | Promise<boolean>;
16
+ }
17
+ /**
18
+ * Type for guard classes
19
+ * Can be either a constructor of IGuard or an instance of IGuard
20
+ */
21
+ export type GuardType = Constructor<IGuard> | IGuard;
@@ -0,0 +1,78 @@
1
+ import type { Context } from 'hono';
2
+ import type { VERSION_NEUTRAL } from '../constants';
3
+ import type { FilterType, GuardType, MiddlewareType, PipeType, PluginType } from '../interfaces';
4
+ import type { DiContainer } from './di-container.interface';
5
+ /**
6
+ * Options for configuring the Honest application
7
+ */
8
+ export interface HonestOptions {
9
+ /**
10
+ * Container instance for dependency injection
11
+ */
12
+ container?: DiContainer;
13
+ /**
14
+ * Hono-specific options
15
+ */
16
+ hono?: {
17
+ /**
18
+ * Whether to use strict matching for routes
19
+ */
20
+ strict?: boolean;
21
+ /**
22
+ * Custom router to use
23
+ */
24
+ router?: any;
25
+ /**
26
+ * Function to extract path from request
27
+ */
28
+ getPath?: (request: Request, options?: any) => string;
29
+ };
30
+ /**
31
+ * Global routing options
32
+ */
33
+ routing?: {
34
+ /**
35
+ * Global API prefix to apply to all routes (e.g. /api)
36
+ */
37
+ prefix?: string;
38
+ /**
39
+ * Global API version to apply to all routes (e.g. 1 becomes /v1)
40
+ * Set to VERSION_NEUTRAL to make routes accessible both with and without version prefix
41
+ * Set to an array of numbers to make routes available at multiple versions
42
+ */
43
+ version?: number | typeof VERSION_NEUTRAL | number[];
44
+ };
45
+ /**
46
+ * Global components to apply to all routes
47
+ */
48
+ components?: {
49
+ /**
50
+ * Global middleware to apply to all routes
51
+ */
52
+ middleware?: MiddlewareType[];
53
+ /**
54
+ * Global guards to apply to all routes
55
+ */
56
+ guards?: GuardType[];
57
+ /**
58
+ * Global pipes to apply to all routes
59
+ */
60
+ pipes?: PipeType[];
61
+ /**
62
+ * Global exception filters to apply to all routes
63
+ */
64
+ filters?: FilterType[];
65
+ };
66
+ /**
67
+ * Plugins for extending the application functionality
68
+ */
69
+ plugins?: PluginType[];
70
+ /**
71
+ * Default exception handler to use when no filter matches
72
+ */
73
+ onError?: (error: Error, context: Context) => Response | Promise<Response>;
74
+ /**
75
+ * Default not found handler for routes that don't match any pattern
76
+ */
77
+ notFound?: (context: Context) => Response | Promise<Response>;
78
+ }
@@ -0,0 +1,13 @@
1
+ import type { VERSION_NEUTRAL } from '../constants';
2
+ /**
3
+ * Options for HTTP method decorators
4
+ */
5
+ export interface HttpMethodOptions {
6
+ /**
7
+ * API version for this specific route, overrides controller and global version
8
+ * Set to null to explicitly opt out of versioning
9
+ * Set to VERSION_NEUTRAL to make the route accessible both with and without version prefix
10
+ * Set to an array of numbers to make the route available at multiple versions
11
+ */
12
+ version?: number | null | typeof VERSION_NEUTRAL | number[];
13
+ }
@@ -0,0 +1,14 @@
1
+ export * from './controller-options.interface';
2
+ export * from './di-container.interface';
3
+ export * from './error-response.interface';
4
+ export * from './filter.interface';
5
+ export * from './guard.interface';
6
+ export * from './honest-options.interface';
7
+ export * from './http-method-options.interface';
8
+ export * from './middleware.interface';
9
+ export * from './module-options.interface';
10
+ export * from './parameter-metadata.interface';
11
+ export * from './pipe.interface';
12
+ export * from './plugin.interface';
13
+ export * from './route-definition.interface';
14
+ export * from './route-info.interface';
@@ -0,0 +1,22 @@
1
+ import type { Context, Next } from 'hono';
2
+ import type { Constructor } from '../types';
3
+ /**
4
+ * Interface for HTTP middleware components
5
+ * Middleware can process requests before they reach the route handler
6
+ * and modify both the request and response
7
+ */
8
+ export interface IMiddleware {
9
+ /**
10
+ * Processes an HTTP request/response
11
+ * @param c - The Hono context containing request and response information
12
+ * @param next - Function to call the next middleware in the chain
13
+ * @returns A Promise that resolves to a Response or void
14
+ * @throws {Error} If middleware processing fails
15
+ */
16
+ use(c: Context, next: Next): Promise<Response | void>;
17
+ }
18
+ /**
19
+ * Type for middleware implementations
20
+ * Can be either a class implementing IMiddleware or an instance of IMiddleware
21
+ */
22
+ export type MiddlewareType = Constructor<IMiddleware> | IMiddleware;
@@ -0,0 +1,18 @@
1
+ import type { Constructor } from '../types';
2
+ /**
3
+ * Options for configuring a module
4
+ */
5
+ export interface ModuleOptions {
6
+ /**
7
+ * List of controller classes
8
+ */
9
+ controllers?: Constructor[];
10
+ /**
11
+ * List of service classes
12
+ */
13
+ services?: Constructor[];
14
+ /**
15
+ * List of imported modules
16
+ */
17
+ imports?: Constructor[];
18
+ }
@@ -0,0 +1,27 @@
1
+ import type { Constructor } from '../types';
2
+ import type { Context } from 'hono';
3
+ /**
4
+ * Metadata for route parameters
5
+ */
6
+ export interface ParameterMetadata {
7
+ /**
8
+ * Parameter index
9
+ */
10
+ index: number;
11
+ /**
12
+ * Parameter name (body, param, query, etc.)
13
+ */
14
+ name: string;
15
+ /**
16
+ * Additional parameter data (e.g., param name)
17
+ */
18
+ data?: any;
19
+ /**
20
+ * Optional factory function to transform the data
21
+ */
22
+ factory: (data: any, ctx: Context) => any;
23
+ /**
24
+ * The class type of the parameter
25
+ */
26
+ metatype?: Constructor<unknown>;
27
+ }
@@ -0,0 +1,37 @@
1
+ import type { Constructor } from '../types';
2
+ /**
3
+ * Metadata about an argument being processed by a pipe
4
+ */
5
+ export interface ArgumentMetadata {
6
+ /**
7
+ * The type of argument (body, query, param, or custom)
8
+ */
9
+ type: 'body' | 'query' | 'param' | 'custom';
10
+ /**
11
+ * The class type of the argument
12
+ */
13
+ metatype?: Constructor<unknown>;
14
+ /**
15
+ * Additional data about the argument
16
+ */
17
+ data?: string;
18
+ }
19
+ /**
20
+ * Interface for transformation pipes
21
+ * Pipes transform input data before it reaches the route handler
22
+ */
23
+ export interface IPipe {
24
+ /**
25
+ * Transforms the input value according to the pipe's logic
26
+ * @param value - The value to transform
27
+ * @param metadata - Metadata about the argument being transformed
28
+ * @returns The transformed value, which can be synchronous or asynchronous
29
+ * @throws {Error} If the transformation fails or validation fails
30
+ */
31
+ transform(value: unknown, metadata: ArgumentMetadata): Promise<unknown> | unknown;
32
+ }
33
+ /**
34
+ * Type for pipe implementations
35
+ * Can be either a class implementing IPipe or an instance of IPipe
36
+ */
37
+ export type PipeType = Constructor<IPipe> | IPipe;
@@ -0,0 +1,31 @@
1
+ import type { Hono } from 'hono';
2
+ import type { Application } from '../application';
3
+ import type { Constructor } from '../types';
4
+ /**
5
+ * Interface for Honest framework plugins
6
+ * Plugins can extend the framework's functionality by hooking into
7
+ * different stages of the application lifecycle
8
+ */
9
+ export interface IPlugin {
10
+ /**
11
+ * Hook that runs before module registration begins
12
+ * Use this to set up plugin functionality that modules might depend on
13
+ * @param app - The Honest application instance
14
+ * @param hono - The underlying Hono application instance
15
+ * @returns Void or a Promise that resolves to void
16
+ */
17
+ beforeModulesRegistered?: (app: Application, hono: Hono) => void | Promise<void>;
18
+ /**
19
+ * Hook that runs after all modules have been registered
20
+ * Use this to perform cleanup or setup that requires all modules to be ready
21
+ * @param app - The Honest application instance
22
+ * @param hono - The underlying Hono application instance
23
+ * @returns Void or a Promise that resolves to void
24
+ */
25
+ afterModulesRegistered?: (app: Application, hono: Hono) => void | Promise<void>;
26
+ }
27
+ /**
28
+ * Type for plugin implementations
29
+ * Can be either a class implementing IPlugin or an instance of IPlugin
30
+ */
31
+ export type PluginType = Constructor<IPlugin> | IPlugin;
@@ -0,0 +1,30 @@
1
+ import type { VERSION_NEUTRAL } from '../constants';
2
+ import type { ParameterMetadata } from '../interfaces';
3
+ /**
4
+ * Metadata for defining a route
5
+ */
6
+ export interface RouteDefinition {
7
+ /**
8
+ * Route path
9
+ */
10
+ path: string;
11
+ /**
12
+ * HTTP method
13
+ */
14
+ method: string;
15
+ /**
16
+ * Handler method name
17
+ */
18
+ handlerName: string | symbol;
19
+ /**
20
+ * Parameter metadata for the handler
21
+ */
22
+ parameterMetadata: ParameterMetadata[];
23
+ /**
24
+ * Route-specific API version, overrides controller and global version
25
+ * Set to null to explicitly opt out of versioning
26
+ * Set to VERSION_NEUTRAL to make the route accessible both with and without version prefix
27
+ * Set to an array of numbers to make the route available at multiple versions
28
+ */
29
+ version?: number | null | typeof VERSION_NEUTRAL | number[];
30
+ }
@@ -0,0 +1,42 @@
1
+ import type { ParameterMetadata } from './parameter-metadata.interface';
2
+ /**
3
+ * Route information for registered routes
4
+ */
5
+ export interface RouteInfo {
6
+ /**
7
+ * Controller name
8
+ */
9
+ controller: string | symbol;
10
+ /**
11
+ * Handler method name
12
+ */
13
+ handler: string | symbol;
14
+ /**
15
+ * HTTP method
16
+ */
17
+ method: string;
18
+ /**
19
+ * Effective prefix
20
+ */
21
+ prefix: string;
22
+ /**
23
+ * Effective version
24
+ */
25
+ version?: string;
26
+ /**
27
+ * Controller route path
28
+ */
29
+ route: string;
30
+ /**
31
+ * Method path
32
+ */
33
+ path: string;
34
+ /**
35
+ * Complete path (prefix + version + route + path)
36
+ */
37
+ fullPath: string;
38
+ /**
39
+ * Parameter metadata for the handler
40
+ */
41
+ parameters: ParameterMetadata[];
42
+ }
@@ -0,0 +1,143 @@
1
+ import type { Context, Next } from 'hono';
2
+ import type { ArgumentMetadata, DiContainer, GuardType, IGuard, IPipe, MiddlewareType, PipeType } from '../interfaces';
3
+ import { type ComponentType, type ComponentTypeMap } from '../registries';
4
+ import type { Constructor } from '../types';
5
+ /**
6
+ * Manager class for handling all component types in the Honest framework
7
+ * Provides unified management of middleware, guards, pipes, and filters
8
+ * Handles component registration, resolution, and execution at global, controller, and handler levels
9
+ * Works with the dependency injection container to resolve component instances
10
+ */
11
+ export declare class ComponentManager {
12
+ private static container;
13
+ /**
14
+ * Initializes the ComponentManager with a dependency injection container
15
+ * Must be called before using any other ComponentManager methods
16
+ * @param container - The dependency injection container to use for resolving components
17
+ */
18
+ static init(container: DiContainer): void;
19
+ /**
20
+ * Configures global components from application options
21
+ * Global components are applied to all routes in the application
22
+ * @param options - Application options containing component configurations
23
+ * @param options.components - Optional component configuration object
24
+ * @param options.components.middleware - Optional array of global middleware
25
+ * @param options.components.guards - Optional array of global guards
26
+ * @param options.components.pipes - Optional array of global pipes
27
+ * @param options.components.filters - Optional array of global filters
28
+ */
29
+ static setupGlobalComponents(options: {
30
+ components?: {
31
+ middleware?: any[];
32
+ guards?: any[];
33
+ pipes?: any[];
34
+ filters?: any[];
35
+ };
36
+ }): void;
37
+ /**
38
+ * Registers a component at the global level
39
+ * @param type - The type of component to register
40
+ * @param components - The component classes or instances to register
41
+ */
42
+ static registerGlobal<T extends ComponentType>(type: T, ...components: ComponentTypeMap[T][]): void;
43
+ /**
44
+ * Registers a component at the controller level
45
+ * @param type - The type of component to register
46
+ * @param controller - The controller class to register the component for
47
+ * @param components - The component classes or instances to register
48
+ */
49
+ static registerController<T extends ComponentType>(type: T, controller: Constructor, ...components: ComponentTypeMap[T][]): void;
50
+ /**
51
+ * Registers a component at the handler level
52
+ * @param type - The type of component to register
53
+ * @param controller - The controller class
54
+ * @param handlerName - The handler method name
55
+ * @param components - The component classes or instances to register
56
+ */
57
+ static registerHandler<T extends ComponentType>(type: T, controller: Constructor, handlerName: string | symbol, ...components: ComponentTypeMap[T][]): void;
58
+ /**
59
+ * Gets all components of a specific type for a handler
60
+ * @param type - The type of component to get
61
+ * @param controller - The controller class
62
+ * @param handlerName - The handler method name
63
+ * ..returns An array of component instances
64
+ */
65
+ static getComponents<T extends ComponentType>(type: T, controller: Constructor, handlerName: string | symbol): ComponentTypeMap[T][];
66
+ /**
67
+ * Resolves middleware classes or instances to middleware functions
68
+ * @param middlewareItems - The middleware classes or instances to resolve
69
+ * ..returns An array of middleware functions
70
+ */
71
+ static resolveMiddleware(middlewareItems: MiddlewareType[]): ((c: Context, next: Next) => Promise<Response | void>)[];
72
+ /**
73
+ * Gets middleware for a specific handler
74
+ * @param controller - The controller class
75
+ * @param handlerName - The handler method name
76
+ * ..returns An array of middleware functions
77
+ */
78
+ static getHandlerMiddleware(controller: Constructor, handlerName: string | symbol): ((c: Context, next: Next) => Promise<Response | void>)[];
79
+ /**
80
+ * Gets global middleware
81
+ * ..returns An array of middleware functions
82
+ */
83
+ static getGlobalMiddleware(): ((c: Context, next: Next) => Promise<Response | void>)[];
84
+ /**
85
+ * Resolves guard classes or instances to guard instances
86
+ * @param guardItems - The guard classes or instances to resolve
87
+ * ..returns An array of guard instances
88
+ */
89
+ static resolveGuards(guardItems: GuardType[]): IGuard[];
90
+ /**
91
+ * Gets guards for a specific handler
92
+ * @param controller - The controller class
93
+ * @param handlerName - The handler method name
94
+ * ..returns An array of guard instances
95
+ */
96
+ static getHandlerGuards(controller: Constructor, handlerName: string | symbol): IGuard[];
97
+ /**
98
+ * Resolves pipe classes or instances to pipe instances
99
+ * @param pipeItems - The pipe classes or instances to resolve
100
+ * ..returns An array of pipe instances
101
+ */
102
+ static resolvePipes(pipeItems: PipeType[]): IPipe[];
103
+ /**
104
+ * Gets pipes for a specific handler
105
+ * @param controller - The controller class
106
+ * @param handlerName - The handler method name
107
+ * ..returns An array of pipe instances
108
+ */
109
+ static getHandlerPipes(controller: Constructor, handlerName: string | symbol): IPipe[];
110
+ /**
111
+ * Executes a series of pipes on a value
112
+ * Pipes are executed in sequence, with each pipe's output feeding into the next pipe
113
+ * @param value - The initial value to transform
114
+ * @param metadata - Metadata about the parameter being transformed
115
+ * @param pipes - Array of pipes to execute
116
+ * @returns The final transformed value after all pipes have executed
117
+ * @throws {Error} If any pipe transformation fails
118
+ */
119
+ static executePipes(value: any, metadata: ArgumentMetadata, pipes: IPipe[]): Promise<any>;
120
+ /**
121
+ * Handles an exception by passing it through registered exception filters
122
+ * Filters are executed in sequence until one returns a response
123
+ * @param exception - The error to handle
124
+ * @param context - The Hono context object
125
+ * @returns A Response object if a filter handles the exception, undefined otherwise
126
+ */
127
+ static handleException(exception: Error, context: Context): Promise<Response | undefined>;
128
+ /**
129
+ * Executes a list of exception filters
130
+ * @param filterItems - The exception filter classes or instances to execute
131
+ * @param exception - The exception that was thrown
132
+ * @param context - The Hono context object
133
+ * ..returns The response from the first filter that handles the exception or undefined if no filter handled it
134
+ */
135
+ private static executeFilters;
136
+ /**
137
+ * Registers a module and its dependencies with the container
138
+ * @param moduleClass - The module class to register
139
+ * @param container - The dependency injection container
140
+ * @returns An array of controller classes registered from this module
141
+ */
142
+ static registerModule(moduleClass: Constructor, container: DiContainer): Promise<Constructor[]>;
143
+ }
@@ -0,0 +1,2 @@
1
+ export * from './component.manager';
2
+ export * from './route.manager';