@velajs/vela 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/cache/cache.module.d.ts +4 -1
  2. package/dist/cache/cache.module.js +51 -9
  3. package/dist/config/config.module.d.ts +4 -1
  4. package/dist/config/config.module.js +40 -3
  5. package/dist/config/config.types.d.ts +1 -0
  6. package/dist/constants.d.ts +8 -2
  7. package/dist/constants.js +6 -0
  8. package/dist/container/container.d.ts +2 -0
  9. package/dist/container/container.js +51 -16
  10. package/dist/container/decorators.d.ts +3 -1
  11. package/dist/container/decorators.js +27 -6
  12. package/dist/container/index.d.ts +4 -2
  13. package/dist/container/index.js +4 -2
  14. package/dist/container/mixin.d.ts +24 -0
  15. package/dist/container/mixin.js +26 -0
  16. package/dist/container/module-ref.d.ts +21 -0
  17. package/dist/container/module-ref.js +48 -0
  18. package/dist/container/types.d.ts +9 -3
  19. package/dist/container/types.js +9 -0
  20. package/dist/cors/cors.module.js +2 -2
  21. package/dist/errors/http-exception.d.ts +20 -20
  22. package/dist/errors/http-exception.js +47 -41
  23. package/dist/factory.js +11 -2
  24. package/dist/fetch/fetch.module.d.ts +6 -0
  25. package/dist/fetch/fetch.module.js +77 -0
  26. package/dist/fetch/fetch.service.d.ts +24 -0
  27. package/dist/fetch/fetch.service.js +145 -0
  28. package/dist/fetch/fetch.types.d.ts +24 -0
  29. package/dist/fetch/fetch.types.js +1 -0
  30. package/dist/fetch/index.d.ts +3 -0
  31. package/dist/fetch/index.js +2 -0
  32. package/dist/health/health.service.js +2 -2
  33. package/dist/http/decorators.d.ts +65 -0
  34. package/dist/http/decorators.js +91 -2
  35. package/dist/http/index.d.ts +3 -1
  36. package/dist/http/index.js +2 -1
  37. package/dist/http/middleware-consumer.d.ts +36 -0
  38. package/dist/http/middleware-consumer.js +71 -0
  39. package/dist/http/route.manager.d.ts +4 -0
  40. package/dist/http/route.manager.js +91 -6
  41. package/dist/http/types.d.ts +1 -0
  42. package/dist/index.d.ts +11 -6
  43. package/dist/index.js +7 -4
  44. package/dist/metadata.d.ts +1 -1
  45. package/dist/module/decorators.d.ts +1 -0
  46. package/dist/module/decorators.js +24 -8
  47. package/dist/module/index.d.ts +2 -2
  48. package/dist/module/index.js +1 -1
  49. package/dist/module/module-loader.d.ts +5 -1
  50. package/dist/module/module-loader.js +54 -10
  51. package/dist/module/types.d.ts +13 -3
  52. package/dist/pipeline/index.d.ts +3 -2
  53. package/dist/pipeline/index.js +1 -1
  54. package/dist/pipeline/pipes.d.ts +22 -0
  55. package/dist/pipeline/pipes.js +50 -0
  56. package/dist/pipeline/tokens.d.ts +1 -1
  57. package/dist/pipeline/tokens.js +1 -1
  58. package/dist/pipeline/types.d.ts +16 -0
  59. package/dist/registry/metadata.registry.d.ts +7 -6
  60. package/dist/registry/metadata.registry.js +13 -0
  61. package/dist/registry/types.d.ts +1 -0
  62. package/dist/schedule/schedule.module.d.ts +4 -1
  63. package/dist/schedule/schedule.module.js +39 -7
  64. package/dist/testing/testing.builder.js +5 -5
  65. package/dist/throttler/throttler.module.d.ts +2 -1
  66. package/dist/throttler/throttler.module.js +47 -9
  67. package/dist/validation/validation.pipe.js +1 -1
  68. package/package.json +1 -1
@@ -38,12 +38,60 @@ export declare const Patch: (path?: string) => MethodDecorator;
38
38
  export declare const Delete: (path?: string) => MethodDecorator;
39
39
  export declare const Options: (path?: string) => MethodDecorator;
40
40
  export declare const Head: (path?: string) => MethodDecorator;
41
+ export declare const All: (path?: string) => MethodDecorator;
41
42
  export declare const Sse: (path?: string) => MethodDecorator;
42
43
  export declare const Param: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
