honestjs 0.1.11 → 0.1.12
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/dist/application.d.ts +6 -119
- package/dist/decorators/decorators.test.d.ts +1 -0
- package/dist/di/container.d.ts +7 -2
- package/dist/handlers/handlers.test.d.ts +1 -0
- package/dist/helpers/create-error-response.helper.test.d.ts +1 -0
- package/dist/index.js +19 -19
- package/dist/interfaces/di-container.interface.d.ts +11 -0
- package/dist/interfaces/route-definition.interface.d.ts +0 -6
- package/dist/managers/component.manager.d.ts +34 -131
- package/dist/managers/component.manager.test.d.ts +1 -0
- package/dist/managers/route.manager.d.ts +8 -86
- package/dist/managers/route.manager.test.d.ts +1 -0
- package/dist/pipeline.integration.test.d.ts +1 -0
- package/dist/registries/metadata.registry.d.ts +2 -28
- package/dist/registries/metadata.registry.test.d.ts +1 -0
- package/dist/registries/route.registry.d.ts +10 -57
- package/package.json +6 -6
package/dist/application.d.ts
CHANGED
|
@@ -2,143 +2,30 @@ import { Hono } from 'hono';
|
|
|
2
2
|
import type { HonestOptions, IApplicationContext, RouteInfo } from './interfaces';
|
|
3
3
|
import type { Constructor } from './types';
|
|
4
4
|
/**
|
|
5
|
-
* Main application class for the Honest framework
|
|
6
|
-
* Serves as the entry point for creating and configuring web applications
|
|
5
|
+
* Main application class for the Honest framework.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
* - Plugin system for extending functionality
|
|
12
|
-
* - Route management with versioning support
|
|
13
|
-
* - Global error handling
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* const { app } = await Application.create(AppModule, {
|
|
18
|
-
* routing: { prefix: '/api', version: 1 },
|
|
19
|
-
* plugins: [new LoggerPlugin()]
|
|
20
|
-
* });
|
|
21
|
-
* ```
|
|
7
|
+
* All per-app runtime state (routes, global components, DI container) is
|
|
8
|
+
* instance-based. Static decorator metadata lives in MetadataRegistry and
|
|
9
|
+
* is shared across all Application instances in the same process.
|
|
22
10
|
*/
|
|
23
11
|
export declare class Application {
|
|
24
12
|
private readonly hono;
|
|
25
13
|
private readonly container;
|
|
26
14
|
private readonly context;
|
|
15
|
+
private readonly routeRegistry;
|
|
16
|
+
private readonly componentManager;
|
|
27
17
|
private readonly routeManager;
|
|
28
18
|
private readonly options;
|
|
29
|
-
/**
|
|
30
|
-
* Creates a new Application instance with the specified configuration
|
|
31
|
-
* @param options - Configuration options for the application
|
|
32
|
-
* @param options.routing - Route configuration (prefix, versioning)
|
|
33
|
-
* @param options.plugins - Array of plugins to extend functionality
|
|
34
|
-
* @param options.container - Custom dependency injection container
|
|
35
|
-
* @param options.hono - Hono-specific configuration options
|
|
36
|
-
* @throws {Error} If options are invalid or initialization fails
|
|
37
|
-
*/
|
|
38
19
|
constructor(options?: HonestOptions);
|
|
39
|
-
/**
|
|
40
|
-
* Sets up global components from application options
|
|
41
|
-
* Initializes the component manager and registers global middleware,
|
|
42
|
-
* guards, pipes, and filters
|
|
43
|
-
* @private
|
|
44
|
-
*/
|
|
45
|
-
private setupComponents;
|
|
46
|
-
/**
|
|
47
|
-
* Sets up global error handlers for the application
|
|
48
|
-
* Configures handlers for 404 Not Found and general error cases
|
|
49
|
-
* @private
|
|
50
|
-
*/
|
|
51
20
|
private setupErrorHandlers;
|
|
52
|
-
/**
|
|
53
|
-
* Resolves a plugin from either a constructor or instance
|
|
54
|
-
* @param pluginType - Plugin constructor or instance
|
|
55
|
-
* @returns Resolved plugin instance
|
|
56
|
-
* @private
|
|
57
|
-
* @throws {Error} If plugin instantiation fails
|
|
58
|
-
*/
|
|
59
21
|
private resolvePlugin;
|
|
60
|
-
/**
|
|
61
|
-
* Normalizes a plugin entry to a resolved plugin with pre/post processor arrays.
|
|
62
|
-
* @param entry - Plugin entry (plain plugin or object with plugin and processors)
|
|
63
|
-
* @returns Normalized entry with plugin instance and processor arrays
|
|
64
|
-
* @private
|
|
65
|
-
*/
|
|
66
22
|
private normalizePluginEntry;
|
|
67
|
-
/**
|
|
68
|
-
* Registers a module with the application
|
|
69
|
-
* Processes the module's metadata and registers its controllers
|
|
70
|
-
*
|
|
71
|
-
* @param moduleClass - The module class to register
|
|
72
|
-
* @returns The application instance for method chaining
|
|
73
|
-
* @throws {Error} If module registration fails
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* ```ts
|
|
77
|
-
* const app = new Application();
|
|
78
|
-
* await app.register(UsersModule)
|
|
79
|
-
* .register(AuthModule);
|
|
80
|
-
* ```
|
|
81
|
-
*/
|
|
82
23
|
register(moduleClass: Constructor): Promise<Application>;
|
|
83
|
-
/**
|
|
84
|
-
* Creates and initializes a new application with a root module
|
|
85
|
-
*
|
|
86
|
-
* Process:
|
|
87
|
-
* 1. Creates application instance with provided options
|
|
88
|
-
* 2. Initializes and runs plugin lifecycle hooks
|
|
89
|
-
* 3. Registers the root module
|
|
90
|
-
* 4. Returns both the application and Hono instances
|
|
91
|
-
*
|
|
92
|
-
* @param rootModule - The root module class for the application
|
|
93
|
-
* @param options - Application configuration options
|
|
94
|
-
* @returns Object containing the application and Hono instances
|
|
95
|
-
* @throws {Error} If application creation or module registration fails
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* ```ts
|
|
99
|
-
* const { app, hono } = await Application.create(AppModule, {
|
|
100
|
-
* routing: { prefix: '/api' }
|
|
101
|
-
* });
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
24
|
static create(rootModule: Constructor, options?: HonestOptions): Promise<{
|
|
105
25
|
app: Application;
|
|
106
26
|
hono: Hono;
|
|
107
27
|
}>;
|
|
108
|
-
/**
|
|
109
|
-
* Gets the underlying Hono instance for direct access
|
|
110
|
-
* Use this method when you need to access Hono-specific features
|
|
111
|
-
*
|
|
112
|
-
* @returns The Hono application instance
|
|
113
|
-
* @example
|
|
114
|
-
* ```ts
|
|
115
|
-
* const hono = app.getApp();
|
|
116
|
-
* hono.use(someHonoMiddleware());
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
28
|
getApp(): Hono;
|
|
120
|
-
/**
|
|
121
|
-
* Gets the app-level registry (context) where your app can publish and read pipeline data by key.
|
|
122
|
-
* Use namespaced keys (e.g. 'app.config', 'openapi.spec') and document contracts in your app.
|
|
123
|
-
*
|
|
124
|
-
* @returns The application context instance
|
|
125
|
-
* @example
|
|
126
|
-
* ```ts
|
|
127
|
-
* app.getContext().set('app.config', { env: process.env.NODE_ENV })
|
|
128
|
-
* const config = app.getContext().get<{ env: string }>('app.config')
|
|
129
|
-
* ```
|
|
130
|
-
*/
|
|
131
29
|
getContext(): IApplicationContext;
|
|
132
|
-
/**
|
|
133
|
-
* Gets information about all registered routes in the application
|
|
134
|
-
* Useful for documentation and debugging purposes
|
|
135
|
-
*
|
|
136
|
-
* @returns Array of route information objects (read-only)
|
|
137
|
-
* @example
|
|
138
|
-
* ```ts
|
|
139
|
-
* const routes = app.getRoutes();
|
|
140
|
-
* console.log(routes.map(r => r.path));
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
30
|
getRoutes(): ReadonlyArray<RouteInfo>;
|
|
144
31
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
package/dist/di/container.d.ts
CHANGED
|
@@ -11,14 +11,19 @@ export declare class Container implements DiContainer {
|
|
|
11
11
|
/**
|
|
12
12
|
* Resolves a class instance, creating it if necessary and injecting its dependencies
|
|
13
13
|
* @param target - The class constructor to resolve
|
|
14
|
-
* @param resolving - A set of classes currently being resolved, for circular dependency detection
|
|
15
14
|
* @returns An instance of the target class
|
|
16
15
|
*/
|
|
17
|
-
resolve<T>(target: Constructor<T
|
|
16
|
+
resolve<T>(target: Constructor<T>): T;
|
|
17
|
+
/**
|
|
18
|
+
* Internal recursive resolver with circular dependency tracking
|
|
19
|
+
*/
|
|
20
|
+
private resolveWithTracking;
|
|
18
21
|
/**
|
|
19
22
|
* Registers a pre-created instance for a class
|
|
20
23
|
* @param target - The class constructor to register
|
|
21
24
|
* @param instance - The instance to register
|
|
22
25
|
*/
|
|
23
26
|
register<T>(target: Constructor<T>, instance: T): void;
|
|
27
|
+
has<T>(target: Constructor<T>): boolean;
|
|
28
|
+
clear(): void;
|
|
24
29
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import"reflect-metadata";import{Hono as t}from"hono";class M{store=new Map;get($){return this.store.get($)}set($,_){this.store.set($,_)}has($){return this.store.has($)}delete($){return this.store.delete($)}keys(){return this.store.keys()}}class C{instances=new Map;resolve($,_=new Set){if(this.instances.has($))return this.instances.get($);if(_.has($))throw Error(`Circular dependency detected: ${[..._.keys(),$].map((Q)=>Q.name).join(" -> ")}`);_.add($);let W=Reflect.getMetadata("design:paramtypes",$)||[];if($.length>0&&W.length===0)throw Error(`Cannot resolve dependencies for ${$.name}: constructor metadata is missing. Ensure 'reflect-metadata' is imported and 'emitDecoratorMetadata' is enabled.`);let Y=W.map((Q,B)=>{if(!Q||Q===Object||Q===Array||Q===Function)throw Error(`Cannot resolve dependency at index ${B} of ${$.name}. Use concrete class types for constructor dependencies.`);return this.resolve(Q,new Set(_))}),q=new $(...Y);return this.instances.set($,q),q}register($,_){this.instances.set($,_)}}import{HTTPException as r}from"hono/http-exception";function R($,_,W){let Y=new Date().toISOString(),q=_.get("requestId"),Q=_.req.path;if($ instanceof r)return{response:{status:W?.status||$.status,message:W?.title||$.message,timestamp:Y,path:Q,requestId:q,code:W?.code,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:W?.status||$.status};if($.statusCode||$.status){let L=$.statusCode||$.status,A=W?.status||L;return{response:{status:A,message:W?.title||$.message,timestamp:Y,path:Q,requestId:q,code:W?.code||$.name,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:A}}let B=W?.status||500;return{response:{status:B,message:W?.title||$.message,timestamp:Y,path:Q,requestId:q,code:W?.code||$.name,details:W?.additionalDetails||{stack:$.stack},...W?.detail&&{detail:W.detail}},status:B}}class X{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($){return this.routes.get($)||[]}static setRoutes($,_){this.routes.set($,_)}static addRoute($,_){if(!this.routes.has($))this.routes.set($,[]);this.routes.get($).push(_)}static getControllerPath($){return this.controllers.get($)||""}static hasController($){return this.controllers.has($)}static setControllerPath($,_){this.controllers.set($,_)}static getControllerOptions($){return this.controllerOptions.get($)||{}}static setControllerOptions($,_){this.controllerOptions.set($,_)}static isService($){return this.services.has($)}static addService($){this.services.add($)}static getAllServices(){return this.services}static getModuleOptions($){return this.modules.get($)}static setModuleOptions($,_){this.modules.set($,_)}static getParameters($){return this.parameters.get($)||new Map}static setParameterMap($,_){this.parameters.set($,_)}static getContextIndices($){return this.contextIndices.get($)||new Map}static setContextIndices($,_){this.contextIndices.set($,_)}static registerGlobal($,_){this.global.get($).add(_)}static getGlobal($){return this.global.get($)}static registerController($,_,W){let Y=this.controller.get($);if(!Y.has(_))Y.set(_,[]);Y.get(_).push(W)}static getController($,_){return this.controller.get($).get(_)||[]}static registerHandler($,_,W){let Y=this.handler.get($);if(!Y.has(_))Y.set(_,[]);Y.get(_).push(W)}static getHandler($,_){return this.handler.get($).get(_)||[]}static clear(){this.routes.clear(),this.controllers.clear(),this.controllerOptions.clear(),this.services.clear(),this.modules.clear(),this.parameters.clear(),this.contextIndices.clear();for(let $ of this.global.values())$.clear();for(let $ of this.controller.values())$.clear();for(let $ of this.handler.values())$.clear()}}class T{static routes=[];static registerRoute($){if(!$)throw Error("Route info is required");if(!$.controller)throw Error("Route controller is required");if(!$.handler)throw Error("Route handler is required");if(!$.method)throw Error("Route method is required");if(!$.fullPath)throw Error("Route fullPath is required");if(this.routes.some((W)=>W.fullPath===$.fullPath&&W.method.toUpperCase()===$.method.toUpperCase()))throw Error(`Duplicate route detected: ${$.method.toUpperCase()} ${$.fullPath} (${String($.controller)}.${String($.handler)})`);this.routes.push($)}static getRoutes(){return this.routes}static getRoutesByController($){return this.routes.filter((_)=>_.controller===$)}static getRoutesByMethod($){return this.routes.filter((_)=>_.method.toUpperCase()===$.toUpperCase())}static getRoutesByPath($){return this.routes.filter((_)=>$.test(_.fullPath))}static clear(){this.routes.length=0}}function H($){return(_="",W={})=>{return(Y,q,Q)=>{let B=Y.constructor;X.addRoute(B,{path:_,method:$,handlerName:q,parameterMetadata:[],version:W.version,prefix:W.prefix})}}}function E($,_){let W=(Y,q)=>{if(Y===void 0)return q;return q.get(Y)};return(Y)=>{return(q,Q,B)=>{let Z=q.constructor;if(!X.getParameters(Z).size)X.setParameterMap(Z,new Map);let L=X.getParameters(Z);if(!L.has(Q))L.set(Q,[]);let z=Reflect.getMetadata("design:paramtypes",q,Q)?.[B];if(L.get(Q).push({index:B,name:$,data:Y,factory:_||W,metatype:z}),$==="context"){if(!X.getContextIndices(Z).size)X.setContextIndices(Z,new Map);X.getContextIndices(Z).set(Q,B)}}}}class x{static handle(){return async($,_)=>{let{response:W,status:Y}=R($,_);return _.json(W,Y)}}}class I{static handle(){return async($)=>{return $.json({message:`Not Found - ${$.req.path}`},404)}}}var N$=($)=>typeof $>"u",N=($)=>$===null||typeof $>"u",O=($)=>$!==null&&typeof $==="object",b$=($)=>{if(!O($))return!1;let _=Object.getPrototypeOf($);if(_===null)return!0;let W=Object.prototype.hasOwnProperty.call(_,"constructor")&&_.constructor;return typeof W==="function"&&W instanceof W&&Function.prototype.toString.call(W)===Function.prototype.toString.call(Object)},i=($)=>typeof $==="function",v=($)=>typeof $==="string",w$=($)=>typeof $==="number",P$=($)=>$.length===0,K$=($)=>typeof $==="symbol",R$=($)=>typeof $==="string"?$.charAt(0)!=="/"?"/"+$:$:"",y=($)=>$?$.startsWith("/")?("/"+$.replace(/\/+$/,"")).replace(/\/+/g,"/"):"/"+$.replace(/\/+$/,""):"/",f$=($)=>$.endsWith("/")?$.slice(0,-1):$,c=($)=>{return i($)&&!N($.prototype)&&!i($.prototype)&&Object.getOwnPropertyNames($.prototype).length>=1};class J{static container;static init($){this.container=$}static setupGlobalComponents($){let _=$.components||{};if(_.middleware)this.registerGlobal("middleware",..._.middleware);if(_.guards)this.registerGlobal("guard",..._.guards);if(_.pipes)this.registerGlobal("pipe",..._.pipes);if(_.filters)this.registerGlobal("filter",..._.filters)}static registerGlobal($,..._){_.forEach((W)=>{X.registerGlobal($,W)})}static registerController($,_,...W){W.forEach((Y)=>{X.registerController($,_,Y)})}static registerHandler($,_,W,...Y){let q=`${_.name}:${String(W)}`;Y.forEach((Q)=>{X.registerHandler($,q,Q)})}static getComponents($,_,W){let Y=`${_.name}:${String(W)}`,q=X.getHandler($,Y),Q=X.getController($,_);return[...Array.from(X.getGlobal($)),...Q,...q]}static resolveMiddleware($){return $.map((_)=>{if(O(_)&&"use"in _)return _.use.bind(_);let W=this.container.resolve(_);return W.use.bind(W)})}static getHandlerMiddleware($,_){let W=this.getComponents("middleware",$,_);return this.resolveMiddleware(W)}static getGlobalMiddleware(){let $=Array.from(X.getGlobal("middleware"));return this.resolveMiddleware($)}static resolveGuards($){return $.map((_)=>{if(O(_)&&"canActivate"in _)return _;return this.container.resolve(_)})}static getHandlerGuards($,_){let W=this.getComponents("guard",$,_);return this.resolveGuards(W)}static resolvePipes($){return $.map((_)=>{if(O(_)&&"transform"in _)return _;return this.container.resolve(_)})}static getHandlerPipes($,_){let W=this.getComponents("pipe",$,_);return this.resolvePipes(W)}static async executePipes($,_,W){let Y=$;for(let q of W)Y=await q.transform(Y,_);return Y}static async handleException($,_){let W=_.get("controllerClass"),Y=_.get("handlerName");if(W&&Y){let Z=X.getHandler("filter",`${W.name}:${Y}`);if(Z.length>0){let L=await this.executeFilters(Z,$,_);if(L)return L}}if(W){let Z=X.getController("filter",W);if(Z.length>0){let L=await this.executeFilters(Z,$,_);if(L)return L}}let q=Array.from(X.getGlobal("filter"));if(q.length>0){let Z=await this.executeFilters(q,$,_);if(Z)return Z}let{response:Q,status:B}=R($,_);return _.json(Q,B)}static async executeFilters($,_,W){for(let Y of $){let q;if(O(Y)&&"catch"in Y)q=Y;else q=this.container.resolve(Y);try{let Q=await q.catch(_,W);if(Q!==void 0)return Q}catch(Q){console.error("Error in exception filter:",Q)}}return}static async registerModule($,_){let W=X.getModuleOptions($);if(!W)throw Error(`Module ${$.name} is not properly decorated with @Module()`);let Y=[];if(W.imports&&W.imports.length>0)for(let q of W.imports){let Q=await this.registerModule(q,_);Y.push(...Q)}if(W.services&&W.services.length>0)for(let q of W.services)_.resolve(q);if(W.controllers&&W.controllers.length>0)Y.push(...W.controllers);return Y}}import{HTTPException as o}from"hono/http-exception";var h=Symbol("VERSION_NEUTRAL");class g{hono;container;globalPrefix;globalVersion;constructor($,_,W={}){this.hono=$,this.container=_,this.globalPrefix=W.prefix!==void 0?this.normalizePath(W.prefix):void 0,this.globalVersion=W.version,this.applyGlobalMiddleware()}applyGlobalMiddleware(){let $=J.getGlobalMiddleware();for(let _ of $)this.hono.use("*",_)}normalizePath($){if(v($))return y($);return $?`/${$}`:""}registerRouteHandler($,_,W,Y){if(W.length>0)this.hono.on($.toUpperCase(),_,...W,Y);else this.hono.on($.toUpperCase(),_,Y)}buildRoutePath($,_,W,Y){return y(`${$}${_}${W}${Y}`)}formatVersionSegment($){if(N($))return"";return $===h?"":`/v${String($)}`}async registerController($){if(!X.hasController($))throw Error(`Controller ${$.name} is not decorated with @Controller()`);let _=X.getControllerPath($)||"",W=X.getControllerOptions($)||{},Y=X.getRoutes($)||[],q=X.getParameters($)||new Map,Q=X.getContextIndices($)||new Map,B=this.normalizePath(_),Z=this.container.resolve($),L=W.prefix!==void 0?W.prefix:this.globalPrefix,A=W.version!==void 0?W.version:this.globalVersion;if(Y.length===0)throw Error(`Controller ${$.name} has no route handlers. Add HTTP method decorators like @Get()`);for(let z of Y){let{path:j,method:V,handlerName:f,version:b,prefix:w}=z,P=w!==void 0?w:L,S=!N(P)?this.normalizePath(P):"",G=b!==void 0?b:A,k=this.normalizePath(j);if(N(G)){this.registerRoute(Z,z,q,Q,$,S,"",B,k,V);continue}if(G===h){this.registerRoute(Z,z,q,Q,$,S,"",B,k,V),this.registerRoute(Z,z,q,Q,$,S,"/:version{v[0-9]+}",B,k,V);continue}if(Array.isArray(G)){for(let D of G){let F=this.formatVersionSegment(D);this.registerRoute(Z,z,q,Q,$,S,F,B,k,V)}continue}let K=this.formatVersionSegment(G);this.registerRoute(Z,z,q,Q,$,S,K,B,k,V)}}registerRoute($,_,W,Y,q,Q,B,Z,L,A){let{handlerName:z}=_,j=this.buildRoutePath(Q,B,Z,L),V=$[z].bind($),f=W.get(z)||[],b=Y.get(z),w=J.getHandlerMiddleware(q,z),P=J.getHandlerPipes(q,z);T.registerRoute({controller:q.name,handler:z,method:A,prefix:Q,version:B,route:Z,path:L,fullPath:j,parameters:f});let S=async(G)=>{try{G.set("controllerClass",q),G.set("handlerName",String(z));let k=J.getHandlerGuards(q,z);for(let F of k)if(!await F.canActivate(G))throw new o(403,{message:`Forbidden by ${F.constructor?.name||"UnknownGuard"} at ${q.name}.${String(z)}`});let K=Array(V.length);for(let F of f){if(typeof F.factory!=="function")throw Error(`Invalid parameter decorator metadata for ${q.name}.${String(z)}`);let d=F.factory(F.data,G),a=await J.executePipes(d,{type:F.name,metatype:F.metatype,data:F.data},P);K[F.index]=a}let D=await V(...K);if(b!==void 0)return D;if(D instanceof Response)return D;if(N(D))return G.json(null);if(v(D))return G.text(D);return G.json(D)}catch(k){return J.handleException(k,G)}};this.registerRouteHandler(A,j,w,S)}}class p{hono;container;context;routeManager;options;constructor($={}){if(this.options=O($)?$:{},T.clear(),this.hono=new t(this.options.hono),this.container=this.options.container||new C,this.context=new M,this.setupComponents(),this.setupErrorHandlers(),this.routeManager=new g(this.hono,this.container,{prefix:this.options.routing?.prefix,version:this.options.routing?.version}),this.options.deprecations?.printPreV1Warning)console.warn("[HonestJS] Pre-v1 warning: APIs may change before 1.0.0.")}setupComponents(){J.init(this.container),J.setupGlobalComponents(this.options)}setupErrorHandlers(){this.hono.notFound(this.options.notFound||I.handle()),this.hono.onError(this.options.onError||x.handle())}resolvePlugin($){if(c($))return new $;return $}normalizePluginEntry($){if($&&typeof $==="object"&&"plugin"in $){let _=$;return{plugin:this.resolvePlugin(_.plugin),preProcessors:_.preProcessors??[],postProcessors:_.postProcessors??[]}}return{plugin:this.resolvePlugin($),preProcessors:[],postProcessors:[]}}async register($){let _=await J.registerModule($,this.container);for(let W of _)await this.routeManager.registerController(W);return this}static async create($,_={}){let W=new p(_),Y=(_.plugins||[]).map((A)=>W.normalizePluginEntry(A)),q=W.getContext(),Q=_.debug,B=Q===!0||typeof Q==="object"&&Q.plugins,Z=Q===!0||typeof Q==="object"&&Q.routes;if(B&&Y.length>0)console.info("[HonestJS] Plugin order:",Y.map(({plugin:A})=>A.constructor?.name||"AnonymousPlugin").join(" -> "));for(let{plugin:A,preProcessors:z}of Y){for(let j of z)await j(W,W.hono,q);if(A.beforeModulesRegistered)await A.beforeModulesRegistered(W,W.hono)}await W.register($);let L=W.getRoutes();if(_.strict?.requireRoutes&&L.length===0)throw Error("Strict mode: no routes were registered. Check your module/controller decorators.");if(Z)console.info("[HonestJS] Registered routes:",L.map((A)=>`${A.method.toUpperCase()} ${A.fullPath}`));for(let{plugin:A,postProcessors:z}of Y){if(A.afterModulesRegistered)await A.afterModulesRegistered(W,W.hono);for(let j of z)await j(W,W.hono,q)}return{app:W,hono:W.getApp()}}getApp(){return this.hono}getContext(){return this.context}getRoutes(){return T.getRoutes()}}import{html as U,raw as u}from"hono/html";var e={type:"website",locale:"en_US"},m=($)=>{if(!$)return"";return Object.entries($).map(([_,W])=>{if(typeof W==="boolean")return W?_:"";let Y=String(W).replace(/"/g,""");return`${_}="${Y}"`}).filter(Boolean).join(" ")},X_=($)=>{let _={...e,...$};return U`
|
|
1
|
+
import"reflect-metadata";import{Hono as $$}from"hono";class C{store=new Map;get($){return this.store.get($)}set($,_){this.store.set($,_)}has($){return this.store.has($)}delete($){return this.store.delete($)}keys(){return this.store.keys()}}class Z{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 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($){return this.routes.get($)||[]}static setRoutes($,_){this.routes.set($,_)}static addRoute($,_){if(!this.routes.has($))this.routes.set($,[]);this.routes.get($).push(_)}static getControllerPath($){return this.controllers.get($)||""}static hasController($){return this.controllers.has($)}static setControllerPath($,_){this.controllers.set($,_)}static getControllerOptions($){return this.controllerOptions.get($)||{}}static setControllerOptions($,_){this.controllerOptions.set($,_)}static isService($){return this.services.has($)}static addService($){this.services.add($)}static getAllServices(){return this.services}static getModuleOptions($){return this.modules.get($)}static setModuleOptions($,_){this.modules.set($,_)}static getParameters($){return this.parameters.get($)||new Map}static setParameterMap($,_){this.parameters.set($,_)}static getContextIndices($){return this.contextIndices.get($)||new Map}static setContextIndices($,_){this.contextIndices.set($,_)}static registerController($,_,W){let Y=this.controller.get($);if(!Y.has(_))Y.set(_,[]);Y.get(_).push(W)}static getController($,_){return this.controller.get($).get(_)||[]}static registerHandler($,_,W){let Y=this.handler.get($);if(!Y.has(_))Y.set(_,[]);Y.get(_).push(W)}static getHandler($,_){return this.handler.get($).get(_)||[]}static clear(){this.routes.clear(),this.controllers.clear(),this.controllerOptions.clear(),this.services.clear(),this.modules.clear(),this.parameters.clear(),this.contextIndices.clear();for(let $ of this.controller.values())$.clear();for(let $ of this.handler.values())$.clear()}}class M{routes=[];registerRoute($){if(!$)throw Error("Route info is required");if(!$.controller)throw Error("Route controller is required");if(!$.handler)throw Error("Route handler is required");if(!$.method)throw Error("Route method is required");if(!$.fullPath)throw Error("Route fullPath is required");if(this.routes.some((W)=>W.fullPath===$.fullPath&&W.method.toUpperCase()===$.method.toUpperCase()))throw Error(`Duplicate route detected: ${$.method.toUpperCase()} ${$.fullPath} (${String($.controller)}.${String($.handler)})`);this.routes.push($)}getRoutes(){return this.routes}getRoutesByController($){return this.routes.filter((_)=>_.controller===$)}getRoutesByMethod($){return this.routes.filter((_)=>_.method.toUpperCase()===$.toUpperCase())}getRoutesByPath($){return this.routes.filter((_)=>$.test(_.fullPath))}clear(){this.routes.length=0}}class f{instances=new Map;resolve($){return this.resolveWithTracking($,new Set)}resolveWithTracking($,_){if(this.instances.has($))return this.instances.get($);if(_.has($))throw Error(`Circular dependency detected: ${[..._.keys(),$].map((X)=>X.name).join(" -> ")}`);_.add($);let W=Reflect.getMetadata("design:paramtypes",$)||[];if($.length>0&&W.length===0){if(!Z.isService($))throw Error(`Cannot resolve ${$.name}: it is not decorated with @Service(). Did you forget to add @Service() to the class?`);throw Error(`Cannot resolve dependencies for ${$.name}: constructor metadata is missing. Ensure 'reflect-metadata' is imported and 'emitDecoratorMetadata' is enabled.`)}let Y=W.map((X,B)=>{if(!X||X===Object||X===Array||X===Function)throw Error(`Cannot resolve dependency at index ${B} of ${$.name}. Use concrete class types for constructor dependencies.`);return this.resolveWithTracking(X,new Set(_))}),Q=new $(...Y);return this.instances.set($,Q),Q}register($,_){this.instances.set($,_)}has($){return this.instances.has($)}clear(){this.instances.clear()}}import{HTTPException as t}from"hono/http-exception";function b($,_,W){let Y=new Date().toISOString(),Q=_.get("requestId"),X=_.req.path;if($ instanceof t)return{response:{status:W?.status||$.status,message:W?.title||$.message,timestamp:Y,path:X,requestId:Q,code:W?.code,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:W?.status||$.status};if($.statusCode||$.status){let q=$.statusCode||$.status,z=W?.status||q;return{response:{status:z,message:W?.title||$.message,timestamp:Y,path:X,requestId:Q,code:W?.code||$.name,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:z}}let B=W?.status||500;return{response:{status:B,message:W?.title||$.message,timestamp:Y,path:X,requestId:Q,code:W?.code||$.name,details:W?.additionalDetails||{stack:$.stack},...W?.detail&&{detail:W.detail}},status:B}}function k($){return(_="",W={})=>{return(Y,Q,X)=>{let B=Y.constructor;Z.addRoute(B,{path:_,method:$,handlerName:Q,version:W.version,prefix:W.prefix})}}}function j($,_){let W=(Y,Q)=>{if(Y===void 0)return Q;return Q.get(Y)};return(Y)=>{return(Q,X,B)=>{let J=Q.constructor;if(!Z.getParameters(J).size)Z.setParameterMap(J,new Map);let q=Z.getParameters(J);if(!q.has(X))q.set(X,[]);let U=Reflect.getMetadata("design:paramtypes",Q,X)?.[B];if(q.get(X).push({index:B,name:$,data:Y,factory:_||W,metatype:U}),$==="context"){if(!Z.getContextIndices(J).size)Z.setContextIndices(J,new Map);Z.getContextIndices(J).set(X,B)}}}}class x{static handle(){return async($,_)=>{let{response:W,status:Y}=b($,_);return _.json(W,Y)}}}class I{static handle(){return async($)=>{return $.json({message:`Not Found - ${$.req.path}`},404)}}}var K$=($)=>typeof $>"u",T=($)=>$===null||typeof $>"u",O=($)=>$!==null&&typeof $==="object",w$=($)=>{if(!O($))return!1;let _=Object.getPrototypeOf($);if(_===null)return!0;let W=Object.prototype.hasOwnProperty.call(_,"constructor")&&_.constructor;return typeof W==="function"&&W instanceof W&&Function.prototype.toString.call(W)===Function.prototype.toString.call(Object)},p=($)=>typeof $==="function",v=($)=>typeof $==="string",R$=($)=>typeof $==="number",C$=($)=>$.length===0,M$=($)=>typeof $==="symbol",f$=($)=>typeof $==="string"?$.charAt(0)!=="/"?"/"+$:$:"",y=($)=>$?$.startsWith("/")?("/"+$.replace(/\/+$/,"")).replace(/\/+/g,"/"):"/"+$.replace(/\/+$/,""):"/",x$=($)=>$.endsWith("/")?$.slice(0,-1):$,s=($)=>{return p($)&&!T($.prototype)&&!p($.prototype)&&Object.getOwnPropertyNames($.prototype).length>=1};class g{container;globalComponents=new Map([["middleware",new Set],["guard",new Set],["pipe",new Set],["filter",new Set]]);constructor($){this.container=$}setupGlobalComponents($){let _=$.components||{};if(_.middleware)this.registerGlobal("middleware",..._.middleware);if(_.guards)this.registerGlobal("guard",..._.guards);if(_.pipes)this.registerGlobal("pipe",..._.pipes);if(_.filters)this.registerGlobal("filter",..._.filters)}registerGlobal($,..._){_.forEach((W)=>{this.globalComponents.get($).add(W)})}getGlobal($){return this.globalComponents.get($)}getComponents($,_,W){let Y=`${_.name}:${String(W)}`,Q=Z.getHandler($,Y),X=Z.getController($,_);return[...Array.from(this.globalComponents.get($)||[]),...X,...Q]}resolveMiddleware($){return $.map((_)=>{if(O(_)&&"use"in _)return _.use.bind(_);let W=this.container.resolve(_);return W.use.bind(W)})}getHandlerMiddleware($,_){let W=this.getComponents("middleware",$,_);return this.resolveMiddleware(W)}getGlobalMiddleware(){let $=Array.from(this.globalComponents.get("middleware")||[]);return this.resolveMiddleware($)}resolveGuards($){return $.map((_)=>{if(O(_)&&"canActivate"in _)return _;return this.container.resolve(_)})}getHandlerGuards($,_){let W=this.getComponents("guard",$,_);return this.resolveGuards(W)}resolvePipes($){return $.map((_)=>{if(O(_)&&"transform"in _)return _;return this.container.resolve(_)})}getHandlerPipes($,_){let W=this.getComponents("pipe",$,_);return this.resolvePipes(W)}async executePipes($,_,W){let Y=$;for(let Q of W)Y=await Q.transform(Y,_);return Y}async handleException($,_){let W=_.get("__honest_controllerClass"),Y=_.get("__honest_handlerName");if(W&&Y){let J=Z.getHandler("filter",`${W.name}:${Y}`);if(J.length>0){let q=await this.executeFilters(J,$,_);if(q)return q}}if(W){let J=Z.getController("filter",W);if(J.length>0){let q=await this.executeFilters(J,$,_);if(q)return q}}let Q=Array.from(this.globalComponents.get("filter")||[]);if(Q.length>0){let J=await this.executeFilters(Q,$,_);if(J)return J}let{response:X,status:B}=b($,_);return _.json(X,B)}async executeFilters($,_,W){for(let Y of $){let Q;if(O(Y)&&"catch"in Y)Q=Y;else Q=this.container.resolve(Y);try{let X=await Q.catch(_,W);if(X!==void 0)return X}catch(X){let B=Q.constructor?.name||"UnknownFilter";console.error(`Error in exception filter ${B}:`,X);let{response:J,status:q}=b(X,W);return W.json(J,q)}}return}async registerModule($,_=new Set){if(_.has($))return[];_.add($);let W=Z.getModuleOptions($);if(!W)throw Error(`Module ${$.name} is not properly decorated with @Module()`);let Y=[];if(W.imports&&W.imports.length>0)for(let Q of W.imports){let X=await this.registerModule(Q,_);Y.push(...X)}if(W.services&&W.services.length>0)for(let Q of W.services)this.container.resolve(Q);if(W.controllers&&W.controllers.length>0)Y.push(...W.controllers);return Y}}import{HTTPException as e}from"hono/http-exception";var h=Symbol("VERSION_NEUTRAL");class m{hono;container;routeRegistry;componentManager;globalPrefix;globalVersion;constructor($,_,W,Y,Q={}){this.hono=$,this.container=_,this.routeRegistry=W,this.componentManager=Y,this.globalPrefix=Q.prefix!==void 0?this.normalizePath(Q.prefix):void 0,this.globalVersion=Q.version,this.applyGlobalMiddleware()}applyGlobalMiddleware(){let $=this.componentManager.getGlobalMiddleware();for(let _ of $)this.hono.use("*",_)}normalizePath($){if(!v($))throw Error(`Invalid path: expected a string but received ${typeof $}. Check your @Controller() and route decorator arguments.`);return y($)}registerRouteHandler($,_,W,Y){if(W.length>0)this.hono.on($.toUpperCase(),_,...W,Y);else this.hono.on($.toUpperCase(),_,Y)}buildRoutePath($,_,W,Y){return y(`${$}${_}${W}${Y}`)}formatVersionSegment($){if(T($))return"";return $===h?"":`/v${String($)}`}async registerController($){if(!Z.hasController($))throw Error(`Controller ${$.name} is not decorated with @Controller()`);let _=Z.getControllerPath($)||"",W=Z.getControllerOptions($)||{},Y=Z.getRoutes($)||[],Q=Z.getParameters($)||new Map,X=Z.getContextIndices($)||new Map,B=this.normalizePath(_),J=this.container.resolve($),q=W.prefix!==void 0?W.prefix:this.globalPrefix,z=W.version!==void 0?W.version:this.globalVersion;if(Y.length===0)throw Error(`Controller ${$.name} has no route handlers. Add HTTP method decorators like @Get()`);for(let U of Y){let{path:E,method:V,version:H,prefix:K}=U,w=K!==void 0?K:q,D=!T(w)?this.normalizePath(w):"",A=H!==void 0?H:z,S=this.normalizePath(E);if(T(A)){this.registerRoute(J,U,Q,X,$,D,"",B,S,V);continue}if(A===h){this.registerRoute(J,U,Q,X,$,D,"",B,S,V),this.registerRoute(J,U,Q,X,$,D,"/:version{v[0-9]+}",B,S,V);continue}if(Array.isArray(A)){for(let P of A){let R=this.formatVersionSegment(P);this.registerRoute(J,U,Q,X,$,D,R,B,S,V)}continue}let F=this.formatVersionSegment(A);this.registerRoute(J,U,Q,X,$,D,F,B,S,V)}}registerRoute($,_,W,Y,Q,X,B,J,q,z){let{handlerName:U}=_,E=this.buildRoutePath(X,B,J,q),V=$[U].bind($),H=W.get(U)||[],K=Y.get(U),w=this.componentManager.getHandlerMiddleware(Q,U),D=this.componentManager.getHandlerPipes(Q,U);this.routeRegistry.registerRoute({controller:Q.name,handler:U,method:z,prefix:X,version:B,route:J,path:q,fullPath:E,parameters:H});let A=this.componentManager,S=async(F)=>{try{F.set("__honest_controllerClass",Q),F.set("__honest_handlerName",String(U));let P=A.getHandlerGuards(Q,U);for(let G of P)if(!await G.canActivate(F))throw new e(403,{message:`Forbidden by ${G.constructor?.name||"UnknownGuard"} at ${Q.name}.${String(U)}`});let R=H.length>0?Math.max(...H.map((G)=>G.index)):-1,c=Array(Math.max(V.length,R+1));for(let G of H){if(typeof G.factory!=="function")throw Error(`Invalid parameter decorator metadata for ${Q.name}.${String(U)}`);let i=G.factory(G.data,F),r=await A.executePipes(i,{type:G.name,metatype:G.metatype,data:G.data},D);c[G.index]=r}let N=await V(...c);if(K!==void 0)return N;if(N instanceof Response)return N;if(T(N))return F.json(null);if(v(N))return F.text(N);return F.json(N)}catch(P){return A.handleException(P,F)}};this.registerRouteHandler(z,E,w,S)}}class l{hono;container;context;routeRegistry;componentManager;routeManager;options;constructor($={}){if(this.options=O($)?$:{},this.hono=new $$(this.options.hono),this.container=this.options.container||new f,this.context=new C,this.routeRegistry=new M,this.componentManager=new g(this.container),this.componentManager.setupGlobalComponents(this.options),this.setupErrorHandlers(),this.routeManager=new m(this.hono,this.container,this.routeRegistry,this.componentManager,{prefix:this.options.routing?.prefix,version:this.options.routing?.version}),this.options.deprecations?.printPreV1Warning)console.warn("[HonestJS] Pre-v1 warning: APIs may change before 1.0.0.")}setupErrorHandlers(){this.hono.notFound(this.options.notFound||I.handle()),this.hono.onError(this.options.onError||x.handle())}resolvePlugin($){if(s($))return new $;return $}normalizePluginEntry($){if($&&typeof $==="object"&&"plugin"in $){let _=$;return{plugin:this.resolvePlugin(_.plugin),preProcessors:_.preProcessors??[],postProcessors:_.postProcessors??[]}}return{plugin:this.resolvePlugin($),preProcessors:[],postProcessors:[]}}async register($){let _=await this.componentManager.registerModule($);for(let W of _)await this.routeManager.registerController(W);return this}static async create($,_={}){let W=new l(_),Y=(_.plugins||[]).map((z)=>W.normalizePluginEntry(z)),Q=W.getContext(),X=_.debug,B=X===!0||typeof X==="object"&&X.plugins,J=X===!0||typeof X==="object"&&X.routes;if(B&&Y.length>0)console.info("[HonestJS] Plugin order:",Y.map(({plugin:z})=>z.constructor?.name||"AnonymousPlugin").join(" -> "));for(let{plugin:z,preProcessors:U}of Y){for(let E of U)await E(W,W.hono,Q);if(z.beforeModulesRegistered)await z.beforeModulesRegistered(W,W.hono)}await W.register($);let q=W.getRoutes();if(_.strict?.requireRoutes&&q.length===0)throw Error("Strict mode: no routes were registered. Check your module/controller decorators.");if(J)console.info("[HonestJS] Registered routes:",q.map((z)=>`${z.method.toUpperCase()} ${z.fullPath}`));for(let{plugin:z,postProcessors:U}of Y){if(z.afterModulesRegistered)await z.afterModulesRegistered(W,W.hono);for(let E of U)await E(W,W.hono,Q)}return{app:W,hono:W.getApp()}}getApp(){return this.hono}getContext(){return this.context}getRoutes(){return this.routeRegistry.getRoutes()}}import{html as L,raw as u}from"hono/html";var _$={type:"website",locale:"en_US"},d=($)=>{if(!$)return"";return Object.entries($).map(([_,W])=>{if(typeof W==="boolean")return W?_:"";let Y=String(W).replace(/"/g,""");return`${_}="${Y}"`}).filter(Boolean).join(" ")},B_=($)=>{let _={..._$,...$};return L`
|
|
2
2
|
<!DOCTYPE html>
|
|
3
|
-
<html lang="${_.locale?.split("_")[0]||"en"}" ${u(
|
|
4
|
-
<head ${u(
|
|
3
|
+
<html lang="${_.locale?.split("_")[0]||"en"}" ${u(d(_.htmlAttributes))}>
|
|
4
|
+
<head ${u(d(_.headAttributes))}>
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
${_.csp?
|
|
7
|
+
${_.csp?L`<meta http-equiv="Content-Security-Policy" content="${_.csp}" />`:""}
|
|
8
8
|
<title>${_.title}</title>
|
|
9
|
-
${_.description?
|
|
9
|
+
${_.description?L`<meta name="description" content="${_.description}" />`:""}
|
|
10
10
|
|
|
11
11
|
<!-- Open Graph / Facebook -->
|
|
12
12
|
<meta prefix="og: http://ogp.me/ns#" />
|
|
13
13
|
<meta property="og:title" content="${_.title}" />
|
|
14
|
-
${_.description?
|
|
15
|
-
${_.image?
|
|
16
|
-
${_.url?
|
|
17
|
-
${_.locale?
|
|
18
|
-
${_.type?
|
|
19
|
-
${_.siteName?
|
|
14
|
+
${_.description?L`<meta property="og:description" content="${_.description}" />`:""}
|
|
15
|
+
${_.image?L`<meta property="og:image" content="${_.image}" />`:""}
|
|
16
|
+
${_.url?L`<meta property="og:url" content="${_.url}" />`:""}
|
|
17
|
+
${_.locale?L`<meta property="og:locale" content="${_.locale}" />`:""}
|
|
18
|
+
${_.type?L`<meta property="og:type" content="${_.type}" />`:""}
|
|
19
|
+
${_.siteName?L`<meta property="og:site_name" content="${_.siteName}" />`:""}
|
|
20
20
|
|
|
21
21
|
<!-- Twitter -->
|
|
22
22
|
<meta
|
|
@@ -24,23 +24,23 @@ import"reflect-metadata";import{Hono as t}from"hono";class M{store=new Map;get($
|
|
|
24
24
|
content="${_.twitterCard||(_.image?"summary_large_image":"summary")}"
|
|
25
25
|
/>
|
|
26
26
|
<meta name="twitter:title" content="${_.title}" />
|
|
27
|
-
${_.description?
|
|
28
|
-
${_.image?
|
|
27
|
+
${_.description?L`<meta name="twitter:description" content="${_.description}" />`:""}
|
|
28
|
+
${_.image?L`<meta name="twitter:image" content="${_.image}" />`:""}
|
|
29
29
|
|
|
30
30
|
<!-- Custom Meta Tags -->
|
|
31
|
-
${_.customMeta?_.customMeta.map((W)=>{let Y=W.name?`name="${W.name}"`:"",
|
|
31
|
+
${_.customMeta?_.customMeta.map((W)=>{let Y=W.name?`name="${W.name}"`:"",Q=W.property?`property="${W.property}"`:"";return L`<meta ${Y} ${Q} content="${W.content}" />`}):""}
|
|
32
32
|
|
|
33
33
|
<!-- Favicon -->
|
|
34
|
-
${_.favicon?
|
|
34
|
+
${_.favicon?L`<link rel="icon" href="${_.favicon}" />`:""}
|
|
35
35
|
|
|
36
36
|
<!-- Stylesheets -->
|
|
37
|
-
${_.stylesheets?_.stylesheets.map((W)=>
|
|
37
|
+
${_.stylesheets?_.stylesheets.map((W)=>L`<link rel="stylesheet" href="${W}" />`):""}
|
|
38
38
|
|
|
39
39
|
<!-- Scripts -->
|
|
40
|
-
${_.scripts?_.scripts.map((W)=>{if(typeof W==="string")return
|
|
40
|
+
${_.scripts?_.scripts.map((W)=>{if(typeof W==="string")return L`<script src="${W}"></script>`;let{src:Y,async:Q,defer:X}=W;if(Q&&X)return L`<script src="${Y}" async defer></script>`;if(Q)return L`<script src="${Y}" async></script>`;if(X)return L`<script src="${Y}" defer></script>`;return L`<script src="${Y}"></script>`}):""}
|
|
41
41
|
</head>
|
|
42
|
-
<body ${u(
|
|
42
|
+
<body ${u(d(_.bodyAttributes))}>
|
|
43
43
|
${_.children}
|
|
44
44
|
</body>
|
|
45
45
|
</html>
|
|
46
|
-
`};function
|
|
46
|
+
`};function n($="",_={}){return(W)=>{Z.setControllerPath(W,$),Z.setControllerOptions(W,_)}}var a=k("get"),F_=k("post"),E_=k("put"),V_=k("delete"),A_=k("patch"),k_=k("options"),O_=k("all");function o($={}){return(_)=>{Z.setModuleOptions(_,$)}}function b_($="",_={prefix:null,version:null}){return n($,_)}var K_=a;function w_($={}){return o({imports:$.imports,services:$.services,controllers:($.views||[]).concat($.controllers||[])})}var M_=j("body",async($,_)=>{let W=_.get("__honest.body.cache");if(W===void 0)W=await _.req.json(),_.set("__honest.body.cache",W);if($&&W&&typeof W==="object")return W[String($)];return W}),f_=j("param",($,_)=>{return $?_.req.param($):_.req.param()}),x_=j("query",($,_)=>{return $?_.req.query($):_.req.query()}),I_=j("header",($,_)=>{return $?_.req.header($):_.req.header()}),v_=j("request",($,_)=>_.req),y_=j("request",($,_)=>_.req),g_=j("response",($,_)=>_.res),h_=j("response",($,_)=>_.res),m_=j("context",($,_)=>_),u_=j("context",($,_)=>_),d_=j("variable",($,_)=>_.get($)),c_=j("variable",($,_)=>_.get($));function s_(){return($)=>{Z.addService($)}}function a_($,..._){return(W,Y)=>{if(Y){let X=`${W.constructor.name}:${String(Y)}`;_.forEach((B)=>Z.registerHandler($,X,B))}else _.forEach((Q)=>Z.registerController($,W,Q))}}function t_(...$){return(_,W)=>{if(W){let Q=`${_.constructor.name}:${String(W)}`;$.forEach((X)=>Z.registerHandler("filter",Q,X))}else $.forEach((Y)=>Z.registerController("filter",_,Y))}}function _W(...$){return(_,W)=>{if(W){let Q=`${_.constructor.name}:${String(W)}`;$.forEach((X)=>Z.registerHandler("guard",Q,X))}else $.forEach((Y)=>Z.registerController("guard",_,Y))}}function QW(...$){return(_,W)=>{if(W){let Q=`${_.constructor.name}:${String(W)}`;$.forEach((X)=>Z.registerHandler("middleware",Q,X))}else $.forEach((Y)=>Z.registerController("middleware",_,Y))}}function JW(...$){return(_,W)=>{if(W){let Q=`${_.constructor.name}:${String(W)}`;$.forEach((X)=>Z.registerHandler("pipe",Q,X))}else $.forEach((Y)=>Z.registerController("pipe",_,Y))}}export{x$ as stripEndSlash,y as normalizePath,K$ as isUndefined,M$ as isSymbol,v as isString,w$ as isPlainObject,O as isObject,R$ as isNumber,T as isNil,p as isFunction,C$ as isEmpty,s as isConstructor,j as createParamDecorator,k as createHttpMethodDecorator,b as createErrorResponse,f$ as addLeadingSlash,b_ as View,c_ as Variable,d_ as Var,h as VERSION_NEUTRAL,JW as UsePipes,QW as UseMiddleware,_W as UseGuards,t_ as UseFilters,a_ as UseComponent,s_ as Service,M as RouteRegistry,h_ as Response,g_ as Res,y_ as Request,v_ as Req,x_ as Query,E_ as Put,F_ as Post,A_ as Patch,f_ as Param,K_ as Page,k_ as Options,I as NotFoundHandler,w_ as MvcModule,o as Module,Z as MetadataRegistry,B_ as Layout,I_ as Header,a as Get,x as ErrorHandler,V_ as Delete,m_ as Ctx,n as Controller,u_ as Context,f as Container,M_ as Body,C as ApplicationContext,l as Application,O_ as All};
|
|
@@ -21,4 +21,15 @@ export interface DiContainer {
|
|
|
21
21
|
* @throws {Error} If registration fails
|
|
22
22
|
*/
|
|
23
23
|
register<T>(target: Constructor<T>, instance: T): void;
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether the container already holds an instance for the given class
|
|
26
|
+
* @param target - The class constructor to check
|
|
27
|
+
* @returns true if an instance has been resolved or registered
|
|
28
|
+
*/
|
|
29
|
+
has<T>(target: Constructor<T>): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Removes all cached instances from the container
|
|
32
|
+
* Useful for resetting state between tests
|
|
33
|
+
*/
|
|
34
|
+
clear(): void;
|
|
24
35
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { VERSION_NEUTRAL } from '../constants';
|
|
2
|
-
import type { ParameterMetadata } from '../interfaces';
|
|
3
2
|
/**
|
|
4
3
|
* Internal metadata for defining a route. This interface is used by the framework
|
|
5
4
|
* to store route information collected from decorators.
|
|
@@ -30,11 +29,6 @@ export interface RouteDefinition {
|
|
|
30
29
|
* Name of the method in the controller class that handles this route
|
|
31
30
|
*/
|
|
32
31
|
handlerName: string | symbol;
|
|
33
|
-
/**
|
|
34
|
-
* Metadata about the parameters of the handler method,
|
|
35
|
-
* including decorators like @Body(), @Param(), @Query(), etc.
|
|
36
|
-
*/
|
|
37
|
-
parameterMetadata: ParameterMetadata[];
|
|
38
32
|
/**
|
|
39
33
|
* Route-specific API version, overrides controller and global version.
|
|
40
34
|
*
|
|
@@ -1,143 +1,46 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono';
|
|
2
|
-
import type { ArgumentMetadata, DiContainer, GuardType, IGuard, IPipe, MiddlewareType, PipeType } from '../interfaces';
|
|
2
|
+
import type { ArgumentMetadata, DiContainer, FilterType, GuardType, IGuard, IPipe, MiddlewareType, PipeType } from '../interfaces';
|
|
3
3
|
import { type ComponentType, type ComponentTypeMap } from '../registries';
|
|
4
4
|
import type { Constructor } from '../types';
|
|
5
5
|
/**
|
|
6
|
-
* Manager class for handling all component types in the Honest framework
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Manager class for handling all component types in the Honest framework.
|
|
7
|
+
*
|
|
8
|
+
* Each Application instance owns a ComponentManager, which holds per-app
|
|
9
|
+
* global components and a reference to the DI container. Controller-level
|
|
10
|
+
* and handler-level components remain in MetadataRegistry (static, set at
|
|
11
|
+
* class-definition time by decorators).
|
|
10
12
|
*/
|
|
11
13
|
export declare class ComponentManager {
|
|
12
|
-
private
|
|
14
|
+
private readonly container;
|
|
15
|
+
private readonly globalComponents;
|
|
16
|
+
constructor(container: DiContainer);
|
|
13
17
|
/**
|
|
14
|
-
*
|
|
15
|
-
* Must be called before using any other ComponentManager methods
|
|
16
|
-
* @param container - The dependency injection container to use for resolving components
|
|
18
|
+
* Configures global components from application options.
|
|
17
19
|
*/
|
|
18
|
-
|
|
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: {
|
|
20
|
+
setupGlobalComponents(options: {
|
|
30
21
|
components?: {
|
|
31
|
-
middleware?:
|
|
32
|
-
guards?:
|
|
33
|
-
pipes?:
|
|
34
|
-
filters?:
|
|
22
|
+
middleware?: MiddlewareType[];
|
|
23
|
+
guards?: GuardType[];
|
|
24
|
+
pipes?: PipeType[];
|
|
25
|
+
filters?: FilterType[];
|
|
35
26
|
};
|
|
36
27
|
}): void;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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[]>;
|
|
28
|
+
registerGlobal<T extends ComponentType>(type: T, ...components: ComponentTypeMap[T][]): void;
|
|
29
|
+
getGlobal<T extends ComponentType>(type: T): Set<ComponentTypeMap[T]>;
|
|
30
|
+
/**
|
|
31
|
+
* Gets all components of a specific type for a handler.
|
|
32
|
+
* Merges: instance global → static controller → static handler.
|
|
33
|
+
*/
|
|
34
|
+
getComponents<T extends ComponentType>(type: T, controller: Constructor, handlerName: string | symbol): ComponentTypeMap[T][];
|
|
35
|
+
resolveMiddleware(middlewareItems: MiddlewareType[]): ((c: Context, next: Next) => Promise<Response | void>)[];
|
|
36
|
+
getHandlerMiddleware(controller: Constructor, handlerName: string | symbol): ((c: Context, next: Next) => Promise<Response | void>)[];
|
|
37
|
+
getGlobalMiddleware(): ((c: Context, next: Next) => Promise<Response | void>)[];
|
|
38
|
+
resolveGuards(guardItems: GuardType[]): IGuard[];
|
|
39
|
+
getHandlerGuards(controller: Constructor, handlerName: string | symbol): IGuard[];
|
|
40
|
+
resolvePipes(pipeItems: PipeType[]): IPipe[];
|
|
41
|
+
getHandlerPipes(controller: Constructor, handlerName: string | symbol): IPipe[];
|
|
42
|
+
executePipes(value: any, metadata: ArgumentMetadata, pipes: IPipe[]): Promise<any>;
|
|
43
|
+
handleException(exception: Error, context: Context): Promise<Response | undefined>;
|
|
44
|
+
private executeFilters;
|
|
45
|
+
registerModule(moduleClass: Constructor, registered?: Set<Constructor>): Promise<Constructor[]>;
|
|
143
46
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
@@ -1,109 +1,31 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import { VERSION_NEUTRAL } from '../constants';
|
|
3
3
|
import type { DiContainer } from '../interfaces';
|
|
4
|
+
import { ComponentManager } from './component.manager';
|
|
5
|
+
import { RouteRegistry } from '../registries/route.registry';
|
|
4
6
|
import type { Constructor } from '../types';
|
|
5
7
|
/**
|
|
6
|
-
* Manager class for handling route registration in the Honest framework
|
|
7
|
-
* Responsible for:
|
|
8
|
-
* - Registering controller routes with the Hono application
|
|
9
|
-
* - Managing route versioning and prefixing
|
|
10
|
-
* - Applying middleware and guards to routes
|
|
11
|
-
* - Handling parameter transformation and validation
|
|
8
|
+
* Manager class for handling route registration in the Honest framework.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* - Controllers can opt out of versioning by setting version to null
|
|
16
|
-
* - Routes can use VERSION_NEUTRAL to be accessible with and without version prefix
|
|
17
|
-
* - Routes can specify an array of versions to support multiple versions
|
|
18
|
-
*
|
|
19
|
-
* Path handling:
|
|
20
|
-
* - Global prefix can be overridden at controller level
|
|
21
|
-
* - Paths are automatically normalized
|
|
22
|
-
* - Final path structure: prefix/version/controller-path/method-path
|
|
10
|
+
* Receives all per-app dependencies (Hono, Container, RouteRegistry,
|
|
11
|
+
* ComponentManager) via constructor — no static state.
|
|
23
12
|
*/
|
|
24
13
|
export declare class RouteManager {
|
|
25
14
|
private hono;
|
|
26
15
|
private container;
|
|
16
|
+
private routeRegistry;
|
|
17
|
+
private componentManager;
|
|
27
18
|
private globalPrefix?;
|
|
28
19
|
private globalVersion?;
|
|
29
|
-
|
|
30
|
-
* Creates a new RouteManager instance
|
|
31
|
-
* @param hono - The Hono application instance for route registration
|
|
32
|
-
* @param container - The dependency injection container for resolving controllers and dependencies
|
|
33
|
-
* @param options - Configuration options for the route manager
|
|
34
|
-
* @param options.prefix - Optional global prefix for all routes
|
|
35
|
-
* @param options.version - Optional global version or version array for all routes
|
|
36
|
-
*/
|
|
37
|
-
constructor(hono: Hono, container: DiContainer, options?: {
|
|
20
|
+
constructor(hono: Hono, container: DiContainer, routeRegistry: RouteRegistry, componentManager: ComponentManager, options?: {
|
|
38
21
|
prefix?: string;
|
|
39
22
|
version?: number | typeof VERSION_NEUTRAL | number[];
|
|
40
23
|
});
|
|
41
|
-
/**
|
|
42
|
-
* Applies global middleware to the application
|
|
43
|
-
*/
|
|
44
24
|
private applyGlobalMiddleware;
|
|
45
|
-
/**
|
|
46
|
-
* Normalizes a path segment for route registration
|
|
47
|
-
* @param path - The path segment to normalize
|
|
48
|
-
* @returns The normalized path segment
|
|
49
|
-
*/
|
|
50
25
|
private normalizePath;
|
|
51
|
-
/**
|
|
52
|
-
* Registers a wrapper handler with middleware for a route
|
|
53
|
-
* @param method - HTTP method
|
|
54
|
-
* @param path - Full path for the route
|
|
55
|
-
* @param handlerMiddleware - Middleware for the handler
|
|
56
|
-
* @param wrapperHandler - The wrapper handler function
|
|
57
|
-
*/
|
|
58
26
|
private registerRouteHandler;
|
|
59
|
-
/**
|
|
60
|
-
* Builds a route path with the correct order: prefix, version, controller path, method path
|
|
61
|
-
* @param prefix - Global or controller-specific prefix
|
|
62
|
-
* @param version - Version string (e.g., '/v1') or empty string if no version
|
|
63
|
-
* @param controllerPath - Controller path
|
|
64
|
-
* @param methodPath - Method-specific path
|
|
65
|
-
* @returns Properly formatted full path
|
|
66
|
-
*/
|
|
67
27
|
private buildRoutePath;
|
|
68
|
-
/**
|
|
69
|
-
* Formats a version number or VERSION_NEUTRAL into a path segment
|
|
70
|
-
* @param version - Version number or VERSION_NEUTRAL
|
|
71
|
-
* @returns Formatted version string (e.g., '/v1') or empty string if null
|
|
72
|
-
*/
|
|
73
28
|
private formatVersionSegment;
|
|
74
|
-
/**
|
|
75
|
-
* Registers a controller and all its routes with the application
|
|
76
|
-
* Handles versioning, prefixing, and middleware application
|
|
77
|
-
*
|
|
78
|
-
* @param controllerClass - The controller class to register
|
|
79
|
-
* @throws {Error} If controller registration fails or if required dependencies cannot be resolved
|
|
80
|
-
*
|
|
81
|
-
* Route registration process:
|
|
82
|
-
* 1. Resolves controller instance and metadata
|
|
83
|
-
* 2. Processes controller-level options (prefix, version)
|
|
84
|
-
* 3. Registers each route with appropriate:
|
|
85
|
-
* - Path construction (prefix/version/controller-path/method-path)
|
|
86
|
-
* - Middleware application
|
|
87
|
-
* - Parameter processing
|
|
88
|
-
* - Guard validation
|
|
89
|
-
*/
|
|
90
29
|
registerController(controllerClass: Constructor): Promise<void>;
|
|
91
|
-
/**
|
|
92
|
-
* Registers a specific route with the application
|
|
93
|
-
* Handles middleware setup, parameter processing, and response handling
|
|
94
|
-
*
|
|
95
|
-
* @param controllerInstance - Instance of the controller containing the route handler
|
|
96
|
-
* @param route - Route metadata including path and HTTP method
|
|
97
|
-
* @param parameterMetadata - Metadata for parameter processing
|
|
98
|
-
* @param contextIndices - Map of context parameter indices
|
|
99
|
-
* @param controllerClass - The controller class
|
|
100
|
-
* @param prefix - Route prefix
|
|
101
|
-
* @param versionSegment - Version segment of the path
|
|
102
|
-
* @param controllerSegment - Controller path segment
|
|
103
|
-
* @param methodSegment - Method-specific path segment
|
|
104
|
-
* @param method - HTTP method for the route
|
|
105
|
-
*
|
|
106
|
-
* @throws {Error} If route registration fails
|
|
107
|
-
*/
|
|
108
30
|
private registerRoute;
|
|
109
31
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
import type { ControllerOptions, FilterType, GuardType, MiddlewareType, ModuleOptions, ParameterMetadata, PipeType, RouteDefinition } from '../interfaces';
|
|
2
2
|
import type { Constructor } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
* Available component types that can be registered at different levels in the application
|
|
5
|
-
* Each type corresponds to a specific aspect of request processing
|
|
6
|
-
*/
|
|
7
3
|
export type ComponentType = 'middleware' | 'guard' | 'pipe' | 'filter';
|
|
8
|
-
/**
|
|
9
|
-
* Union type of all possible component instances
|
|
10
|
-
* Represents any type of component that can be registered in the application
|
|
11
|
-
*/
|
|
12
4
|
export type ComponentInstance = MiddlewareType | GuardType | PipeType | FilterType;
|
|
13
|
-
/**
|
|
14
|
-
* Maps component type identifiers to their specific instance types
|
|
15
|
-
* Used for type-safe component registration and retrieval
|
|
16
|
-
*/
|
|
17
5
|
export interface ComponentTypeMap {
|
|
18
6
|
middleware: MiddlewareType;
|
|
19
7
|
guard: GuardType;
|
|
@@ -64,11 +52,6 @@ export declare class MetadataRegistry {
|
|
|
64
52
|
* Used for optimizing context injection
|
|
65
53
|
*/
|
|
66
54
|
private static readonly contextIndices;
|
|
67
|
-
/**
|
|
68
|
-
* Registry for global-level components
|
|
69
|
-
* Components registered here apply to all routes
|
|
70
|
-
*/
|
|
71
|
-
private static readonly global;
|
|
72
55
|
/**
|
|
73
56
|
* Registry for controller-level components
|
|
74
57
|
* Components registered here apply to all routes in a specific controller
|
|
@@ -149,14 +132,6 @@ export declare class MetadataRegistry {
|
|
|
149
132
|
* Set context indices
|
|
150
133
|
*/
|
|
151
134
|
static setContextIndices(controller: Constructor, indices: Map<string | symbol, number>): void;
|
|
152
|
-
/**
|
|
153
|
-
* Register a component at the global level
|
|
154
|
-
*/
|
|
155
|
-
static registerGlobal<T extends ComponentType>(type: T, component: ComponentTypeMap[T]): void;
|
|
156
|
-
/**
|
|
157
|
-
* Get all global components of a specific type
|
|
158
|
-
*/
|
|
159
|
-
static getGlobal<T extends ComponentType>(type: T): Set<ComponentTypeMap[T]>;
|
|
160
135
|
/**
|
|
161
136
|
* Register a component at the controller level
|
|
162
137
|
*/
|
|
@@ -174,9 +149,8 @@ export declare class MetadataRegistry {
|
|
|
174
149
|
*/
|
|
175
150
|
static getHandler<T extends ComponentType>(type: T, handlerKey: string): ComponentTypeMap[T][];
|
|
176
151
|
/**
|
|
177
|
-
* Clears all registered metadata
|
|
178
|
-
* Primarily used for testing
|
|
179
|
-
* Use with caution in production environments
|
|
152
|
+
* Clears all registered decorator metadata.
|
|
153
|
+
* Primarily used for testing.
|
|
180
154
|
*/
|
|
181
155
|
static clear(): void;
|
|
182
156
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
@@ -1,63 +1,16 @@
|
|
|
1
1
|
import type { RouteInfo } from '../interfaces';
|
|
2
2
|
/**
|
|
3
|
-
* Registry for managing and querying route information in the application
|
|
3
|
+
* Registry for managing and querying route information in the application.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* - Query routes by various criteria (controller, method, path)
|
|
8
|
-
* - Access route information for documentation and debugging
|
|
9
|
-
* - Manage route lifecycle (registration and cleanup)
|
|
10
|
-
*
|
|
11
|
-
* The registry maintains a read-only view of routes to prevent unintended modifications
|
|
5
|
+
* Each Application instance owns its own RouteRegistry, ensuring routes
|
|
6
|
+
* from one app never leak into another.
|
|
12
7
|
*/
|
|
13
8
|
export declare class RouteRegistry {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* @param routeInfo - Complete route information including path, method, and handler details
|
|
22
|
-
* @throws {Error} If the route information is invalid or incomplete
|
|
23
|
-
*/
|
|
24
|
-
static registerRoute(routeInfo: RouteInfo): void;
|
|
25
|
-
/**
|
|
26
|
-
* Retrieves all registered routes in the application
|
|
27
|
-
* @returns A read-only array of all route information
|
|
28
|
-
* Routes are returned in their registration order
|
|
29
|
-
*/
|
|
30
|
-
static getRoutes(): ReadonlyArray<RouteInfo>;
|
|
31
|
-
/**
|
|
32
|
-
* Retrieves all routes registered for a specific controller
|
|
33
|
-
* @param controllerName - Name or symbol identifying the controller
|
|
34
|
-
* @returns A read-only array of routes belonging to the specified controller
|
|
35
|
-
* Returns an empty array if no routes are found for the controller
|
|
36
|
-
*/
|
|
37
|
-
static getRoutesByController(controllerName: string | symbol): ReadonlyArray<RouteInfo>;
|
|
38
|
-
/**
|
|
39
|
-
* Retrieves all routes registered for a specific HTTP method
|
|
40
|
-
* @param method - HTTP method to filter by (case-insensitive)
|
|
41
|
-
* @returns A read-only array of routes handling the specified HTTP method
|
|
42
|
-
* Returns an empty array if no routes are found for the method
|
|
43
|
-
*/
|
|
44
|
-
static getRoutesByMethod(method: string): ReadonlyArray<RouteInfo>;
|
|
45
|
-
/**
|
|
46
|
-
* Retrieves routes matching a specific path pattern
|
|
47
|
-
* @param pattern - Regular expression to match against route paths
|
|
48
|
-
* @returns A read-only array of routes whose paths match the pattern
|
|
49
|
-
* Returns an empty array if no matching routes are found
|
|
50
|
-
* @example
|
|
51
|
-
* ```ts
|
|
52
|
-
* // Find all routes containing 'users'
|
|
53
|
-
* const userRoutes = RouteRegistry.getRoutesByPath(/users/);
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
static getRoutesByPath(pattern: RegExp): ReadonlyArray<RouteInfo>;
|
|
57
|
-
/**
|
|
58
|
-
* Removes all registered routes from the registry
|
|
59
|
-
* Primarily used for testing and development purposes
|
|
60
|
-
* Use with caution in production environments
|
|
61
|
-
*/
|
|
62
|
-
static clear(): void;
|
|
9
|
+
private readonly routes;
|
|
10
|
+
registerRoute(routeInfo: RouteInfo): void;
|
|
11
|
+
getRoutes(): ReadonlyArray<RouteInfo>;
|
|
12
|
+
getRoutesByController(controllerName: string | symbol): ReadonlyArray<RouteInfo>;
|
|
13
|
+
getRoutesByMethod(method: string): ReadonlyArray<RouteInfo>;
|
|
14
|
+
getRoutesByPath(pattern: RegExp): ReadonlyArray<RouteInfo>;
|
|
15
|
+
clear(): void;
|
|
63
16
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "honestjs",
|
|
3
3
|
"description": "HonestJS - a modern web framework built on top of Hono",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.12",
|
|
5
5
|
"author": "Orkhan Karimov <karimovok1@gmail.com> (https://github.com/kerimovok)",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"types": "dist/index.d.ts",
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@eslint/js": "^9.39.
|
|
16
|
-
"@types/bun": "^1.3.
|
|
17
|
-
"eslint": "^9.39.
|
|
15
|
+
"@eslint/js": "^9.39.4",
|
|
16
|
+
"@types/bun": "^1.3.10",
|
|
17
|
+
"eslint": "^9.39.4",
|
|
18
18
|
"eslint-config-prettier": "^10.1.8",
|
|
19
19
|
"globals": "^16.5.0",
|
|
20
20
|
"husky": "^9.1.7",
|
|
21
|
-
"lint-staged": "^16.
|
|
21
|
+
"lint-staged": "^16.4.0",
|
|
22
22
|
"prettier": "3.6.2",
|
|
23
|
-
"typescript-eslint": "^8.
|
|
23
|
+
"typescript-eslint": "^8.57.0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"hono": "^4.8.5",
|