honestjs 0.1.18 β 0.1.20
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/README.md +26 -34
- package/dist/application.d.ts +1 -3
- package/dist/di/container.d.ts +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -16
- package/dist/interfaces/honest-options.interface.d.ts +3 -3
- package/dist/interfaces/index.d.ts +1 -1
- package/dist/interfaces/logger.interface.d.ts +23 -0
- package/dist/interfaces/plugin.interface.d.ts +14 -26
- package/dist/loggers/console.logger.d.ts +7 -0
- package/dist/loggers/index.d.ts +2 -0
- package/dist/loggers/noop.logger.d.ts +7 -0
- package/dist/managers/component.manager.d.ts +3 -3
- package/dist/managers/pipeline.executor.d.ts +3 -3
- package/dist/managers/route.manager.d.ts +3 -3
- package/dist/testing/testing.interface.d.ts +3 -3
- package/package.json +1 -1
- package/dist/diagnostics/console-diagnostics.emitter.d.ts +0 -7
- package/dist/diagnostics/index.d.ts +0 -2
- package/dist/diagnostics/noop-diagnostics.emitter.d.ts +0 -7
- package/dist/interfaces/diagnostics.interface.d.ts +0 -23
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://github.com/honestjs/" target="blank"><img src="https://
|
|
2
|
+
<a href="https://github.com/honestjs/" target="blank"><img src="https://honestjs.dev/images/honestjs.png" width="120" alt="Honest.js Logo" /></a>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
@@ -48,6 +48,21 @@ ultra-fast performance of Hono, giving you the best of both worlds.
|
|
|
48
48
|
</a>
|
|
49
49
|
</p>
|
|
50
50
|
|
|
51
|
+
<hr />
|
|
52
|
+
|
|
53
|
+
<div align="center">
|
|
54
|
+
|
|
55
|
+
[](https://github.com/honestjs/honest/blob/main/LICENSE)
|
|
56
|
+
[](https://www.npmjs.com/package/honestjs)
|
|
57
|
+
[](https://www.npmjs.com/package/honestjs)
|
|
58
|
+
[](https://bundlephobia.com/result?p=honestjs)
|
|
59
|
+
[](https://bundlephobia.com/result?p=honestjs)
|
|
60
|
+
[](https://github.com/honestjs/honest/pulse)
|
|
61
|
+
[](https://github.com/honestjs/honest/commits/main)
|
|
62
|
+
[](https://discord.gg/g3TUeXbeq)
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
51
66
|
## Cursor / Agent skills
|
|
52
67
|
|
|
53
68
|
Install the Honest skill so your editor agent (e.g. Cursor) can use Honest-specific guidance:
|
|
@@ -92,8 +107,9 @@ for full docs.
|
|
|
92
107
|
- **π High performance** β Built on Hono for maximum speed and minimal overhead.
|
|
93
108
|
- **ποΈ Familiar architecture** β Decorator-based API inspired by NestJS; TypeScript-first.
|
|
94
109
|
- **π Dependency injection** β Built-in DI container for clean, testable code and automatic wiring.
|
|
95
|
-
- **π Plugin system** β Extend the app with custom plugins, middleware, pipes, and filters.
|
|
96
|
-
|
|
110
|
+
- **π Plugin system** β Extend the app with custom plugins, middleware, pipes, and filters. Plugins run in
|
|
111
|
+
`options.plugins` order; wrapped entries may attach `preProcessors` / `postProcessors` and optional `name` for
|
|
112
|
+
diagnostics.
|
|
97
113
|
- **π£οΈ Advanced routing** β Prefixes, API versioning, and nested route organization.
|
|
98
114
|
- **π‘οΈ Request pipeline** β Middleware, guards, pipes, and filters at app, controller, or handler level.
|
|
99
115
|
- **π§ͺ Lightweight testing harness** β Helpers for application, controller, and service-level tests.
|
|
@@ -144,7 +160,7 @@ const { app, hono } = await Application.create(AppModule, {
|
|
|
144
160
|
di: true,
|
|
145
161
|
startup: true
|
|
146
162
|
},
|
|
147
|
-
|
|
163
|
+
logger: myLogger,
|
|
148
164
|
strict: { requireRoutes: true },
|
|
149
165
|
deprecations: { printPreV1Warning: true },
|
|
150
166
|
container: myContainer,
|
|
@@ -172,7 +188,7 @@ const { app, hono } = await Application.create(AppModule, {
|
|
|
172
188
|
preProcessors: [pre],
|
|
173
189
|
postProcessors: [post]
|
|
174
190
|
},
|
|
175
|
-
{ plugin: MetricsPlugin, name: 'metrics'
|
|
191
|
+
{ plugin: MetricsPlugin, name: 'metrics' }
|
|
176
192
|
],
|
|
177
193
|
onError: (err, c) => c.json({ error: err.message }, 500),
|
|
178
194
|
notFound: (c) => c.json({ error: 'Not found' }, 404)
|
|
@@ -190,34 +206,10 @@ Decorator metadata is still collected globally, but each application instance no
|
|
|
190
206
|
captured during startup. This prevents metadata mutations made after bootstrap from changing behavior in already-running
|
|
191
207
|
applications.
|
|
192
208
|
|
|
193
|
-
## Plugin
|
|
194
|
-
|
|
195
|
-
Use named plugin entries when order matters and optionally declare startup capability contracts via `meta`.
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
class ArtifactPlugin {
|
|
199
|
-
meta = {
|
|
200
|
-
name: 'artifact',
|
|
201
|
-
provides: ['artifact:routes']
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
class DocsPlugin {
|
|
206
|
-
meta = {
|
|
207
|
-
name: 'docs',
|
|
208
|
-
requires: ['artifact:routes']
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
await Application.create(AppModule, {
|
|
213
|
-
plugins: [
|
|
214
|
-
{ plugin: new DocsPlugin(), name: 'docs', after: ['artifact'] },
|
|
215
|
-
{ plugin: new ArtifactPlugin(), name: 'artifact' }
|
|
216
|
-
]
|
|
217
|
-
})
|
|
218
|
-
```
|
|
209
|
+
## Plugin order
|
|
219
210
|
|
|
220
|
-
|
|
211
|
+
Plugins run in the order they appear in `options.plugins`. Put producer plugins (for example RPC) before consumers (for
|
|
212
|
+
example API docs) when one plugin depends on anotherβs app-context output.
|
|
221
213
|
|
|
222
214
|
## Testing harness
|
|
223
215
|
|
|
@@ -273,8 +265,8 @@ await Application.create(AppModule, {
|
|
|
273
265
|
})
|
|
274
266
|
```
|
|
275
267
|
|
|
276
|
-
Guide mode emits startup diagnostics hints for common issues such as missing decorators, strict no-routes startup,
|
|
277
|
-
metadata issues
|
|
268
|
+
Guide mode emits startup diagnostics hints for common issues such as missing decorators, strict no-routes startup, and
|
|
269
|
+
metadata issues.
|
|
278
270
|
|
|
279
271
|
## License
|
|
280
272
|
|
package/dist/application.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare class Application {
|
|
|
16
16
|
private readonly metadataRepository;
|
|
17
17
|
private readonly componentManager;
|
|
18
18
|
private readonly routeManager;
|
|
19
|
-
private readonly
|
|
19
|
+
private readonly logger;
|
|
20
20
|
private readonly options;
|
|
21
21
|
private static readonly DEFAULT_PLUGIN_NAME;
|
|
22
22
|
constructor(options?: HonestOptions, metadataRepository?: IMetadataRepository);
|
|
@@ -24,8 +24,6 @@ export declare class Application {
|
|
|
24
24
|
private resolvePlugin;
|
|
25
25
|
private normalizePluginEntry;
|
|
26
26
|
private resolvePluginName;
|
|
27
|
-
private resolvePluginExecutionOrder;
|
|
28
|
-
private validatePluginCapabilities;
|
|
29
27
|
private shouldEmitRouteDiagnostics;
|
|
30
28
|
private emitStartupGuide;
|
|
31
29
|
private createStartupGuideHints;
|
package/dist/di/container.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type { DiContainer,
|
|
1
|
+
import type { DiContainer, ILogger, IServiceRegistry } from '../interfaces';
|
|
2
2
|
import type { Constructor } from '../types';
|
|
3
3
|
/**
|
|
4
4
|
* Dependency Injection container that manages class instances and their dependencies
|
|
5
5
|
*/
|
|
6
6
|
export declare class Container implements DiContainer {
|
|
7
7
|
private readonly serviceRegistry;
|
|
8
|
-
private readonly
|
|
8
|
+
private readonly logger;
|
|
9
9
|
private readonly debugDi;
|
|
10
|
-
constructor(serviceRegistry?: IServiceRegistry,
|
|
10
|
+
constructor(serviceRegistry?: IServiceRegistry, logger?: ILogger, debugDi?: boolean);
|
|
11
11
|
/**
|
|
12
12
|
* Map of class constructors to their instances
|
|
13
13
|
*/
|
|
14
14
|
private instances;
|
|
15
|
-
private
|
|
15
|
+
private emitLog;
|
|
16
16
|
/**
|
|
17
17
|
* Resolves a class instance, creating it if necessary and injecting its dependencies
|
|
18
18
|
* @param target - The class constructor to resolve
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export * from './application-context';
|
|
|
4
4
|
export * from './components';
|
|
5
5
|
export * from './constants';
|
|
6
6
|
export * from './decorators';
|
|
7
|
-
export * from './
|
|
7
|
+
export * from './loggers';
|
|
8
8
|
export * from './di';
|
|
9
9
|
export * from './errors';
|
|
10
10
|
export * from './handlers';
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import"reflect-metadata";import{Hono as B$}from"hono";class h{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 g{emit($){let _=`[HonestJS:${$.category}]`,W=$.details?[_,$.message,$.details]:[_,$.message];switch($.level){case"debug":case"info":console.info(...W);break;case"warn":console.warn(...W);break;case"error":console.error(...W);break}}}class H{emit($){}}class L{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 Q=this.controller.get($);if(!Q.has(_))Q.set(_,[]);Q.get(_).push(W)}static getController($,_){return this.controller.get($).get(_)||[]}static registerHandler($,_,W){let Q=this.handler.get($);if(!Q.has(_))Q.set(_,[]);Q.get(_).push(W)}static getHandler($,_){return this.handler.get($).get(_)||[]}static clearHandlerComponents(){for(let $ of this.handler.values())$.clear()}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 D{hasController($){return L.hasController($)}getControllerPath($){return L.getControllerPath($)}getControllerOptions($){return L.getControllerOptions($)}getRoutes($){return L.getRoutes($)}getParameters($){return L.getParameters($)}getContextIndices($){return L.getContextIndices($)}getModuleOptions($){return L.getModuleOptions($)}getControllerComponents($,_){return L.getController($,_)}getHandlerComponents($,_){return L.getHandler($,_)}}class C{controllerPaths=new Map;controllerOptions=new Map;routes=new Map;parameters=new Map;contextIndices=new Map;modules=new Map;controllerComponents=new Map([["middleware",new Map],["guard",new Map],["pipe",new Map],["filter",new Map]]);handlerComponents=new Map([["middleware",new Map],["guard",new Map],["pipe",new Map],["filter",new Map]]);static fromRootModule($,_=new D){let W=new C;return W.captureModuleGraph($,_),W}hasController($){return this.controllerPaths.has($)}getControllerPath($){return this.controllerPaths.get($)||""}getControllerOptions($){let _=this.controllerOptions.get($);return _?{..._}:{}}getRoutes($){return(this.routes.get($)||[]).map((_)=>this.cloneRouteDefinition(_))}getParameters($){let _=this.parameters.get($);if(!_)return new Map;let W=new Map;for(let[Q,X]of _.entries())W.set(Q,X.map((Z)=>({...Z})));return W}getContextIndices($){return new Map(this.contextIndices.get($)||new Map)}getModuleOptions($){let _=this.modules.get($);if(!_)return;return{controllers:_.controllers?[..._.controllers]:void 0,services:_.services?[..._.services]:void 0,imports:_.imports?[..._.imports]:void 0}}getControllerComponents($,_){return[...this.controllerComponents.get($).get(_)||[]]}getHandlerComponents($,_){return[...this.handlerComponents.get($).get(_)||[]]}captureModuleGraph($,_){let W=new Set,Q=new Set,X=(Z)=>{if(W.has(Z))return;W.add(Z);let U=_.getModuleOptions(Z);if(!U)return;let J={controllers:U.controllers?[...U.controllers]:void 0,services:U.services?[...U.services]:void 0,imports:U.imports?[...U.imports]:void 0};this.modules.set(Z,J);for(let Y of J.controllers||[])Q.add(Y);for(let Y of J.imports||[])X(Y)};X($);for(let Z of Q)this.captureController(Z,_)}captureController($,_){if(!_.hasController($))return;this.controllerPaths.set($,_.getControllerPath($)||""),this.controllerOptions.set($,{..._.getControllerOptions($)});let W=(_.getRoutes($)||[]).map((Z)=>this.cloneRouteDefinition(Z));this.routes.set($,W);let Q=_.getParameters($),X=new Map;for(let[Z,U]of Q.entries())X.set(Z,(U||[]).map((J)=>({...J})));this.parameters.set($,X),this.contextIndices.set($,new Map(_.getContextIndices($)||new Map));for(let Z of["middleware","guard","pipe","filter"])this.controllerComponents.get(Z).set($,[..._.getControllerComponents(Z,$)||[]]);for(let Z of W){let U=`${$.name}:${String(Z.handlerName)}`;for(let J of["middleware","guard","pipe","filter"])this.handlerComponents.get(J).set(U,[..._.getHandlerComponents(J,U)||[]])}}cloneRouteDefinition($){return{...$,version:Array.isArray($.version)?[...$.version]:$.version}}}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 u{isService($){return L.isService($)}}class E{serviceRegistry;diagnosticsEmitter;debugDi;constructor($=new u,_=new H,W=!1){this.serviceRegistry=$;this.diagnosticsEmitter=_;this.debugDi=W}instances=new Map;emitDiagnostic($){if(!this.debugDi)return;this.diagnosticsEmitter.emit($)}resolve($){return this.resolveWithTracking($,new Set)}resolveWithTracking($,_){if(this.instances.has($))return this.emitDiagnostic({level:"debug",category:"di",message:`Resolved ${$.name} from DI cache`}),this.instances.get($);if(_.has($)){let Z=[..._.keys(),$].map((U)=>U.name).join(" -> ");throw this.emitDiagnostic({level:"error",category:"di",message:`Circular dependency detected while resolving ${$.name}`,details:{cycle:Z}}),Error(`Circular dependency detected: ${Z}`)}_.add($),this.emitDiagnostic({level:"debug",category:"di",message:`Resolving ${$.name}`,details:{resolving:[..._].map((Z)=>Z.name)}});let W=Reflect.getMetadata("design:paramtypes",$)||[];if($.length>0&&W.length===0){if(!this.serviceRegistry.isService($))throw this.emitDiagnostic({level:"error",category:"di",message:`Cannot resolve ${$.name}: missing @Service() decorator`}),Error(`Cannot resolve ${$.name}: it is not decorated with @Service(). Did you forget to add @Service() to the class?`);throw this.emitDiagnostic({level:"error",category:"di",message:`Cannot resolve ${$.name}: missing constructor metadata`}),Error(`Cannot resolve dependencies for ${$.name}: constructor metadata is missing. Ensure 'reflect-metadata' is imported and 'emitDecoratorMetadata' is enabled.`)}let Q=W.map((Z,U)=>{if(!Z||Z===Object||Z===Array||Z===Function)throw this.emitDiagnostic({level:"error",category:"di",message:`Cannot resolve dependency at index ${U} of ${$.name}`}),Error(`Cannot resolve dependency at index ${U} of ${$.name}. Use concrete class types for constructor dependencies.`);return this.resolveWithTracking(Z,new Set(_))}),X=new $(...Q);return this.instances.set($,X),this.emitDiagnostic({level:"debug",category:"di",message:`Created ${$.name} instance`,details:{dependencyCount:Q.length}}),X}register($,_){this.instances.set($,_)}has($){return this.instances.has($)}clear(){this.instances.clear()}}import{HTTPException as U$}from"hono/http-exception";class d extends Error{status;code;category;remediation;details;constructor($,_){super($);if(this.name="FrameworkError",this.status=_.status,this.code=_.code,this.category=_.category,this.remediation=_.remediation,this.details=_.details,_.cause!==void 0)this.cause=_.cause}}function R($,_,W){let Q=$ instanceof Error?$:Error(String($)),X=new Date().toISOString(),Z=_.get("requestId"),U=_.req.path;if(Q instanceof U$)return{response:{status:W?.status||Q.status,message:W?.title||Q.message,timestamp:X,path:U,requestId:Z,code:W?.code,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:W?.status||Q.status};if(Q instanceof d){let B=W?.status||Q.status||500;return{response:{status:B,message:W?.title||Q.message,timestamp:X,path:U,requestId:Z,code:W?.code||Q.code,details:{category:Q.category,remediation:Q.remediation,...Q.details,...W?.additionalDetails},...W?.detail&&{detail:W.detail}},status:B}}if(Q.statusCode||Q.status){let B=Q.statusCode||Q.status||500,q=W?.status||B;return{response:{status:q,message:W?.title||Q.message,timestamp:X,path:U,requestId:Z,code:W?.code||Q.name,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:q}}let J=W?.status||500;return{response:{status:J,message:W?.title||Q.message,timestamp:X,path:U,requestId:Z,code:W?.code||Q.name,details:W?.additionalDetails||{stack:Q.stack},...W?.detail&&{detail:W.detail}},status:J}}function T($){return(_="",W={})=>{return(Q,X,Z)=>{let U=Q.constructor;L.addRoute(U,{path:_,method:$,handlerName:X,version:W.version,prefix:W.prefix})}}}function z($,_){let W=(Q,X)=>{if(Q===void 0)return X;return X.get(String(Q))};return(Q)=>{return(X,Z,U)=>{let J=X.constructor;if(!L.getParameters(J).size)L.setParameterMap(J,new Map);let Y=L.getParameters(J);if(!Y.has(Z))Y.set(Z,[]);let q=Reflect.getMetadata("design:paramtypes",X,Z)?.[U];if(Y.get(Z).push({index:U,name:$,data:Q,factory:_||W,metatype:q}),$==="context"){if(!L.getContextIndices(J).size)L.setContextIndices(J,new Map);L.getContextIndices(J).set(Z,U)}}}}class c{static handle(){return async($,_)=>{let{response:W,status:Q}=R($,_);return _.json(W,Q)}}}class p{static handle(){return async($)=>{return $.json({message:`Not Found - ${$.req.path}`},404)}}}var i=Symbol("VERSION_NEUTRAL");var I="__honest_controllerClass",M="__honest_handlerName",l="__honest.body.cache";var X_=($)=>typeof $>"u",S=($)=>$===null||typeof $>"u",K=($)=>$!==null&&typeof $==="object",Z_=($)=>{if(!K($))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)},_$=($)=>typeof $==="function",f=($)=>typeof $==="string",J_=($)=>typeof $==="number",U_=($)=>$.length===0,Y_=($)=>typeof $==="symbol",B_=($)=>typeof $==="string"?$.charAt(0)!=="/"?"/"+$:$:"",s=($)=>$?$.startsWith("/")?("/"+$.replace(/\/+$/,"")).replace(/\/+/g,"/"):"/"+$.replace(/\/+$/,""):"/",L_=($)=>$.endsWith("/")?$.slice(0,-1):$,W$=($)=>{return _$($)&&!S($.prototype)&&!_$($.prototype)&&Object.getOwnPropertyNames($.prototype).length>=1};class n{container;metadataRepository;diagnosticsEmitter;globalComponents=new Map([["middleware",new Set],["guard",new Set],["pipe",new Set],["filter",new Set]]);constructor($,_=new D,W=new H){this.container=$;this.metadataRepository=_;this.diagnosticsEmitter=W}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 Q=`${_.name}:${String(W)}`,X=this.metadataRepository.getHandlerComponents($,Q),Z=this.metadataRepository.getControllerComponents($,_);return[...Array.from(this.globalComponents.get($)||[]),...Z,...X]}resolveMiddleware($){return $.map((_)=>{if(K(_)&&"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(K(_)&&"canActivate"in _)return _;return this.container.resolve(_)})}getHandlerGuards($,_){let W=this.getComponents("guard",$,_);return this.resolveGuards(W)}resolvePipes($){return $.map((_)=>{if(K(_)&&"transform"in _)return _;return this.container.resolve(_)})}getHandlerPipes($,_){let W=this.getComponents("pipe",$,_);return this.resolvePipes(W)}async executePipes($,_,W){let Q=$;for(let X of W)Q=await X.transform(Q,_);return Q}async handleException($,_){let W=_.get(I),Q=_.get(M);if(W&&Q){let J=this.metadataRepository.getHandlerComponents("filter",`${W.name}:${Q}`);if(J.length>0){let Y=await this.executeFilters(J,$,_);if(Y)return Y}}if(W){let J=this.metadataRepository.getControllerComponents("filter",W);if(J.length>0){let Y=await this.executeFilters(J,$,_);if(Y)return Y}}let X=Array.from(this.globalComponents.get("filter")||[]);if(X.length>0){let J=await this.executeFilters(X,$,_);if(J)return J}let{response:Z,status:U}=R($,_);return _.json(Z,U)}async executeFilters($,_,W){for(let Q of $){let X;if(K(Q)&&"catch"in Q)X=Q;else X=this.container.resolve(Q);try{let Z=await X.catch(_,W);if(Z!==void 0)return Z}catch(Z){let U=X.constructor?.name||"UnknownFilter";this.diagnosticsEmitter.emit({level:"error",category:"errors",message:`Error in exception filter ${U}`,details:{error:Z instanceof Error?Z.message:String(Z)}});let{response:J,status:Y}=R(Z,W);return W.json(J,Y)}}return}async registerModule($,_=new Set){if(_.has($))return[];_.add($);let W=this.metadataRepository.getModuleOptions($);if(!W)throw this.diagnosticsEmitter.emit({level:"error",category:"startup",message:`Module ${$.name} is not properly decorated with @Module()`}),Error(`Module ${$.name} is not properly decorated with @Module()`);let Q=[];if(W.imports&&W.imports.length>0)for(let X of W.imports){let Z=await this.registerModule(X,_);Q.push(...Z)}if(W.services&&W.services.length>0)for(let X of W.services)this.container.resolve(X);if(W.controllers&&W.controllers.length>0)Q.push(...W.controllers);return Q}}class a{async invoke({handler:$,args:_,context:W,contextIndex:Q}){let X=await $(..._);if(Q!==void 0)return X;if(X instanceof Response)return X;if(S(X))return W.json(null);if(f(X))return W.text(X);return W.json(X)}}class o{componentManager;constructor($){this.componentManager=$}async resolveArguments($){let{controllerName:_,handlerName:W,handlerArity:Q,handlerParams:X,handlerPipes:Z,context:U}=$,J=X.length>0?Math.max(...X.map((B)=>B.index)):-1,Y=Array(Math.max(Q,J+1));for(let B of X){if(typeof B.factory!=="function")throw Error(`Invalid parameter decorator metadata for ${_}.${String(W)}`);let q=await B.factory(B.data,U),F=await this.componentManager.executePipes(q,{type:B.name,metatype:B.metatype,data:typeof B.data==="string"||typeof B.data>"u"?B.data:String(B.data)},Z);Y[B.index]=F}return Y}}import{HTTPException as Y$}from"hono/http-exception";class r{componentManager;parameterResolver;handlerInvoker;diagnosticsEmitter;debugPipeline;constructor($,_,W,Q=new H,X=!1){this.componentManager=$;this.parameterResolver=_;this.handlerInvoker=W;this.diagnosticsEmitter=Q;this.debugPipeline=X}async execute($){let{controllerClass:_,handlerName:W,handler:Q,handlerParams:X,handlerPipes:Z,contextIndex:U,context:J}=$;J.set(I,_),J.set(M,String(W));let Y=this.componentManager.getHandlerGuards(_,W);for(let q of Y)if(!await q.canActivate(J)){if(this.debugPipeline)this.diagnosticsEmitter.emit({level:"warn",category:"pipeline",message:`Guard rejected request at ${_.name}.${String(W)}`,details:{guard:q.constructor?.name||"UnknownGuard"}});throw new Y$(403,{message:`Forbidden by ${q.constructor?.name||"UnknownGuard"} at ${_.name}.${String(W)}`})}let B=await this.parameterResolver.resolveArguments({controllerName:_.name,handlerName:W,handlerArity:Q.length,handlerParams:X,handlerPipes:Z,context:J});if(this.debugPipeline)this.diagnosticsEmitter.emit({level:"debug",category:"pipeline",message:`Resolved handler arguments for ${_.name}.${String(W)}`,details:{guardCount:Y.length,parameterCount:X.length,pipeCount:Z.length}});return this.handlerInvoker.invoke({handler:Q,args:B,context:J,contextIndex:U})}}class t{hono;container;routeRegistry;componentManager;parameterResolver;pipelineExecutor;metadataRepository;diagnosticsEmitter;globalPrefix;globalVersion;constructor($,_,W,Q,X=new D,Z=new H,U={}){this.hono=$,this.container=_,this.routeRegistry=W,this.componentManager=Q,this.parameterResolver=new o(this.componentManager),this.diagnosticsEmitter=Z,this.pipelineExecutor=new r(this.componentManager,this.parameterResolver,new a,this.diagnosticsEmitter,Boolean(U.debugPipeline)),this.metadataRepository=X,this.globalPrefix=U.prefix!==void 0?this.normalizePath(U.prefix):void 0,this.globalVersion=U.version,this.applyGlobalMiddleware()}applyGlobalMiddleware(){let $=this.componentManager.getGlobalMiddleware();for(let _ of $)this.hono.use("*",_)}normalizePath($){if(!f($))throw Error(`Invalid path: expected a string but received ${typeof $}. Check your @Controller() and route decorator arguments.`);return s($)}registerRouteHandler($,_,W,Q){if(W.length>0)this.hono.on($.toUpperCase(),[_],...W,Q);else this.hono.on($.toUpperCase(),[_],Q)}buildRoutePath($,_,W,Q){return s(`${$}${_}${W}${Q}`)}formatVersionSegment($){if(S($))return"";return $===i?"":`/v${String($)}`}async registerController($){if(!this.metadataRepository.hasController($))throw Error(`Controller ${$.name} is not decorated with @Controller()`);let _=this.metadataRepository.getControllerPath($)||"",W=this.metadataRepository.getControllerOptions($)||{},Q=this.metadataRepository.getRoutes($)||[],X=this.metadataRepository.getParameters($)||new Map,Z=this.metadataRepository.getContextIndices($)||new Map,U=this.normalizePath(_),J=this.container.resolve($),Y=W.prefix!==void 0?W.prefix:this.globalPrefix,B=W.version!==void 0?W.version:this.globalVersion;if(Q.length===0)throw Error(`Controller ${$.name} has no route handlers. Add HTTP method decorators like @Get()`);for(let q of Q){let{path:F,method:A,version:V,prefix:G}=q,O=G!==void 0?G:Y,k=!S(O)?this.normalizePath(O):"",N=V!==void 0?V:B,P=this.normalizePath(F);if(S(N)){this.registerRoute(J,q,X,Z,$,k,"",U,P,A);continue}if(N===i){this.registerRoute(J,q,X,Z,$,k,"",U,P,A),this.registerRoute(J,q,X,Z,$,k,"/:version{v[0-9]+}",U,P,A);continue}if(Array.isArray(N)){for(let b of N){let y=this.formatVersionSegment(b);this.registerRoute(J,q,X,Z,$,k,y,U,P,A)}continue}let v=this.formatVersionSegment(N);this.registerRoute(J,q,X,Z,$,k,v,U,P,A)}}registerRoute($,_,W,Q,X,Z,U,J,Y,B){let{handlerName:q}=_,F=this.buildRoutePath(Z,U,J,Y),A=$[q].bind($),V=W.get(q)||[],G=Q.get(q),O=this.componentManager.getHandlerMiddleware(X,q),k=this.componentManager.getHandlerPipes(X,q);this.routeRegistry.registerRoute({controller:X.name,handler:q,method:B,prefix:Z,version:U,route:J,path:Y,fullPath:F,parameters:V});let N=this.componentManager,P=this.pipelineExecutor,v=async(b)=>{try{return await P.execute({controllerClass:X,handlerName:q,handler:A,handlerParams:V,handlerPipes:k,contextIndex:G,context:b})}catch(y){return N.handleException(y,b)}};this.registerRouteHandler(B,F,O,v)}}class w{hono;container;context;routeRegistry;metadataRepository;componentManager;routeManager;diagnosticsEmitter;options;static DEFAULT_PLUGIN_NAME="AnonymousPlugin";constructor($={},_=new D){this.options=K($)?$:{};let W=this.options.debug===!0||typeof this.options.debug==="object"&&Boolean(this.options.debug.pipeline),Q=this.options.debug===!0||typeof this.options.debug==="object"&&Boolean(this.options.debug.di);if(this.hono=new B$(this.options.hono),this.diagnosticsEmitter=this.options.diagnostics||new g,this.container=this.options.container||new E(void 0,this.diagnosticsEmitter,Q),this.context=new h,this.routeRegistry=new m,this.metadataRepository=_,this.componentManager=new n(this.container,this.metadataRepository,this.diagnosticsEmitter),this.componentManager.setupGlobalComponents(this.options),this.setupErrorHandlers(),this.routeManager=new t(this.hono,this.container,this.routeRegistry,this.componentManager,this.metadataRepository,this.diagnosticsEmitter,{prefix:this.options.routing?.prefix,version:this.options.routing?.version,debugPipeline:W}),this.options.deprecations?.printPreV1Warning)this.diagnosticsEmitter.emit({level:"warn",category:"deprecations",message:"Pre-v1 warning: APIs may change before 1.0.0."})}setupErrorHandlers(){this.hono.notFound(this.options.notFound||p.handle()),this.hono.onError(this.options.onError||c.handle())}resolvePlugin($){if(W$($))return new $;return $}normalizePluginEntry($,_){if($&&typeof $==="object"&&"plugin"in $){let Q=$,X=this.resolvePlugin(Q.plugin),Z=this.resolvePluginName(X,_,Q.name);return{plugin:X,name:Z,before:Q.before??[],after:Q.after??[],provides:X.meta?.provides??[],requires:X.meta?.requires??[],index:_,preProcessors:Q.preProcessors??[],postProcessors:Q.postProcessors??[]}}let W=this.resolvePlugin($);return{plugin:W,name:this.resolvePluginName(W,_),before:[],after:[],provides:W.meta?.provides??[],requires:W.meta?.requires??[],index:_,preProcessors:[],postProcessors:[]}}resolvePluginName($,_,W){let Q=W||$.meta?.name||$.constructor?.name;if(!Q||Q===w.DEFAULT_PLUGIN_NAME)return`${w.DEFAULT_PLUGIN_NAME}#${_+1}`;return Q}resolvePluginExecutionOrder($){if($.length===0)return $;let _=new Map;for(let J=0;J<$.length;J++){let Y=$[J];if(_.has(Y.name))throw Error(`Duplicate plugin name detected: ${Y.name}. Use unique plugin names in options.plugins.`);_.set(Y.name,J)}let W=Array($.length).fill(0),Q=new Map,X=(J,Y)=>{if(!Q.has(J))Q.set(J,new Set);let B=Q.get(J);if(!B.has(Y))B.add(Y),W[Y]++};for(let J=0;J<$.length;J++){let Y=$[J];for(let B of Y.after){let q=_.get(B);if(q===void 0)throw Error(`Plugin ordering error: ${Y.name} declares after '${B}', but no such plugin is registered.`);X(q,J)}for(let B of Y.before){let q=_.get(B);if(q===void 0)throw Error(`Plugin ordering error: ${Y.name} declares before '${B}', but no such plugin is registered.`);X(J,q)}}let Z=[];for(let J=0;J<$.length;J++)if(W[J]===0)Z.push(J);Z.sort((J,Y)=>$[J].index-$[Y].index);let U=[];while(Z.length>0){let J=Z.shift();U.push(J);let Y=Q.get(J);if(!Y)continue;for(let B of Y)if(W[B]--,W[B]===0)Z.push(B);Z.sort((B,q)=>$[B].index-$[q].index)}if(U.length!==$.length)throw Error("Plugin ordering cycle detected. Check before/after constraints in options.plugins.");return U.map((J)=>$[J])}validatePluginCapabilities($){if($.length===0)return;let _=new Set;for(let W of $){for(let Q of W.requires)if(!_.has(Q))throw Error(`Plugin capability error: ${W.name} requires '${Q}', but it was not provided by any previous plugin. Use before/after ordering or register the provider plugin earlier.`);for(let Q of W.provides)_.add(Q)}}shouldEmitRouteDiagnostics(){let $=this.options.debug;return $===!0||typeof $==="object"&&Boolean($.routes)}emitStartupGuide($,_){let W=this.options.startupGuide;if(!W)return;let Q=typeof W==="object"&&Boolean(W.verbose),X=$ instanceof Error?$.message:String($),Z=this.createStartupGuideHints(X);if(this.diagnosticsEmitter.emit({level:"warn",category:"startup",message:"Startup guide",details:{rootModule:_.name,errorMessage:X,hints:Z,verbose:Q}}),Q)this.diagnosticsEmitter.emit({level:"warn",category:"startup",message:"Startup guide (verbose)",details:{steps:["Verify decorators are present for controllers/services used by DI and routing.","Ensure 'reflect-metadata' is imported once at entry and 'emitDecoratorMetadata' is enabled.","Enable debug.startup for extra startup diagnostics and timing details."]}})}createStartupGuideHints($){let _=new Set;if(_.add("Check module wiring: root module imports, controllers, and services should be registered correctly."),$.includes("not decorated with @Controller()"))_.add("Add @Controller() to the class or remove it from module.controllers.");if($.includes("has no route handlers"))_.add("Add at least one HTTP method decorator such as @Get() or @Post() in the controller.");if($.includes("not decorated with @Service()"))_.add("Add @Service() to injectable classes used in constructor dependencies.");if($.includes("constructor metadata is missing")||$.includes("reflect-metadata"))_.add("Import 'reflect-metadata' in your entry file and enable 'emitDecoratorMetadata' in tsconfig.");if($.includes("Strict mode: no routes were registered"))_.add("Disable strict.requireRoutes for empty modules, or add a controller with at least one route.");if($.includes("Plugin ordering error")||$.includes("Plugin capability error"))_.add("Check plugin order and before/after constraints, then ensure required capabilities are provided earlier.");return[..._]}async register($){let _=await this.componentManager.registerModule($),W=this.shouldEmitRouteDiagnostics();for(let Q of _){let X=Date.now(),Z=this.routeRegistry.getRoutes().length;try{if(await this.routeManager.registerController(Q),W)this.diagnosticsEmitter.emit({level:"info",category:"routes",message:"Registered controller routes",details:{controller:Q.name,routeCountAdded:this.routeRegistry.getRoutes().length-Z,registrationDurationMs:Date.now()-X}})}catch(U){if(W)this.diagnosticsEmitter.emit({level:"error",category:"routes",message:"Failed to register controller routes",details:{controller:Q.name,registrationDurationMs:Date.now()-X,errorMessage:U instanceof Error?U.message:String(U)}});throw U}}return this}static async create($,_={}){let W=Date.now(),Q=C.fromRootModule($),X=new w(_,Q),Z=(_.plugins||[]).map((V,G)=>X.normalizePluginEntry(V,G)),U=X.resolvePluginExecutionOrder(Z);X.validatePluginCapabilities(U);let J=X.getContext(),Y=_.debug,B=Y===!0||typeof Y==="object"&&Y.plugins,q=Y===!0||typeof Y==="object"&&Y.routes,F=Y===!0||typeof Y==="object"&&(Y.startup||q),A=!1;try{if(B&&U.length>0)X.diagnosticsEmitter.emit({level:"info",category:"plugins",message:`Plugin order: ${U.map(({name:G})=>G).join(" -> ")}`});for(let{plugin:G,preProcessors:O}of U){for(let k of O)await k(X,X.hono,J);if(G.beforeModulesRegistered)await G.beforeModulesRegistered(X,X.hono)}await X.register($);let V=X.getRoutes();if(F)X.diagnosticsEmitter.emit({level:"info",category:"startup",message:`Application registered ${V.length} route(s)`,details:{routeCount:V.length,rootModule:$.name}});if(_.strict?.requireRoutes&&V.length===0){A=!0,X.diagnosticsEmitter.emit({level:"error",category:"startup",message:"Strict mode failed: no routes were registered",details:{rootModule:$.name,requireRoutes:!0,startupDurationMs:Date.now()-W}});let G=Error("Strict mode: no routes were registered. Check your module/controller decorators.");throw X.emitStartupGuide(G,$),G}if(q)X.diagnosticsEmitter.emit({level:"info",category:"routes",message:"Registered routes",details:{routes:V.map((G)=>`${G.method.toUpperCase()} ${G.fullPath}`)}});for(let{plugin:G,postProcessors:O}of U){if(G.afterModulesRegistered)await G.afterModulesRegistered(X,X.hono);for(let k of O)await k(X,X.hono,J)}if(F)X.diagnosticsEmitter.emit({level:"info",category:"startup",message:"Application startup completed",details:{rootModule:$.name,pluginCount:U.length,routeCount:V.length,startupDurationMs:Date.now()-W}});return{app:X,hono:X.getApp()}}catch(V){if(X.emitStartupGuide(V,$),F&&!A)X.diagnosticsEmitter.emit({level:"error",category:"startup",message:"Application startup failed",details:{rootModule:$.name,startupDurationMs:Date.now()-W,errorMessage:V instanceof Error?V.message:String(V)}});throw V}}getApp(){return this.hono}getContainer(){return this.container}getContext(){return this.context}getRoutes(){return this.routeRegistry.getRoutes()}}import{html as j,raw as e}from"hono/html";var L$={type:"website",locale:"en_US"},$$=($)=>{if(!$)return"";return Object.entries($).map(([_,W])=>{if(typeof W==="boolean")return W?_:"";let Q=String(W).replace(/"/g,""");return`${_}="${Q}"`}).filter(Boolean).join(" ")},r_=($)=>{let _={...L$,...$};return j`
|
|
1
|
+
import"reflect-metadata";import{Hono as B$}from"hono";class h{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 g{emit($){let _=`[HonestJS:${$.category}]`,W=$.details?[_,$.message,$.details]:[_,$.message];switch($.level){case"debug":case"info":console.info(...W);break;case"warn":console.warn(...W);break;case"error":console.error(...W);break}}}class A{emit($){}}class Y{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 Q=this.controller.get($);if(!Q.has(_))Q.set(_,[]);Q.get(_).push(W)}static getController($,_){return this.controller.get($).get(_)||[]}static registerHandler($,_,W){let Q=this.handler.get($);if(!Q.has(_))Q.set(_,[]);Q.get(_).push(W)}static getHandler($,_){return this.handler.get($).get(_)||[]}static clearHandlerComponents(){for(let $ of this.handler.values())$.clear()}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 H{hasController($){return Y.hasController($)}getControllerPath($){return Y.getControllerPath($)}getControllerOptions($){return Y.getControllerOptions($)}getRoutes($){return Y.getRoutes($)}getParameters($){return Y.getParameters($)}getContextIndices($){return Y.getContextIndices($)}getModuleOptions($){return Y.getModuleOptions($)}getControllerComponents($,_){return Y.getController($,_)}getHandlerComponents($,_){return Y.getHandler($,_)}}class C{controllerPaths=new Map;controllerOptions=new Map;routes=new Map;parameters=new Map;contextIndices=new Map;modules=new Map;controllerComponents=new Map([["middleware",new Map],["guard",new Map],["pipe",new Map],["filter",new Map]]);handlerComponents=new Map([["middleware",new Map],["guard",new Map],["pipe",new Map],["filter",new Map]]);static fromRootModule($,_=new H){let W=new C;return W.captureModuleGraph($,_),W}hasController($){return this.controllerPaths.has($)}getControllerPath($){return this.controllerPaths.get($)||""}getControllerOptions($){let _=this.controllerOptions.get($);return _?{..._}:{}}getRoutes($){return(this.routes.get($)||[]).map((_)=>this.cloneRouteDefinition(_))}getParameters($){let _=this.parameters.get($);if(!_)return new Map;let W=new Map;for(let[Q,X]of _.entries())W.set(Q,X.map((Z)=>({...Z})));return W}getContextIndices($){return new Map(this.contextIndices.get($)||new Map)}getModuleOptions($){let _=this.modules.get($);if(!_)return;return{controllers:_.controllers?[..._.controllers]:void 0,services:_.services?[..._.services]:void 0,imports:_.imports?[..._.imports]:void 0}}getControllerComponents($,_){return[...this.controllerComponents.get($).get(_)||[]]}getHandlerComponents($,_){return[...this.handlerComponents.get($).get(_)||[]]}captureModuleGraph($,_){let W=new Set,Q=new Set,X=(Z)=>{if(W.has(Z))return;W.add(Z);let J=_.getModuleOptions(Z);if(!J)return;let U={controllers:J.controllers?[...J.controllers]:void 0,services:J.services?[...J.services]:void 0,imports:J.imports?[...J.imports]:void 0};this.modules.set(Z,U);for(let B of U.controllers||[])Q.add(B);for(let B of U.imports||[])X(B)};X($);for(let Z of Q)this.captureController(Z,_)}captureController($,_){if(!_.hasController($))return;this.controllerPaths.set($,_.getControllerPath($)||""),this.controllerOptions.set($,{..._.getControllerOptions($)});let W=(_.getRoutes($)||[]).map((Z)=>this.cloneRouteDefinition(Z));this.routes.set($,W);let Q=_.getParameters($),X=new Map;for(let[Z,J]of Q.entries())X.set(Z,(J||[]).map((U)=>({...U})));this.parameters.set($,X),this.contextIndices.set($,new Map(_.getContextIndices($)||new Map));for(let Z of["middleware","guard","pipe","filter"])this.controllerComponents.get(Z).set($,[..._.getControllerComponents(Z,$)||[]]);for(let Z of W){let J=`${$.name}:${String(Z.handlerName)}`;for(let U of["middleware","guard","pipe","filter"])this.handlerComponents.get(U).set(J,[..._.getHandlerComponents(U,J)||[]])}}cloneRouteDefinition($){return{...$,version:Array.isArray($.version)?[...$.version]:$.version}}}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 u{isService($){return Y.isService($)}}class w{serviceRegistry;logger;debugDi;constructor($=new u,_=new A,W=!1){this.serviceRegistry=$;this.logger=_;this.debugDi=W}instances=new Map;emitLog($){if(!this.debugDi)return;this.logger.emit($)}resolve($){return this.resolveWithTracking($,new Set)}resolveWithTracking($,_){if(this.instances.has($))return this.emitLog({level:"debug",category:"di",message:`Resolved ${$.name} from DI cache`}),this.instances.get($);if(_.has($)){let Z=[..._.keys(),$].map((J)=>J.name).join(" -> ");throw this.emitLog({level:"error",category:"di",message:`Circular dependency detected while resolving ${$.name}`,details:{cycle:Z}}),Error(`Circular dependency detected: ${Z}`)}_.add($),this.emitLog({level:"debug",category:"di",message:`Resolving ${$.name}`,details:{resolving:[..._].map((Z)=>Z.name)}});let W=Reflect.getMetadata("design:paramtypes",$)||[];if($.length>0&&W.length===0){if(!this.serviceRegistry.isService($))throw this.emitLog({level:"error",category:"di",message:`Cannot resolve ${$.name}: missing @Service() decorator`}),Error(`Cannot resolve ${$.name}: it is not decorated with @Service(). Did you forget to add @Service() to the class?`);throw this.emitLog({level:"error",category:"di",message:`Cannot resolve ${$.name}: missing constructor metadata`}),Error(`Cannot resolve dependencies for ${$.name}: constructor metadata is missing. Ensure 'reflect-metadata' is imported and 'emitDecoratorMetadata' is enabled.`)}let Q=W.map((Z,J)=>{if(!Z||Z===Object||Z===Array||Z===Function)throw this.emitLog({level:"error",category:"di",message:`Cannot resolve dependency at index ${J} of ${$.name}`}),Error(`Cannot resolve dependency at index ${J} of ${$.name}. Use concrete class types for constructor dependencies.`);return this.resolveWithTracking(Z,new Set(_))}),X=new $(...Q);return this.instances.set($,X),this.emitLog({level:"debug",category:"di",message:`Created ${$.name} instance`,details:{dependencyCount:Q.length}}),X}register($,_){this.instances.set($,_)}has($){return this.instances.has($)}clear(){this.instances.clear()}}import{HTTPException as U$}from"hono/http-exception";class d extends Error{status;code;category;remediation;details;constructor($,_){super($);if(this.name="FrameworkError",this.status=_.status,this.code=_.code,this.category=_.category,this.remediation=_.remediation,this.details=_.details,_.cause!==void 0)this.cause=_.cause}}function b($,_,W){let Q=$ instanceof Error?$:Error(String($)),X=new Date().toISOString(),Z=_.get("requestId"),J=_.req.path;if(Q instanceof U$)return{response:{status:W?.status||Q.status,message:W?.title||Q.message,timestamp:X,path:J,requestId:Z,code:W?.code,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:W?.status||Q.status};if(Q instanceof d){let j=W?.status||Q.status||500;return{response:{status:j,message:W?.title||Q.message,timestamp:X,path:J,requestId:Z,code:W?.code||Q.code,details:{category:Q.category,remediation:Q.remediation,...Q.details,...W?.additionalDetails},...W?.detail&&{detail:W.detail}},status:j}}if(Q.statusCode||Q.status){let j=Q.statusCode||Q.status||500,q=W?.status||j;return{response:{status:q,message:W?.title||Q.message,timestamp:X,path:J,requestId:Z,code:W?.code||Q.name,details:W?.additionalDetails,...W?.detail&&{detail:W.detail}},status:q}}let U=W?.status||500;return{response:{status:U,message:W?.title||Q.message,timestamp:X,path:J,requestId:Z,code:W?.code||Q.name,details:W?.additionalDetails||{stack:Q.stack},...W?.detail&&{detail:W.detail}},status:U}}function O($){return(_="",W={})=>{return(Q,X,Z)=>{let J=Q.constructor;Y.addRoute(J,{path:_,method:$,handlerName:X,version:W.version,prefix:W.prefix})}}}function L($,_){let W=(Q,X)=>{if(Q===void 0)return X;return X.get(String(Q))};return(Q)=>{return(X,Z,J)=>{let U=X.constructor;if(!Y.getParameters(U).size)Y.setParameterMap(U,new Map);let B=Y.getParameters(U);if(!B.has(Z))B.set(Z,[]);let q=Reflect.getMetadata("design:paramtypes",X,Z)?.[J];if(B.get(Z).push({index:J,name:$,data:Q,factory:_||W,metatype:q}),$==="context"){if(!Y.getContextIndices(U).size)Y.setContextIndices(U,new Map);Y.getContextIndices(U).set(Z,J)}}}}class c{static handle(){return async($,_)=>{let{response:W,status:Q}=b($,_);return _.json(W,Q)}}}class p{static handle(){return async($)=>{return $.json({message:`Not Found - ${$.req.path}`},404)}}}var i=Symbol("VERSION_NEUTRAL");var I="__honest_controllerClass",M="__honest_handlerName",s="__honest.body.cache";var X_=($)=>typeof $>"u",S=($)=>$===null||typeof $>"u",T=($)=>$!==null&&typeof $==="object",Z_=($)=>{if(!T($))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)},_$=($)=>typeof $==="function",f=($)=>typeof $==="string",J_=($)=>typeof $==="number",U_=($)=>$.length===0,Y_=($)=>typeof $==="symbol",B_=($)=>typeof $==="string"?$.charAt(0)!=="/"?"/"+$:$:"",l=($)=>$?$.startsWith("/")?("/"+$.replace(/\/+$/,"")).replace(/\/+/g,"/"):"/"+$.replace(/\/+$/,""):"/",q_=($)=>$.endsWith("/")?$.slice(0,-1):$,W$=($)=>{return _$($)&&!S($.prototype)&&!_$($.prototype)&&Object.getOwnPropertyNames($.prototype).length>=1};class n{container;metadataRepository;logger;globalComponents=new Map([["middleware",new Set],["guard",new Set],["pipe",new Set],["filter",new Set]]);constructor($,_=new H,W=new A){this.container=$;this.metadataRepository=_;this.logger=W}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 Q=`${_.name}:${String(W)}`,X=this.metadataRepository.getHandlerComponents($,Q),Z=this.metadataRepository.getControllerComponents($,_);return[...Array.from(this.globalComponents.get($)||[]),...Z,...X]}resolveMiddleware($){return $.map((_)=>{if(T(_)&&"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(T(_)&&"canActivate"in _)return _;return this.container.resolve(_)})}getHandlerGuards($,_){let W=this.getComponents("guard",$,_);return this.resolveGuards(W)}resolvePipes($){return $.map((_)=>{if(T(_)&&"transform"in _)return _;return this.container.resolve(_)})}getHandlerPipes($,_){let W=this.getComponents("pipe",$,_);return this.resolvePipes(W)}async executePipes($,_,W){let Q=$;for(let X of W)Q=await X.transform(Q,_);return Q}async handleException($,_){let W=_.get(I),Q=_.get(M);if(W&&Q){let U=this.metadataRepository.getHandlerComponents("filter",`${W.name}:${Q}`);if(U.length>0){let B=await this.executeFilters(U,$,_);if(B)return B}}if(W){let U=this.metadataRepository.getControllerComponents("filter",W);if(U.length>0){let B=await this.executeFilters(U,$,_);if(B)return B}}let X=Array.from(this.globalComponents.get("filter")||[]);if(X.length>0){let U=await this.executeFilters(X,$,_);if(U)return U}let{response:Z,status:J}=b($,_);return _.json(Z,J)}async executeFilters($,_,W){for(let Q of $){let X;if(T(Q)&&"catch"in Q)X=Q;else X=this.container.resolve(Q);try{let Z=await X.catch(_,W);if(Z!==void 0)return Z}catch(Z){let J=X.constructor?.name||"UnknownFilter";this.logger.emit({level:"error",category:"errors",message:`Error in exception filter ${J}`,details:{error:Z instanceof Error?Z.message:String(Z)}});let{response:U,status:B}=b(Z,W);return W.json(U,B)}}return}async registerModule($,_=new Set){if(_.has($))return[];_.add($);let W=this.metadataRepository.getModuleOptions($);if(!W)throw this.logger.emit({level:"error",category:"startup",message:`Module ${$.name} is not properly decorated with @Module()`}),Error(`Module ${$.name} is not properly decorated with @Module()`);let Q=[];if(W.imports&&W.imports.length>0)for(let X of W.imports){let Z=await this.registerModule(X,_);Q.push(...Z)}if(W.services&&W.services.length>0)for(let X of W.services)this.container.resolve(X);if(W.controllers&&W.controllers.length>0)Q.push(...W.controllers);return Q}}class a{async invoke({handler:$,args:_,context:W,contextIndex:Q}){let X=await $(..._);if(Q!==void 0)return X;if(X instanceof Response)return X;if(S(X))return W.json(null);if(f(X))return W.text(X);return W.json(X)}}class r{componentManager;constructor($){this.componentManager=$}async resolveArguments($){let{controllerName:_,handlerName:W,handlerArity:Q,handlerParams:X,handlerPipes:Z,context:J}=$,U=X.length>0?Math.max(...X.map((j)=>j.index)):-1,B=Array(Math.max(Q,U+1));for(let j of X){if(typeof j.factory!=="function")throw Error(`Invalid parameter decorator metadata for ${_}.${String(W)}`);let q=await j.factory(j.data,J),z=await this.componentManager.executePipes(q,{type:j.name,metatype:j.metatype,data:typeof j.data==="string"||typeof j.data>"u"?j.data:String(j.data)},Z);B[j.index]=z}return B}}import{HTTPException as Y$}from"hono/http-exception";class o{componentManager;parameterResolver;handlerInvoker;logger;debugPipeline;constructor($,_,W,Q=new A,X=!1){this.componentManager=$;this.parameterResolver=_;this.handlerInvoker=W;this.logger=Q;this.debugPipeline=X}async execute($){let{controllerClass:_,handlerName:W,handler:Q,handlerParams:X,handlerPipes:Z,contextIndex:J,context:U}=$;U.set(I,_),U.set(M,String(W));let B=this.componentManager.getHandlerGuards(_,W);for(let q of B)if(!await q.canActivate(U)){if(this.debugPipeline)this.logger.emit({level:"warn",category:"pipeline",message:`Guard rejected request at ${_.name}.${String(W)}`,details:{guard:q.constructor?.name||"UnknownGuard"}});throw new Y$(403,{message:`Forbidden by ${q.constructor?.name||"UnknownGuard"} at ${_.name}.${String(W)}`})}let j=await this.parameterResolver.resolveArguments({controllerName:_.name,handlerName:W,handlerArity:Q.length,handlerParams:X,handlerPipes:Z,context:U});if(this.debugPipeline)this.logger.emit({level:"debug",category:"pipeline",message:`Resolved handler arguments for ${_.name}.${String(W)}`,details:{guardCount:B.length,parameterCount:X.length,pipeCount:Z.length}});return this.handlerInvoker.invoke({handler:Q,args:j,context:U,contextIndex:J})}}class t{hono;container;routeRegistry;componentManager;parameterResolver;pipelineExecutor;metadataRepository;logger;globalPrefix;globalVersion;constructor($,_,W,Q,X=new H,Z=new A,J={}){this.hono=$,this.container=_,this.routeRegistry=W,this.componentManager=Q,this.parameterResolver=new r(this.componentManager),this.logger=Z,this.pipelineExecutor=new o(this.componentManager,this.parameterResolver,new a,this.logger,Boolean(J.debugPipeline)),this.metadataRepository=X,this.globalPrefix=J.prefix!==void 0?this.normalizePath(J.prefix):void 0,this.globalVersion=J.version,this.applyGlobalMiddleware()}applyGlobalMiddleware(){let $=this.componentManager.getGlobalMiddleware();for(let _ of $)this.hono.use("*",_)}normalizePath($){if(!f($))throw Error(`Invalid path: expected a string but received ${typeof $}. Check your @Controller() and route decorator arguments.`);return l($)}registerRouteHandler($,_,W,Q){if(W.length>0)this.hono.on($.toUpperCase(),[_],...W,Q);else this.hono.on($.toUpperCase(),[_],Q)}buildRoutePath($,_,W,Q){return l(`${$}${_}${W}${Q}`)}formatVersionSegment($){if(S($))return"";return $===i?"":`/v${String($)}`}async registerController($){if(!this.metadataRepository.hasController($))throw Error(`Controller ${$.name} is not decorated with @Controller()`);let _=this.metadataRepository.getControllerPath($)||"",W=this.metadataRepository.getControllerOptions($)||{},Q=this.metadataRepository.getRoutes($)||[],X=this.metadataRepository.getParameters($)||new Map,Z=this.metadataRepository.getContextIndices($)||new Map,J=this.normalizePath(_),U=this.container.resolve($),B=W.prefix!==void 0?W.prefix:this.globalPrefix,j=W.version!==void 0?W.version:this.globalVersion;if(Q.length===0)throw Error(`Controller ${$.name} has no route handlers. Add HTTP method decorators like @Get()`);for(let q of Q){let{path:z,method:G,version:V,prefix:k}=q,D=k!==void 0?k:B,N=!S(D)?this.normalizePath(D):"",K=V!==void 0?V:j,E=this.normalizePath(z);if(S(K)){this.registerRoute(U,q,X,Z,$,N,"",J,E,G);continue}if(K===i){this.registerRoute(U,q,X,Z,$,N,"",J,E,G),this.registerRoute(U,q,X,Z,$,N,"/:version{v[0-9]+}",J,E,G);continue}if(Array.isArray(K)){for(let R of K){let y=this.formatVersionSegment(R);this.registerRoute(U,q,X,Z,$,N,y,J,E,G)}continue}let v=this.formatVersionSegment(K);this.registerRoute(U,q,X,Z,$,N,v,J,E,G)}}registerRoute($,_,W,Q,X,Z,J,U,B,j){let{handlerName:q}=_,z=this.buildRoutePath(Z,J,U,B),G=$[q].bind($),V=W.get(q)||[],k=Q.get(q),D=this.componentManager.getHandlerMiddleware(X,q),N=this.componentManager.getHandlerPipes(X,q);this.routeRegistry.registerRoute({controller:X.name,handler:q,method:j,prefix:Z,version:J,route:U,path:B,fullPath:z,parameters:V});let K=this.componentManager,E=this.pipelineExecutor,v=async(R)=>{try{return await E.execute({controllerClass:X,handlerName:q,handler:G,handlerParams:V,handlerPipes:N,contextIndex:k,context:R})}catch(y){return K.handleException(y,R)}};this.registerRouteHandler(j,z,D,v)}}class P{hono;container;context;routeRegistry;metadataRepository;componentManager;routeManager;logger;options;static DEFAULT_PLUGIN_NAME="AnonymousPlugin";constructor($={},_=new H){this.options=T($)?$:{};let W=this.options.debug===!0||typeof this.options.debug==="object"&&Boolean(this.options.debug.pipeline),Q=this.options.debug===!0||typeof this.options.debug==="object"&&Boolean(this.options.debug.di);if(this.hono=new B$(this.options.hono),this.logger=this.options.logger||new g,this.container=this.options.container||new w(void 0,this.logger,Q),this.context=new h,this.routeRegistry=new m,this.metadataRepository=_,this.componentManager=new n(this.container,this.metadataRepository,this.logger),this.componentManager.setupGlobalComponents(this.options),this.setupErrorHandlers(),this.routeManager=new t(this.hono,this.container,this.routeRegistry,this.componentManager,this.metadataRepository,this.logger,{prefix:this.options.routing?.prefix,version:this.options.routing?.version,debugPipeline:W}),this.options.deprecations?.printPreV1Warning)this.logger.emit({level:"warn",category:"deprecations",message:"Pre-v1 warning: APIs may change before 1.0.0."})}setupErrorHandlers(){this.hono.notFound(this.options.notFound||p.handle()),this.hono.onError(this.options.onError||c.handle())}resolvePlugin($){if(W$($))return new $;return $}normalizePluginEntry($,_){if($&&typeof $==="object"&&"plugin"in $){let Q=$,X=this.resolvePlugin(Q.plugin),Z=this.resolvePluginName(X,_,Q.name);return{plugin:X,name:Z,preProcessors:Q.preProcessors??[],postProcessors:Q.postProcessors??[]}}let W=this.resolvePlugin($);return{plugin:W,name:this.resolvePluginName(W,_),preProcessors:[],postProcessors:[]}}resolvePluginName($,_,W){let Q=W||$.meta?.name||$.constructor?.name;if(!Q||Q===P.DEFAULT_PLUGIN_NAME)return`${P.DEFAULT_PLUGIN_NAME}#${_+1}`;return Q}shouldEmitRouteDiagnostics(){let $=this.options.debug;return $===!0||typeof $==="object"&&Boolean($.routes)}emitStartupGuide($,_){let W=this.options.startupGuide;if(!W)return;let Q=typeof W==="object"&&Boolean(W.verbose),X=$ instanceof Error?$.message:String($),Z=this.createStartupGuideHints(X);if(this.logger.emit({level:"warn",category:"startup",message:"Startup guide",details:{rootModule:_.name,errorMessage:X,hints:Z,verbose:Q}}),Q)this.logger.emit({level:"warn",category:"startup",message:"Startup guide (verbose)",details:{steps:["Verify decorators are present for controllers/services used by DI and routing.","Ensure 'reflect-metadata' is imported once at entry and 'emitDecoratorMetadata' is enabled.","Enable debug.startup for extra startup diagnostics and timing details."]}})}createStartupGuideHints($){let _=new Set;if(_.add("Check module wiring: root module imports, controllers, and services should be registered correctly."),$.includes("not decorated with @Controller()"))_.add("Add @Controller() to the class or remove it from module.controllers.");if($.includes("has no route handlers"))_.add("Add at least one HTTP method decorator such as @Get() or @Post() in the controller.");if($.includes("not decorated with @Service()"))_.add("Add @Service() to injectable classes used in constructor dependencies.");if($.includes("constructor metadata is missing")||$.includes("reflect-metadata"))_.add("Import 'reflect-metadata' in your entry file and enable 'emitDecoratorMetadata' in tsconfig.");if($.includes("Strict mode: no routes were registered"))_.add("Disable strict.requireRoutes for empty modules, or add a controller with at least one route.");return[..._]}async register($){let _=await this.componentManager.registerModule($),W=this.shouldEmitRouteDiagnostics();for(let Q of _){let X=Date.now(),Z=this.routeRegistry.getRoutes().length;try{if(await this.routeManager.registerController(Q),W)this.logger.emit({level:"info",category:"routes",message:"Registered controller routes",details:{controller:Q.name,routeCountAdded:this.routeRegistry.getRoutes().length-Z,registrationDurationMs:Date.now()-X}})}catch(J){if(W)this.logger.emit({level:"error",category:"routes",message:"Failed to register controller routes",details:{controller:Q.name,registrationDurationMs:Date.now()-X,errorMessage:J instanceof Error?J.message:String(J)}});throw J}}return this}static async create($,_={}){let W=Date.now(),Q=C.fromRootModule($),X=new P(_,Q),Z=(_.plugins||[]).map((G,V)=>X.normalizePluginEntry(G,V)),J=X.getContext(),U=_.debug,B=U===!0||typeof U==="object"&&U.plugins,j=U===!0||typeof U==="object"&&U.routes,q=U===!0||typeof U==="object"&&(U.startup||j),z=!1;try{if(B&&Z.length>0)X.logger.emit({level:"info",category:"plugins",message:`Plugin order: ${Z.map(({name:V})=>V).join(" -> ")}`});for(let{plugin:V,preProcessors:k}of Z){V.logger=X.logger;for(let D of k)await D(X,X.hono,J);if(V.beforeModulesRegistered)await V.beforeModulesRegistered(X,X.hono)}await X.register($);let G=X.getRoutes();if(q)X.logger.emit({level:"info",category:"startup",message:`Application registered ${G.length} route(s)`,details:{routeCount:G.length,rootModule:$.name}});if(_.strict?.requireRoutes&&G.length===0){z=!0,X.logger.emit({level:"error",category:"startup",message:"Strict mode failed: no routes were registered",details:{rootModule:$.name,requireRoutes:!0,startupDurationMs:Date.now()-W}});let V=Error("Strict mode: no routes were registered. Check your module/controller decorators.");throw X.emitStartupGuide(V,$),V}if(j)X.logger.emit({level:"info",category:"routes",message:"Registered routes",details:{routes:G.map((V)=>`${V.method.toUpperCase()} ${V.fullPath}`)}});for(let{plugin:V,postProcessors:k}of Z){if(V.afterModulesRegistered)await V.afterModulesRegistered(X,X.hono);for(let D of k)await D(X,X.hono,J)}if(q)X.logger.emit({level:"info",category:"startup",message:"Application startup completed",details:{rootModule:$.name,pluginCount:Z.length,routeCount:G.length,startupDurationMs:Date.now()-W}});return{app:X,hono:X.getApp()}}catch(G){if(X.emitStartupGuide(G,$),q&&!z)X.logger.emit({level:"error",category:"startup",message:"Application startup failed",details:{rootModule:$.name,startupDurationMs:Date.now()-W,errorMessage:G instanceof Error?G.message:String(G)}});throw G}}getApp(){return this.hono}getContainer(){return this.container}getContext(){return this.context}getRoutes(){return this.routeRegistry.getRoutes()}}import{html as F,raw as e}from"hono/html";var q$={type:"website",locale:"en_US"},$$=($)=>{if(!$)return"";return Object.entries($).map(([_,W])=>{if(typeof W==="boolean")return W?_:"";let Q=String(W).replace(/"/g,""");return`${_}="${Q}"`}).filter(Boolean).join(" ")},o_=($)=>{let _={...q$,...$};return F`
|
|
2
2
|
<!DOCTYPE html>
|
|
3
3
|
<html lang="${_.locale?.split("_")[0]||"en"}" ${e($$(_.htmlAttributes))}>
|
|
4
4
|
<head ${e($$(_.headAttributes))}>
|
|
5
5
|
<meta charset="UTF-8" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
${_.csp?
|
|
7
|
+
${_.csp?F`<meta http-equiv="Content-Security-Policy" content="${_.csp}" />`:""}
|
|
8
8
|
<title>${_.title}</title>
|
|
9
|
-
${_.description?
|
|
9
|
+
${_.description?F`<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?F`<meta property="og:description" content="${_.description}" />`:""}
|
|
15
|
+
${_.image?F`<meta property="og:image" content="${_.image}" />`:""}
|
|
16
|
+
${_.url?F`<meta property="og:url" content="${_.url}" />`:""}
|
|
17
|
+
${_.locale?F`<meta property="og:locale" content="${_.locale}" />`:""}
|
|
18
|
+
${_.type?F`<meta property="og:type" content="${_.type}" />`:""}
|
|
19
|
+
${_.siteName?F`<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 B$}from"hono";class h{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?F`<meta name="twitter:description" content="${_.description}" />`:""}
|
|
28
|
+
${_.image?F`<meta name="twitter:image" content="${_.image}" />`:""}
|
|
29
29
|
|
|
30
30
|
<!-- Custom Meta Tags -->
|
|
31
|
-
${_.customMeta?_.customMeta.map((W)=>{let Q=W.name?`name="${W.name}"`:"",X=W.property?`property="${W.property}"`:"";return
|
|
31
|
+
${_.customMeta?_.customMeta.map((W)=>{let Q=W.name?`name="${W.name}"`:"",X=W.property?`property="${W.property}"`:"";return F`<meta ${Q} ${X} content="${W.content}" />`}):""}
|
|
32
32
|
|
|
33
33
|
<!-- Favicon -->
|
|
34
|
-
${_.favicon?
|
|
34
|
+
${_.favicon?F`<link rel="icon" href="${_.favicon}" />`:""}
|
|
35
35
|
|
|
36
36
|
<!-- Stylesheets -->
|
|
37
|
-
${_.stylesheets?_.stylesheets.map((W)=>
|
|
37
|
+
${_.stylesheets?_.stylesheets.map((W)=>F`<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 F`<script src="${W}"></script>`;let{src:Q,async:X,defer:Z}=W;if(X&&Z)return F`<script src="${Q}" async defer></script>`;if(X)return F`<script src="${Q}" async></script>`;if(Z)return F`<script src="${Q}" defer></script>`;return F`<script src="${Q}"></script>`}):""}
|
|
41
41
|
</head>
|
|
42
42
|
<body ${e($$(_.bodyAttributes))}>
|
|
43
43
|
${_.children}
|
|
44
44
|
</body>
|
|
45
45
|
</html>
|
|
46
|
-
`};function Q$($="",_={}){return(W)=>{
|
|
46
|
+
`};function Q$($="",_={}){return(W)=>{Y.setControllerPath(W,$),Y.setControllerOptions(W,_)}}var X$=O("get"),XW=O("post"),ZW=O("put"),JW=O("delete"),UW=O("patch"),YW=O("options"),BW=O("all");function x($={}){return(_)=>{Y.setModuleOptions(_,$)}}function zW($="",_={prefix:null,version:null}){return Q$($,_)}var AW=X$;function kW($={}){return x({imports:$.imports,services:$.services,controllers:($.views||[]).concat($.controllers||[])})}var TW=L("body",async($,_)=>{let W=_.get(s);if(W===void 0)W=await _.req.json(),_.set(s,W);if($&&W&&typeof W==="object")return W[String($)];return W}),NW=L("param",($,_)=>{return $?_.req.param(String($)):_.req.param()}),KW=L("query",($,_)=>{return $?_.req.query(String($)):_.req.query()}),EW=L("header",($,_)=>{return $?_.req.header(String($)):_.req.header()}),SW=L("request",($,_)=>_.req),PW=L("request",($,_)=>_.req),wW=L("response",($,_)=>_.res),bW=L("response",($,_)=>_.res),RW=L("context",($,_)=>_),CW=L("context",($,_)=>_),IW=L("variable",($,_)=>$===void 0?void 0:_.get(String($))),MW=L("variable",($,_)=>$===void 0?void 0:_.get(String($)));function vW(){return($)=>{Y.addService($)}}function gW($,..._){return(W,Q)=>{if(Q){let Z=`${W.constructor.name}:${String(Q)}`;_.forEach((J)=>Y.registerHandler($,Z,J))}else _.forEach((X)=>Y.registerController($,W,X))}}function dW(...$){return(_,W)=>{if(W){let X=`${_.constructor.name}:${String(W)}`;$.forEach((Z)=>Y.registerHandler("filter",X,Z))}else $.forEach((Q)=>Y.registerController("filter",_,Q))}}function iW(...$){return(_,W)=>{if(W){let X=`${_.constructor.name}:${String(W)}`;$.forEach((Z)=>Y.registerHandler("guard",X,Z))}else $.forEach((Q)=>Y.registerController("guard",_,Q))}}function nW(...$){return(_,W)=>{if(W){let X=`${_.constructor.name}:${String(W)}`;$.forEach((Z)=>Y.registerHandler("middleware",X,Z))}else $.forEach((Q)=>Y.registerController("middleware",_,Q))}}function oW(...$){return(_,W)=>{if(W){let X=`${_.constructor.name}:${String(W)}`;$.forEach((Z)=>Y.registerHandler("pipe",X,Z))}else $.forEach((Q)=>Y.registerController("pipe",_,Q))}}function Z$($={}){let{controllers:_,services:W,imports:Q,name:X="TestModule"}=$,Z={[X]:class{}}[X];return x({controllers:_,services:W,imports:Q})(Z),Z}async function J$($={}){let{module:_,appOptions:W,...Q}=$,X=_??Z$(Q),{app:Z,hono:J}=await P.create(X,W);return{app:Z,hono:J,request:(B,j)=>{if(typeof B==="string"){let q=B.startsWith("http://")||B.startsWith("https://")?B:`http://localhost${B.startsWith("/")?B:`/${B}`}`;return Promise.resolve(J.request(q,j))}return Promise.resolve(J.request(B))}}}async function g8($){let{controller:_,...W}=$;return J$({...W,controllers:[_]})}function c8($={}){let _=$.logger??new A,W=new w(void 0,_,Boolean($.debugDi));for(let Q of $.overrides??[]){let X=Q;W.register(X.provide,X.useValue)}for(let Q of $.preload??[])W.resolve(Q);return{container:W,get(Q){return W.resolve(Q)},register(Q,X){W.register(Q,X)},has(Q){return W.has(Q)},clear(){W.clear()}}}export{q_ as stripEndSlash,l as normalizePath,X_ as isUndefined,Y_ as isSymbol,f as isString,Z_ as isPlainObject,T as isObject,J_ as isNumber,S as isNil,_$ as isFunction,U_ as isEmpty,W$ as isConstructor,Z$ as createTestingModule,J$ as createTestApplication,c8 as createServiceTestContainer,L as createParamDecorator,O as createHttpMethodDecorator,b as createErrorResponse,g8 as createControllerTestApplication,B_ as addLeadingSlash,zW as View,MW as Variable,IW as Var,i as VERSION_NEUTRAL,oW as UsePipes,nW as UseMiddleware,iW as UseGuards,dW as UseFilters,gW as UseComponent,u as StaticServiceRegistry,H as StaticMetadataRepository,C as SnapshotMetadataRepository,vW as Service,m as RouteRegistry,bW as Response,wW as Res,PW as Request,SW as Req,KW as Query,ZW as Put,XW as Post,UW as Patch,NW as Param,AW as Page,YW as Options,p as NotFoundHandler,A as NoopLogger,kW as MvcModule,x as Module,Y as MetadataRegistry,o_ as Layout,EW as Header,M as HONEST_PIPELINE_HANDLER_KEY,I as HONEST_PIPELINE_CONTROLLER_KEY,s as HONEST_PIPELINE_BODY_CACHE_KEY,X$ as Get,d as FrameworkError,c as ErrorHandler,JW as Delete,RW as Ctx,Q$ as Controller,CW as Context,w as Container,g as ConsoleLogger,TW as Body,h as ApplicationContext,P as Application,BW as All};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context } from 'hono';
|
|
2
2
|
import type { VERSION_NEUTRAL } from '../constants';
|
|
3
|
-
import type { FilterType, GuardType,
|
|
3
|
+
import type { FilterType, GuardType, ILogger, MiddlewareType, PipeType, PluginEntry } from '../interfaces';
|
|
4
4
|
import type { DiContainer } from './di-container.interface';
|
|
5
5
|
/**
|
|
6
6
|
* Options for configuring the Honest application
|
|
@@ -27,9 +27,9 @@ export interface HonestOptions {
|
|
|
27
27
|
startup?: boolean;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
* Optional
|
|
30
|
+
* Optional logger for structured framework events.
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
logger?: ILogger;
|
|
33
33
|
/**
|
|
34
34
|
* Optional strict-mode checks for startup validation.
|
|
35
35
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from './application-context.interface';
|
|
2
2
|
export * from './controller-options.interface';
|
|
3
3
|
export * from './di-container.interface';
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './logger.interface';
|
|
5
5
|
export * from './error-response.interface';
|
|
6
6
|
export * from './filter.interface';
|
|
7
7
|
export * from './guard.interface';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level.
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
5
|
+
/**
|
|
6
|
+
* Log category used to filter or route events.
|
|
7
|
+
*/
|
|
8
|
+
export type LogCategory = 'startup' | 'routes' | 'plugins' | 'deprecations' | 'pipeline' | 'di' | 'errors';
|
|
9
|
+
/**
|
|
10
|
+
* Structured log event emitted by Honest runtime components.
|
|
11
|
+
*/
|
|
12
|
+
export interface LogEvent {
|
|
13
|
+
level: LogLevel;
|
|
14
|
+
category: LogCategory;
|
|
15
|
+
message: string;
|
|
16
|
+
details?: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Logger contract.
|
|
20
|
+
*/
|
|
21
|
+
export interface ILogger {
|
|
22
|
+
emit(event: LogEvent): void;
|
|
23
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import type { Application } from '../application';
|
|
3
3
|
import type { IApplicationContext } from './application-context.interface';
|
|
4
|
+
import type { ILogger } from './logger.interface';
|
|
4
5
|
import type { Constructor } from '../types';
|
|
5
6
|
/**
|
|
6
7
|
* Processor callback for plugin pre/post hooks.
|
|
@@ -8,21 +9,13 @@ import type { Constructor } from '../types';
|
|
|
8
9
|
*/
|
|
9
10
|
export type PluginProcessor = (app: Application, hono: Hono, ctx: IApplicationContext) => void | Promise<void>;
|
|
10
11
|
/**
|
|
11
|
-
* Optional metadata for plugin
|
|
12
|
+
* Optional metadata for plugin diagnostics.
|
|
12
13
|
*/
|
|
13
14
|
export interface PluginMeta {
|
|
14
15
|
/**
|
|
15
|
-
* Stable plugin name used for
|
|
16
|
+
* Stable plugin name used for diagnostics.
|
|
16
17
|
*/
|
|
17
18
|
name?: string;
|
|
18
|
-
/**
|
|
19
|
-
* Capabilities this plugin provides for subsequent plugins.
|
|
20
|
-
*/
|
|
21
|
-
provides?: string[];
|
|
22
|
-
/**
|
|
23
|
-
* Capabilities this plugin expects to be provided earlier in the pipeline.
|
|
24
|
-
*/
|
|
25
|
-
requires?: string[];
|
|
26
19
|
}
|
|
27
20
|
/**
|
|
28
21
|
* Object form of a plugin entry with optional pre/post processors.
|
|
@@ -31,18 +24,10 @@ export interface PluginMeta {
|
|
|
31
24
|
export interface PluginEntryObject {
|
|
32
25
|
plugin: IPlugin | Constructor<IPlugin>;
|
|
33
26
|
/**
|
|
34
|
-
* Optional stable plugin name
|
|
27
|
+
* Optional stable plugin name for diagnostics.
|
|
35
28
|
* Takes precedence over plugin.meta.name.
|
|
36
29
|
*/
|
|
37
30
|
name?: string;
|
|
38
|
-
/**
|
|
39
|
-
* Ensure this plugin runs before listed plugin names.
|
|
40
|
-
*/
|
|
41
|
-
before?: string[];
|
|
42
|
-
/**
|
|
43
|
-
* Ensure this plugin runs after listed plugin names.
|
|
44
|
-
*/
|
|
45
|
-
after?: string[];
|
|
46
31
|
preProcessors?: PluginProcessor[];
|
|
47
32
|
postProcessors?: PluginProcessor[];
|
|
48
33
|
}
|
|
@@ -53,23 +38,26 @@ export interface PluginEntryObject {
|
|
|
53
38
|
*/
|
|
54
39
|
export interface IPlugin {
|
|
55
40
|
/**
|
|
56
|
-
* Optional metadata for plugin
|
|
41
|
+
* Optional metadata for plugin diagnostics.
|
|
57
42
|
*/
|
|
58
43
|
meta?: PluginMeta;
|
|
59
44
|
/**
|
|
60
|
-
*
|
|
61
|
-
* Use this to
|
|
45
|
+
* Application logger, injected by the framework before lifecycle hooks run.
|
|
46
|
+
* Use this to emit structured log events from within plugin code.
|
|
47
|
+
*/
|
|
48
|
+
logger?: ILogger;
|
|
49
|
+
/**
|
|
50
|
+
* Hook that runs before module registration begins.
|
|
51
|
+
* Use this to set up plugin functionality that modules might depend on.
|
|
62
52
|
* @param app - The Honest application instance
|
|
63
53
|
* @param hono - The underlying Hono application instance
|
|
64
|
-
* @returns Void or a Promise that resolves to void
|
|
65
54
|
*/
|
|
66
55
|
beforeModulesRegistered?: (app: Application, hono: Hono) => void | Promise<void>;
|
|
67
56
|
/**
|
|
68
|
-
* Hook that runs after all modules have been registered
|
|
69
|
-
* Use this to perform cleanup or setup that requires all modules to be ready
|
|
57
|
+
* Hook that runs after all modules have been registered.
|
|
58
|
+
* Use this to perform cleanup or setup that requires all modules to be ready.
|
|
70
59
|
* @param app - The Honest application instance
|
|
71
60
|
* @param hono - The underlying Hono application instance
|
|
72
|
-
* @returns Void or a Promise that resolves to void
|
|
73
61
|
*/
|
|
74
62
|
afterModulesRegistered?: (app: Application, hono: Hono) => void | Promise<void>;
|
|
75
63
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono';
|
|
2
|
-
import type { ArgumentMetadata, DiContainer, FilterType, GuardType,
|
|
2
|
+
import type { ArgumentMetadata, DiContainer, FilterType, GuardType, ILogger, IMetadataRepository, IGuard, IPipe, MiddlewareType, PipeType } from '../interfaces';
|
|
3
3
|
import { type ComponentType, type ComponentTypeMap } from '../registries';
|
|
4
4
|
import type { Constructor } from '../types';
|
|
5
5
|
/**
|
|
@@ -13,9 +13,9 @@ import type { Constructor } from '../types';
|
|
|
13
13
|
export declare class ComponentManager {
|
|
14
14
|
private readonly container;
|
|
15
15
|
private readonly metadataRepository;
|
|
16
|
-
private readonly
|
|
16
|
+
private readonly logger;
|
|
17
17
|
private readonly globalComponents;
|
|
18
|
-
constructor(container: DiContainer, metadataRepository?: IMetadataRepository,
|
|
18
|
+
constructor(container: DiContainer, metadataRepository?: IMetadataRepository, logger?: ILogger);
|
|
19
19
|
/**
|
|
20
20
|
* Configures global components from application options.
|
|
21
21
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context } from 'hono';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ILogger, ParameterMetadata } from '../interfaces';
|
|
3
3
|
import type { IPipe } from '../interfaces';
|
|
4
4
|
import { ComponentManager } from './component.manager';
|
|
5
5
|
import { HandlerInvoker } from './handler.invoker';
|
|
@@ -21,8 +21,8 @@ export declare class PipelineExecutor {
|
|
|
21
21
|
private readonly componentManager;
|
|
22
22
|
private readonly parameterResolver;
|
|
23
23
|
private readonly handlerInvoker;
|
|
24
|
-
private readonly
|
|
24
|
+
private readonly logger;
|
|
25
25
|
private readonly debugPipeline;
|
|
26
|
-
constructor(componentManager: ComponentManager, parameterResolver: ParameterResolver, handlerInvoker: HandlerInvoker,
|
|
26
|
+
constructor(componentManager: ComponentManager, parameterResolver: ParameterResolver, handlerInvoker: HandlerInvoker, logger?: ILogger, debugPipeline?: boolean);
|
|
27
27
|
execute(input: PipelineExecutionInput): Promise<unknown>;
|
|
28
28
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import { VERSION_NEUTRAL } from '../constants';
|
|
3
|
-
import type { DiContainer,
|
|
3
|
+
import type { DiContainer, ILogger, IMetadataRepository } from '../interfaces';
|
|
4
4
|
import { ComponentManager } from './component.manager';
|
|
5
5
|
import { RouteRegistry } from '../registries/route.registry';
|
|
6
6
|
import type { Constructor } from '../types';
|
|
@@ -18,10 +18,10 @@ export declare class RouteManager {
|
|
|
18
18
|
private parameterResolver;
|
|
19
19
|
private pipelineExecutor;
|
|
20
20
|
private metadataRepository;
|
|
21
|
-
private
|
|
21
|
+
private logger;
|
|
22
22
|
private globalPrefix?;
|
|
23
23
|
private globalVersion?;
|
|
24
|
-
constructor(hono: Hono, container: DiContainer, routeRegistry: RouteRegistry, componentManager: ComponentManager, metadataRepository?: IMetadataRepository,
|
|
24
|
+
constructor(hono: Hono, container: DiContainer, routeRegistry: RouteRegistry, componentManager: ComponentManager, metadataRepository?: IMetadataRepository, logger?: ILogger, options?: {
|
|
25
25
|
prefix?: string;
|
|
26
26
|
version?: number | typeof VERSION_NEUTRAL | number[];
|
|
27
27
|
debugPipeline?: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import type { Application } from '../application';
|
|
3
|
-
import type { DiContainer, HonestOptions,
|
|
3
|
+
import type { DiContainer, HonestOptions, ILogger, ModuleOptions } from '../interfaces';
|
|
4
4
|
import type { Constructor } from '../types';
|
|
5
5
|
/**
|
|
6
6
|
* Options for creating a lightweight test module.
|
|
@@ -76,9 +76,9 @@ export interface CreateServiceTestContainerOptions {
|
|
|
76
76
|
*/
|
|
77
77
|
preload?: Constructor[];
|
|
78
78
|
/**
|
|
79
|
-
* Optional
|
|
79
|
+
* Optional logger used when debugDi is enabled.
|
|
80
80
|
*/
|
|
81
|
-
|
|
81
|
+
logger?: ILogger;
|
|
82
82
|
/**
|
|
83
83
|
* Enable DI diagnostics while resolving services.
|
|
84
84
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { DiagnosticEvent, IDiagnosticsEmitter } from '../interfaces';
|
|
2
|
-
/**
|
|
3
|
-
* Default diagnostics emitter that writes structured events to console.
|
|
4
|
-
*/
|
|
5
|
-
export declare class ConsoleDiagnosticsEmitter implements IDiagnosticsEmitter {
|
|
6
|
-
emit(event: DiagnosticEvent): void;
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { DiagnosticEvent, IDiagnosticsEmitter } from '../interfaces';
|
|
2
|
-
/**
|
|
3
|
-
* Diagnostics emitter implementation that intentionally does nothing.
|
|
4
|
-
*/
|
|
5
|
-
export declare class NoopDiagnosticsEmitter implements IDiagnosticsEmitter {
|
|
6
|
-
emit(_event: DiagnosticEvent): void;
|
|
7
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Diagnostic log level.
|
|
3
|
-
*/
|
|
4
|
-
export type DiagnosticLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
5
|
-
/**
|
|
6
|
-
* Diagnostic category used to filter or route events.
|
|
7
|
-
*/
|
|
8
|
-
export type DiagnosticCategory = 'startup' | 'routes' | 'plugins' | 'deprecations' | 'pipeline' | 'di' | 'errors';
|
|
9
|
-
/**
|
|
10
|
-
* Structured diagnostic event emitted by Honest runtime components.
|
|
11
|
-
*/
|
|
12
|
-
export interface DiagnosticEvent {
|
|
13
|
-
level: DiagnosticLevel;
|
|
14
|
-
category: DiagnosticCategory;
|
|
15
|
-
message: string;
|
|
16
|
-
details?: Record<string, unknown>;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Diagnostics emitter contract.
|
|
20
|
-
*/
|
|
21
|
-
export interface IDiagnosticsEmitter {
|
|
22
|
-
emit(event: DiagnosticEvent): void;
|
|
23
|
-
}
|