43
44
  export declare const Query: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
44
45
  export declare const Body: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
45
46
  export declare const Headers: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
46
47
  export declare const Req: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
48
+ /**
49
+ * Injects the Hono `Context` as the response handle.
50
+ * In Hono, request and response state are unified in the `Context` object,
51
+ * so `@Res()` and `@Req()` both return it.
52
+ *
53
+ * Use `c.header()`, `c.setCookie()`, `c.redirect()`, etc. for response control.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * @Get('/set-cookie')
58
+ * handle(@Res() c: Context) {
59
+ * c.setCookie('session', 'abc123', { httpOnly: true });
60
+ * return { ok: true };
61
+ * }
62
+ * ```
63
+ */
64
+ export declare const Res: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
65
+ export declare const Ip: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
66
+ export declare const Cookie: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
67
+ /**
68
+ * Injects all cookies as a `Record<string, string>`, or a single cookie value by name.
69
+ *
70
+ * - `@Cookie()` — all cookies as an object
71
+ * - `@Cookie('token')` — the value of the `token` cookie
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * @Get('/me')
76
+ * handle(@Cookie('session') session: string) { ... }
77
+ * ```
78
+ */
79
+ export declare const Cookies: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
80
+ /**
81
+ * Injects the raw request body as a `Uint8Array`.
82
+ * Useful for webhook HMAC verification (Stripe, GitHub, etc.) where you
83
+ * need the raw bytes before any JSON parsing.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * @Post('/webhook')
88
+ * async handle(@RawBody() body: Uint8Array) {
89
+ * const sig = new TextDecoder().decode(body);
90
+ * // verify HMAC...
91
+ * }
92
+ * ```
93
+ */
94
+ export declare function RawBody(): ParameterDecorator;
47
95
  /**
48
96
  * Factory for creating custom parameter decorators.
49
97
  *
@@ -120,4 +168,21 @@ export declare function getRedirect(target: Constructor, method: string | symbol
120
168
  url: string;
121
169
  statusCode: number;
122
170
  } | undefined;
171
+ /**
172
+ * Composes multiple decorators into one. Applies them in order (top to bottom),
173
+ * matching how stacked decorators behave when written separately.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * const Auth = (...roles: string[]) => applyDecorators(
178
+ * UseGuards(JwtGuard, RolesGuard),
179
+ * SetMetadata('roles', roles),
180
+ * );
181
+ *
182
+ * @Auth('admin')
183
+ * @Get('/admin')
184
+ * handle() { ... }
185
+ * ```
186
+ */
187
+ export declare function applyDecorators(...decorators: Array<ClassDecorator | MethodDecorator | PropertyDecorator | ParameterDecorator>): ClassDecorator & MethodDecorator & PropertyDecorator;
123
188
  export declare function isController(target: Constructor): boolean;
@@ -22,7 +22,7 @@ function normalizePath(path) {
22
22
  if (typeof prefixOrOptions === 'string') {
23
23
  prefix = prefixOrOptions;
24
24
  } else if (prefixOrOptions) {
25
- prefix = prefixOrOptions.prefix ?? '';
25
+ prefix = prefixOrOptions.path ?? prefixOrOptions.prefix ?? '';
26
26
  version = prefixOrOptions.version;
27
27
  } else {
28
28
  prefix = '';
@@ -96,6 +96,7 @@ export const Patch = createMethodDecorator(HttpMethod.PATCH);
96
96
  export const Delete = createMethodDecorator(HttpMethod.DELETE);
97
97
  export const Options = createMethodDecorator(HttpMethod.OPTIONS);
98
98
  export const Head = createMethodDecorator(HttpMethod.HEAD);
99
+ export const All = createMethodDecorator(HttpMethod.ALL);
99
100
  export const Sse = createMethodDecorator(HttpMethod.GET);
100
101
  // Parameter decorators
101
102
  const CUSTOM_PARAM_TYPE = 'custom';
@@ -136,6 +137,60 @@ export const Query = createBuiltinParamDecorator(ParamType.QUERY);
136
137
  export const Body = createBuiltinParamDecorator(ParamType.BODY);
137
138
  export const Headers = createBuiltinParamDecorator(ParamType.HEADERS);
138
139
  export const Req = createBuiltinParamDecorator(ParamType.REQUEST);
140
+ /**
141
+ * Injects the Hono `Context` as the response handle.
142
+ * In Hono, request and response state are unified in the `Context` object,
143
+ * so `@Res()` and `@Req()` both return it.
144
+ *
145
+ * Use `c.header()`, `c.setCookie()`, `c.redirect()`, etc. for response control.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * @Get('/set-cookie')
150
+ * handle(@Res() c: Context) {
151
+ * c.setCookie('session', 'abc123', { httpOnly: true });
152
+ * return { ok: true };
153
+ * }
154
+ * ```
155
+ */ export const Res = createBuiltinParamDecorator(ParamType.RESPONSE);
156
+ export const Ip = createBuiltinParamDecorator(ParamType.IP);
157
+ export const Cookie = createBuiltinParamDecorator(ParamType.COOKIE);
158
+ /**
159
+ * Injects all cookies as a `Record<string, string>`, or a single cookie value by name.
160
+ *
161
+ * - `@Cookie()` — all cookies as an object
162
+ * - `@Cookie('token')` — the value of the `token` cookie
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * @Get('/me')
167
+ * handle(@Cookie('session') session: string) { ... }
168
+ * ```
169
+ */ export const Cookies = Cookie;
170
+ /**
171
+ * Injects the raw request body as a `Uint8Array`.
172
+ * Useful for webhook HMAC verification (Stripe, GitHub, etc.) where you
173
+ * need the raw bytes before any JSON parsing.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * @Post('/webhook')
178
+ * async handle(@RawBody() body: Uint8Array) {
179
+ * const sig = new TextDecoder().decode(body);
180
+ * // verify HMAC...
181
+ * }
182
+ * ```
183
+ */ export function RawBody() {
184
+ return (target, propertyKey, parameterIndex)=>{
185
+ if (propertyKey === undefined) {
186
+ throw new Error('Parameter decorators can only be used on method parameters');
187
+ }
188
+ MetadataRegistry.addParameter(target.constructor, propertyKey, {
189
+ index: parameterIndex,
190
+ type: ParamType.RAW_BODY
191
+ });
192
+ };
193
+ }
139
194
  /**
140
195
  * Factory for creating custom parameter decorators.
141
196
  *
@@ -175,10 +230,15 @@ export const Req = createBuiltinParamDecorator(ParamType.REQUEST);
175
230
  factory: (_unused, ctx)=>{
176
231
  const honoCtx = ctx;
177
232
  const execCtx = {
233
+ getType: ()=>'http',
178
234
  getClass: ()=>target.constructor,
179
235
  getHandler: ()=>propertyKey,
180
236
  getContext: ()=>honoCtx,
181
- getRequest: ()=>honoCtx.req.raw
237
+ getRequest: ()=>honoCtx.req.raw,
238
+ switchToHttp: ()=>({
239
+ getRequest: ()=>honoCtx.req.raw,
240
+ getResponse: ()=>honoCtx
241
+ })
182
242
  };
183
243
  return factory(data, execCtx);
184
244
  },
@@ -271,6 +331,35 @@ export function getRedirect(target, method) {
271
331
  if (meta?.redirect) return meta.redirect;
272
332
  return getMetadata(METADATA_KEYS.REDIRECT, target, method);
273
333
  }
334
+ /**
335
+ * Composes multiple decorators into one. Applies them in order (top to bottom),
336
+ * matching how stacked decorators behave when written separately.
337
+ *
338
+ * @example
339
+ * ```ts
340
+ * const Auth = (...roles: string[]) => applyDecorators(
341
+ * UseGuards(JwtGuard, RolesGuard),
342
+ * SetMetadata('roles', roles),
343
+ * );
344
+ *
345
+ * @Auth('admin')
346
+ * @Get('/admin')
347
+ * handle() { ... }
348
+ * ```
349
+ */ export function applyDecorators(...decorators) {
350
+ const composed = (target, propertyKey, descriptor)=>{
351
+ for (const decorator of decorators){
352
+ if (propertyKey === undefined && typeof descriptor !== 'number') {
353
+ decorator(target);
354
+ } else if (typeof descriptor === 'number') {
355
+ decorator(target, propertyKey, descriptor);
356
+ } else {
357
+ decorator(target, propertyKey, descriptor);
358
+ }
359
+ }
360
+ };
361
+ return composed;
362
+ }
274
363
  // Helpers
275
364
  export function isController(target) {
276
365
  return MetadataRegistry.getControllerPath(target) !== '' || MetadataRegistry.getRoutes(target).length > 0;
@@ -1,3 +1,5 @@
1
1
  export { RouteManager } from './route.manager';
2
- export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, Sse, Param, Query, Body, Headers, Req, HttpCode, Header, Redirect, createParamDecorator, isController, } from './decorators';
2
+ export { MiddlewareBuilder, RequestMethod } from './middleware-consumer';
3
+ export type { MiddlewareConsumer, MiddlewareConfigProxy, RouteInfo, NestModule, MiddlewareRouteDefinition } from './middleware-consumer';
4
+ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, applyDecorators, isController, } from './decorators';
3
5
  export type { RouteMetadata, ControllerMetadata, ControllerOptions, ParamMetadata, ControllerRegistration, } from './types';
@@ -1,2 +1,3 @@
1
1
  export { RouteManager } from "./route.manager.js";
2
- export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, Sse, Param, Query, Body, Headers, Req, HttpCode, Header, Redirect, createParamDecorator, isController } from "./decorators.js";
2
+ export { MiddlewareBuilder, RequestMethod } from "./middleware-consumer.js";
3
+ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, applyDecorators, isController } from "./decorators.js";
@@ -0,0 +1,36 @@
1
+ import type { NestMiddleware } from '../pipeline/types';
2
+ import type { Type } from '../registry/types';
3
+ export declare enum RequestMethod {
4
+ GET = "GET",
5
+ POST = "POST",
6
+ PUT = "PUT",
7
+ DELETE = "DELETE",
8
+ PATCH = "PATCH",
9
+ OPTIONS = "OPTIONS",
10
+ HEAD = "HEAD",
11
+ ALL = "ALL"
12
+ }
13
+ export interface RouteInfo {
14
+ path: string;
15
+ method?: RequestMethod;
16
+ }
17
+ export interface MiddlewareRouteDefinition {
18
+ middleware: Array<Type<NestMiddleware> | NestMiddleware>;
19
+ routes: RouteInfo[];
20
+ excludes: RouteInfo[];
21
+ }
22
+ export interface MiddlewareConfigProxy {
23
+ exclude(...routes: Array<string | RouteInfo>): MiddlewareConfigProxy;
24
+ forRoutes(...routes: Array<string | Function | RouteInfo>): MiddlewareConsumer;
25
+ }
26
+ export interface MiddlewareConsumer {
27
+ apply(...middleware: Array<Type<NestMiddleware> | NestMiddleware>): MiddlewareConfigProxy;
28
+ }
29
+ export interface NestModule {
30
+ configure(consumer: MiddlewareConsumer): void;
31
+ }
32
+ export declare class MiddlewareBuilder implements MiddlewareConsumer {
33
+ private definitions;
34
+ apply(...middleware: Array<Type<NestMiddleware> | NestMiddleware>): MiddlewareConfigProxy;
35
+ getDefinitions(): MiddlewareRouteDefinition[];
36
+ }
@@ -0,0 +1,71 @@
1
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
2
+ export var RequestMethod = /*#__PURE__*/ function(RequestMethod) {
3
+ RequestMethod["GET"] = "GET";
4
+ RequestMethod["POST"] = "POST";
5
+ RequestMethod["PUT"] = "PUT";
6
+ RequestMethod["DELETE"] = "DELETE";
7
+ RequestMethod["PATCH"] = "PATCH";
8
+ RequestMethod["OPTIONS"] = "OPTIONS";
9
+ RequestMethod["HEAD"] = "HEAD";
10
+ RequestMethod["ALL"] = "ALL";
11
+ return RequestMethod;
12
+ }({});
13
+ export class MiddlewareBuilder {
14
+ definitions = [];
15
+ apply(...middleware) {
16
+ const currentMiddleware = [
17
+ ...middleware
18
+ ];
19
+ let currentExcludes = [];
20
+ const proxy = {
21
+ exclude: (...routes)=>{
22
+ currentExcludes = routes.map(normalizeRouteArg);
23
+ return proxy;
24
+ },
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
26
+ forRoutes: (...routes)=>{
27
+ this.definitions.push({
28
+ middleware: currentMiddleware,
29
+ routes: routes.flatMap(resolveRouteArg),
30
+ excludes: [
31
+ ...currentExcludes
32
+ ]
33
+ });
34
+ currentExcludes = [];
35
+ return this;
36
+ }
37
+ };
38
+ return proxy;
39
+ }
40
+ getDefinitions() {
41
+ return [
42
+ ...this.definitions
43
+ ];
44
+ }
45
+ }
46
+ function normalizeRouteArg(route) {
47
+ return typeof route === 'string' ? {
48
+ path: route
49
+ } : route;
50
+ }
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
52
+ function resolveRouteArg(route) {
53
+ if (typeof route === 'string') {
54
+ return [
55
+ {
56
+ path: route
57
+ }
58
+ ];
59
+ }
60
+ if (typeof route === 'function') {
61
+ const prefix = MetadataRegistry.getControllerPath(route);
62
+ return [
63
+ {
64
+ path: prefix || '/'
65
+ }
66
+ ];
67
+ }
68
+ return [
69
+ route
70
+ ];
71
+ }
@@ -1,6 +1,7 @@
1
1
  import { Hono } from 'hono';
2
2
  import type { Container } from '../container/container';
3
3
  import type { Token, Type } from '../container/types';
4
+ import type { MiddlewareRouteDefinition } from './middleware-consumer';
4
5
  import type { CanActivate, ExceptionFilter, NestInterceptor, NestMiddleware, PipeTransform } from '../pipeline/types';
5
6
  import type { FilterType, GuardType, InterceptorType, MiddlewareType, PipeType } from '../registry/types';
6
7
  import type { ControllerRegistration } from './types';
@@ -13,7 +14,9 @@ export declare class RouteManager {
13
14
  private globalInterceptors;
14
15
  private globalFilters;
15
16
  private globalPrefix;
17
+ private consumerMiddlewareDefinitions;
16
18
  constructor(container: Container);
19
+ registerConsumerMiddleware(definitions: MiddlewareRouteDefinition[]): this;
17
20
  setGlobalPrefix(prefix: string): this;
18
21
  useGlobalMiddleware(...middleware: MiddlewareType[]): this;
19
22
  useGlobalMiddlewareTokens(...middlewareTokens: Array<Token<NestMiddleware>>): this;
@@ -38,5 +41,6 @@ export declare class RouteManager {
38
41
  private registerRoute;
39
42
  private buildVersionedPaths;
40
43
  private joinPaths;
44
+ private matchesConsumerPath;
41
45
  getControllers(): ControllerRegistration[];
42
46
  }
@@ -1,6 +1,7 @@
1
1
  import { Hono } from "hono";
2
2
  import { HttpMethod, ParamType } from "../constants.js";
3
3
  import { getMetadata } from "../metadata.js";
4
+ import { RequestMethod } from "./middleware-consumer.js";
4
5
  import { ForbiddenException, HttpException } from "../errors/http-exception.js";
5
6
  import { ComponentManager } from "../pipeline/component.manager.js";
6
7
  import { shouldFilterCatch } from "../pipeline/decorators.js";
@@ -27,9 +28,14 @@ export class RouteManager {
27
28
  globalInterceptors = [];
28
29
  globalFilters = [];
29
30
  globalPrefix = '';
31
+ consumerMiddlewareDefinitions = [];
30
32
  constructor(container){
31
33
  this.container = container;
32
34
  }
35
+ registerConsumerMiddleware(definitions) {
36
+ this.consumerMiddlewareDefinitions.push(...definitions);
37
+ return this;
38
+ }
33
39
  setGlobalPrefix(prefix) {
34
40
  this.globalPrefix = prefix && !prefix.startsWith('/') ? `/${prefix}` : prefix;
35
41
  return this;
@@ -125,6 +131,37 @@ export class RouteManager {
125
131
  return resolved.use(c, next);
126
132
  });
127
133
  }
134
+ // Register MiddlewareConsumer-configured middleware
135
+ for (const def of this.consumerMiddlewareDefinitions){
136
+ app.use('*', (c, next)=>{
137
+ const reqPath = c.req.path;
138
+ const reqMethod = c.req.method;
139
+ const matches = def.routes.some((route)=>{
140
+ if (!this.matchesConsumerPath(reqPath, route.path)) return false;
141
+ if (route.method && route.method !== RequestMethod.ALL) {
142
+ if (reqMethod !== route.method) return false;
143
+ }
144
+ return true;
145
+ });
146
+ if (!matches) return next();
147
+ const excluded = def.excludes.some((exclude)=>{
148
+ if (!this.matchesConsumerPath(reqPath, exclude.path)) return false;
149
+ if (exclude.method && exclude.method !== RequestMethod.ALL) {
150
+ if (reqMethod !== exclude.method) return false;
151
+ }
152
+ return true;
153
+ });
154
+ if (excluded) return next();
155
+ const requestContainer = this.getRequestContainer(c);
156
+ const runChain = (index)=>{
157
+ if (index >= def.middleware.length) return next();
158
+ const instance = this.instantiate(def.middleware[index], requestContainer);
159
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
+ return instance.use(c, ()=>runChain(index + 1)).then(()=>{});
161
+ };
162
+ return runChain(0);
163
+ });
164
+ }
128
165
  // First pass: register all custom routes (must come before CRUD /:id routes)
129
166
  for (const { controller, metadata, routes } of this.controllers){
130
167
  if (routes.length > 0) {
@@ -171,10 +208,15 @@ export class RouteManager {
171
208
  }
172
209
  createExecutionContext(c, controller, route) {
173
210
  return {
211
+ getType: ()=>'http',
174
212
  getClass: ()=>controller,
175
213
  getHandler: ()=>route.handlerName,
176
214
  getContext: ()=>c,
177
- getRequest: ()=>c.req.raw
215
+ getRequest: ()=>c.req.raw,
216
+ switchToHttp: ()=>({
217
+ getRequest: ()=>c.req.raw,
218
+ getResponse: ()=>c
219
+ })
178
220
  };
179
221
  }
180
222
  createHandler(route, controller, allParamMetadata) {
@@ -310,10 +352,17 @@ export class RouteManager {
310
352
  case ParamType.QUERY:
311
353
  return param.name ? c.req.query(param.name) : c.req.query();
312
354
  case ParamType.BODY:
313
- try {
314
- return await c.req.json();
315
- } catch {
316
- return undefined;
355
+ {
356
+ let body;
357
+ try {
358
+ body = await c.req.json();
359
+ } catch {
360
+ return undefined;
361
+ }
362
+ if (param.name && body !== null && typeof body === 'object') {
363
+ return body[param.name];
364
+ }
365
+ return body;
317
366
  }
318
367
  case ParamType.HEADERS:
319
368
  if (param.name) {
@@ -326,6 +375,28 @@ export class RouteManager {
326
375
  return headers;
327
376
  case ParamType.REQUEST:
328
377
  return c;
378
+ case ParamType.RESPONSE:
379
+ return c;
380
+ case ParamType.IP:
381
+ return c.req.raw.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? c.req.raw.headers.get('x-real-ip') ?? null;
382
+ case ParamType.COOKIE:
383
+ {
384
+ const cookieHeader = c.req.raw.headers.get('cookie') ?? '';
385
+ const cookies = {};
386
+ for (const pair of cookieHeader.split(';')){
387
+ const eqIdx = pair.indexOf('=');
388
+ if (eqIdx === -1) continue;
389
+ const name = pair.slice(0, eqIdx).trim();
390
+ const value = pair.slice(eqIdx + 1).trim();
391
+ if (name) cookies[name] = decodeURIComponent(value);
392
+ }
393
+ return param.name ? cookies[param.name] ?? undefined : cookies;
394
+ }
395
+ case ParamType.RAW_BODY:
396
+ {
397
+ const buffer = await c.req.arrayBuffer();
398
+ return new Uint8Array(buffer);
399
+ }
329
400
  default:
330
401
  // Custom param decorator — use factory if available
331
402
  if (param.factory) {
@@ -368,7 +439,11 @@ export class RouteManager {
368
439
  app.options(normalizedPath, handler);
369
440
  break;
370
441
  case HttpMethod.HEAD:
371
- app.on('HEAD', normalizedPath, handler);
442
+ // Hono converts HEAD to GET internally, so register as GET
443
+ app.get(normalizedPath, handler);
444
+ break;
445
+ case HttpMethod.ALL:
446
+ app.all(normalizedPath, handler);
372
447
  break;
373
448
  default:
374
449
  app.on(method.toUpperCase(), normalizedPath, handler);
@@ -393,6 +468,16 @@ export class RouteManager {
393
468
  const cleanPath = path && !path.startsWith('/') ? `/${path}` : path;
394
469
  return `${cleanPrefix}${cleanPath}` || '/';
395
470
  }
471
+ matchesConsumerPath(reqPath, routePath) {
472
+ if (routePath === '*') return true;
473
+ const normalized = routePath.startsWith('/') ? routePath : `/${routePath}`;
474
+ if (reqPath === normalized) return true;
475
+ if (reqPath.startsWith(`${normalized}/`)) return true;
476
+ if (normalized.endsWith('*')) {
477
+ return reqPath.startsWith(normalized.slice(0, -1));
478
+ }
479
+ return false;
480
+ }
396
481
  getControllers() {
397
482
  return [
398
483
  ...this.controllers
@@ -9,6 +9,7 @@ export interface RouteMetadata {
9
9
  }
10
10
  export interface ControllerOptions {
11
11
  prefix?: string;
12
+ path?: string;
12
13
  version?: number | number[];
13
14
  }
14
15
  export interface ControllerMetadata {
package/dist/index.d.ts CHANGED
@@ -2,14 +2,16 @@ import './metadata';
2
2
  export { defineMetadata, getMetadata } from './metadata';
3
3
  export { VelaFactory } from './factory';
4
4
  export { VelaApplication } from './application';
5
- export { Container, Injectable, Inject, InjectionToken } from './container/index';
5
+ export { Container, Injectable, Inject, Optional, InjectionToken, ForwardRef, forwardRef, ModuleRef, mixin } from './container/index';
6
6
  export type { Type, Token, InjectableOptions, ProviderOptions, } from './container/index';
7
7
  export { METADATA_KEYS, HttpMethod, ParamType, Scope } from './constants';
8
- export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, Sse, Param, Query, Body, Headers, Req, HttpCode, Header, Redirect, createParamDecorator, } from './http/index';
8
+ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, applyDecorators, } from './http/index';
9
9
  export { Logger, LogLevel } from './services/index';
10
10
  export type { LoggerService } from './services/index';
11
11
  export { ConfigModule, ConfigService, CONFIG_OPTIONS } from './config/index';
12
12
  export type { ConfigModuleOptions } from './config/index';
13
+ export { HttpModule, HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } from './fetch/index';
14
+ export type { HttpModuleOptions, HttpResponse, HttpRequestConfig } from './fetch/index';
13
15
  export { CorsModule, CORS_OPTIONS } from './cors/index';
14
16
  export type { CorsOptions } from './cors/index';
15
17
  export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, CacheKey, CacheTTL, CACHE_MANAGER, CACHE_MODULE_OPTIONS, CACHE_KEY_METADATA, CACHE_TTL_METADATA, } from './cache/index';
@@ -22,12 +24,15 @@ export { HealthModule, HealthCheckService, HealthIndicatorService, HttpHealthInd
22
24
  export type { HealthCheckResult, HealthCheckStatus, HealthIndicatorResult, HealthIndicatorFunction, ResponseCheckCallback, HttpPingOptions, } from './health/index';
23
25
  export { ThrottlerModule, ThrottlerGuard, ThrottlerStorage, Throttle, SkipThrottle, THROTTLER_OPTIONS, THROTTLER_STORAGE, THROTTLE_METADATA, SKIP_THROTTLE_METADATA, } from './throttler/index';
24
26
  export type { ThrottlerModuleOptions, ThrottleConfig, ThrottlerStore, ThrottlerStorageRecord, RateLimitInfo, } from './throttler/index';
25
- export { Module } from './module/index';
26
- export type { ModuleOptions, DynamicModule } from './module/index';
27
+ export { Global, Module } from './module/index';
28
+ export type { ModuleOptions, DynamicModule, AsyncModuleOptions, ModuleImport } from './module/index';
29
+ export { RequestMethod } from './http/index';
30
+ export type { MiddlewareConsumer, NestModule, RouteInfo } from './http/index';
27
31
  export { UseMiddleware, UseGuards, UsePipes, UseInterceptors, UseFilters, Catch, SetMetadata, Reflector, APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE, } from './pipeline/index';
28
- export type { ExecutionContext, CanActivate, CallHandler, NestInterceptor, NestMiddleware, PipeTransform, ExceptionFilter, ArgumentMetadata, ReflectableDecorator, CreateDecoratorOptions, } from './pipeline/index';
32
+ export type { HttpArgumentsHost, ExecutionContext, CanActivate, CallHandler, NestInterceptor, NestMiddleware, PipeTransform, ExceptionFilter, ArgumentMetadata, ReflectableDecorator, CreateDecoratorOptions, } from './pipeline/index';
29
33
  export type { Constructor, MiddlewareType, GuardType, PipeType, InterceptorType, FilterType, } from './registry/index';
30
- export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe, } from './pipeline/index';
34
+ export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, ParseUUIDPipe, ParseEnumPipe, ParseArrayPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe, } from './pipeline/index';
35
+ export type { ParseUUIDPipeOptions, ParseArrayPipeOptions } from './pipeline/index';
31
36
  export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, MethodNotAllowedException, NotAcceptableException, RequestTimeoutException, ConflictException, GoneException, PayloadTooLargeException, UnsupportedMediaTypeException, UnprocessableEntityException, TooManyRequestsException, InternalServerErrorException, NotImplementedException, BadGatewayException, ServiceUnavailableException, GatewayTimeoutException, } from './errors/index';
32
37
  export type { OnModuleInit, OnApplicationBootstrap, OnModuleDestroy, OnApplicationShutdown, BeforeApplicationShutdown, } from './lifecycle/index';
33
38
  export { MetadataRegistry } from './registry/index';
package/dist/index.js CHANGED
@@ -4,15 +4,17 @@ export { defineMetadata, getMetadata } from "./metadata.js";
4
4
  export { VelaFactory } from "./factory.js";
5
5
  export { VelaApplication } from "./application.js";
6
6
  // DI Container
7
- export { Container, Injectable, Inject, InjectionToken } from "./container/index.js";
7
+ export { Container, Injectable, Inject, Optional, InjectionToken, ForwardRef, forwardRef, ModuleRef, mixin } from "./container/index.js";
8
8
  // Constants
9
9
  export { METADATA_KEYS, HttpMethod, ParamType, Scope } from "./constants.js";
10
10
  // HTTP Decorators
11
- export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, Sse, Param, Query, Body, Headers, Req, HttpCode, Header, Redirect, createParamDecorator } from "./http/index.js";
11
+ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, applyDecorators } from "./http/index.js";
12
12
  // Services
13
13
  export { Logger, LogLevel } from "./services/index.js";
14
14
  // Config
15
15
  export { ConfigModule, ConfigService, CONFIG_OPTIONS } from "./config/index.js";
16
+ // HTTP Client
17
+ export { HttpModule, HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } from "./fetch/index.js";
16
18
  // CORS
17
19
  export { CorsModule, CORS_OPTIONS } from "./cors/index.js";
18
20
  // Cache
@@ -26,11 +28,12 @@ export { HealthModule, HealthCheckService, HealthIndicatorService, HttpHealthInd
26
28
  // Throttler
27
29
  export { ThrottlerModule, ThrottlerGuard, ThrottlerStorage, Throttle, SkipThrottle, THROTTLER_OPTIONS, THROTTLER_STORAGE, THROTTLE_METADATA, SKIP_THROTTLE_METADATA } from "./throttler/index.js";
28
30
  // Module
29
- export { Module } from "./module/index.js";
31
+ export { Global, Module } from "./module/index.js";
32
+ export { RequestMethod } from "./http/index.js";
30
33
  // Pipeline Decorators
31
34
  export { UseMiddleware, UseGuards, UsePipes, UseInterceptors, UseFilters, Catch, SetMetadata, Reflector, APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE } from "./pipeline/index.js";
32
35
  // Built-in Pipes
33
- export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe } from "./pipeline/index.js";
36
+ export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, ParseUUIDPipe, ParseEnumPipe, ParseArrayPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe } from "./pipeline/index.js";
34
37
  // Errors
35
38
  export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, MethodNotAllowedException, NotAcceptableException, RequestTimeoutException, ConflictException, GoneException, PayloadTooLargeException, UnsupportedMediaTypeException, UnprocessableEntityException, TooManyRequestsException, InternalServerErrorException, NotImplementedException, BadGatewayException, ServiceUnavailableException, GatewayTimeoutException } from "./errors/index.js";
36
39
  // Registry (for advanced usage)
@@ -7,4 +7,4 @@ declare global {
7
7
  }
8
8
  }
9
9
  export declare function defineMetadata(key: string, value: unknown, target: object, propertyKey?: string | symbol): void;
10
- export declare function getMetadata(key: string, target: object, propertyKey?: string | symbol): unknown;
10
+ export declare function getMetadata<T = unknown>(key: string, target: object, propertyKey?: string | symbol): T | undefined;
@@ -1,5 +1,6 @@
1
1
  import type { Constructor } from '../registry/types';
2
2
  import type { ModuleMetadata, ModuleOptions } from './types';
3
+ export declare function Global(): ClassDecorator;
3
4
  export declare function Module(options?: ModuleOptions): ClassDecorator;
4
5
  export declare function isModule(target: Constructor): boolean;
5
6
  export declare function getModuleMetadata(target: Constructor): ModuleMetadata | undefined;