@velajs/vela 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) 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 +6 -1
  7. package/dist/constants.js +5 -0
  8. package/dist/container/container.d.ts +2 -0
  9. package/dist/container/container.js +47 -15
  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/factory.js +11 -2
  22. package/dist/fetch/fetch.module.d.ts +6 -0
  23. package/dist/fetch/fetch.module.js +77 -0
  24. package/dist/fetch/fetch.service.d.ts +24 -0
  25. package/dist/fetch/fetch.service.js +145 -0
  26. package/dist/fetch/fetch.types.d.ts +24 -0
  27. package/dist/fetch/fetch.types.js +1 -0
  28. package/dist/fetch/index.d.ts +3 -0
  29. package/dist/fetch/index.js +2 -0
  30. package/dist/http/decorators.d.ts +64 -0
  31. package/dist/http/decorators.js +89 -1
  32. package/dist/http/index.d.ts +3 -1
  33. package/dist/http/index.js +2 -1
  34. package/dist/http/middleware-consumer.d.ts +36 -0
  35. package/dist/http/middleware-consumer.js +71 -0
  36. package/dist/http/route.manager.d.ts +4 -0
  37. package/dist/http/route.manager.js +75 -1
  38. package/dist/index.d.ts +11 -6
  39. package/dist/index.js +7 -4
  40. package/dist/metadata.d.ts +1 -1
  41. package/dist/module/decorators.d.ts +1 -0
  42. package/dist/module/decorators.js +24 -8
  43. package/dist/module/index.d.ts +2 -2
  44. package/dist/module/index.js +1 -1
  45. package/dist/module/module-loader.d.ts +5 -1
  46. package/dist/module/module-loader.js +54 -10
  47. package/dist/module/types.d.ts +13 -3
  48. package/dist/pipeline/index.d.ts +3 -2
  49. package/dist/pipeline/index.js +1 -1
  50. package/dist/pipeline/pipes.d.ts +22 -0
  51. package/dist/pipeline/pipes.js +50 -0
  52. package/dist/pipeline/tokens.d.ts +1 -1
  53. package/dist/pipeline/tokens.js +1 -1
  54. package/dist/pipeline/types.d.ts +16 -0
  55. package/dist/registry/metadata.registry.d.ts +7 -6
  56. package/dist/registry/metadata.registry.js +13 -0
  57. package/dist/registry/types.d.ts +1 -0
  58. package/dist/schedule/schedule.module.d.ts +4 -1
  59. package/dist/schedule/schedule.module.js +39 -7
  60. package/dist/testing/testing.builder.js +5 -5
  61. package/dist/throttler/throttler.module.d.ts +2 -1
  62. package/dist/throttler/throttler.module.js +47 -9
  63. package/package.json +1 -1
package/dist/factory.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { VelaApplication } from "./application.js";
2
2
  import { Container } from "./container/container.js";
3
+ import { ModuleRef } from "./container/module-ref.js";
3
4
  import { RouteManager } from "./http/route.manager.js";
4
5
  import { ModuleLoader } from "./module/module-loader.js";
5
6
  import { ComponentManager } from "./pipeline/component.manager.js";
@@ -8,9 +9,16 @@ export const VelaFactory = {
8
9
  async create (rootModule) {
9
10
  const container = new Container();
10
11
  container.register({
11
- token: Container,
12
+ provide: Container,
12
13
  useValue: container
13
14
  });
15
+ container.register({
16
+ provide: ModuleRef,
17
+ useFactory: (c)=>new ModuleRef(c),
18
+ inject: [
19
+ Container
20
+ ]
21
+ });
14
22
  const routeManager = new RouteManager(container);
15
23
  ComponentManager.init(container);
16
24
  const loader = new ModuleLoader(container, routeManager);
@@ -45,8 +53,9 @@ export const VelaFactory = {
45
53
  } else if (container.has(APP_MIDDLEWARE)) {
46
54
  routeManager.useGlobalMiddlewareTokens(APP_MIDDLEWARE);
47
55
  }
56
+ routeManager.registerConsumerMiddleware(loader.getConsumerMiddlewareDefinitions());
48
57
  const app = new VelaApplication(container, routeManager);
49
- const instances = loader.resolveAllInstances();
58
+ const instances = await loader.resolveAllInstances();
50
59
  app.setInstances(instances);
51
60
  await app.callOnModuleInit();
52
61
  await app.callOnApplicationBootstrap();
@@ -0,0 +1,6 @@
1
+ import type { AsyncModuleOptions, DynamicModule } from '../module/types';
2
+ import type { HttpModuleOptions } from './fetch.types';
3
+ export declare class HttpModule {
4
+ static register(options?: HttpModuleOptions): DynamicModule;
5
+ static registerAsync(options: AsyncModuleOptions<HttpModuleOptions>): DynamicModule;
6
+ }
@@ -0,0 +1,77 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ import { METADATA_KEYS } from "../constants.js";
8
+ import { defineMetadata } from "../metadata.js";
9
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
10
+ import { Module } from "../module/decorators.js";
11
+ import { HttpService, HTTP_MODULE_OPTIONS } from "./fetch.service.js";
12
+ export class HttpModule {
13
+ static register(options = {}) {
14
+ const moduleClass = class HttpDynamicModule {
15
+ };
16
+ Object.defineProperty(moduleClass, 'name', {
17
+ value: 'HttpModule'
18
+ });
19
+ defineMetadata(METADATA_KEYS.MODULE, true, moduleClass);
20
+ MetadataRegistry.setModuleOptions(moduleClass, {
21
+ exports: [
22
+ HttpService,
23
+ HTTP_MODULE_OPTIONS
24
+ ]
25
+ });
26
+ return {
27
+ module: moduleClass,
28
+ providers: [
29
+ {
30
+ provide: HTTP_MODULE_OPTIONS,
31
+ useValue: options
32
+ },
33
+ HttpService
34
+ ]
35
+ };
36
+ }
37
+ static registerAsync(options) {
38
+ const moduleClass = class HttpAsyncDynamicModule {
39
+ };
40
+ Object.defineProperty(moduleClass, 'name', {
41
+ value: 'HttpModule'
42
+ });
43
+ defineMetadata(METADATA_KEYS.MODULE, true, moduleClass);
44
+ MetadataRegistry.setModuleOptions(moduleClass, {
45
+ imports: options.imports ?? [],
46
+ exports: [
47
+ HttpService,
48
+ HTTP_MODULE_OPTIONS
49
+ ]
50
+ });
51
+ return {
52
+ module: moduleClass,
53
+ providers: [
54
+ {
55
+ provide: HTTP_MODULE_OPTIONS,
56
+ useFactory: options.useFactory,
57
+ inject: options.inject ?? []
58
+ },
59
+ HttpService
60
+ ]
61
+ };
62
+ }
63
+ }
64
+ HttpModule = _ts_decorate([
65
+ Module({
66
+ providers: [
67
+ {
68
+ provide: HTTP_MODULE_OPTIONS,
69
+ useValue: {}
70
+ },
71
+ HttpService
72
+ ],
73
+ exports: [
74
+ HttpService
75
+ ]
76
+ })
77
+ ], HttpModule);
@@ -0,0 +1,24 @@
1
+ import { InjectionToken } from '../container/index';
2
+ import type { HttpModuleOptions, HttpRequestConfig, HttpResponse, RequestConfig } from './fetch.types';
3
+ export declare const HTTP_MODULE_OPTIONS: InjectionToken<HttpModuleOptions>;
4
+ export declare class HttpRequestException extends Error {
5
+ readonly status: number;
6
+ readonly statusText: string;
7
+ readonly response: Response;
8
+ constructor(status: number, statusText: string, response: Response);
9
+ }
10
+ export declare class HttpService {
11
+ private readonly baseURL;
12
+ private readonly defaultHeaders;
13
+ private readonly defaultTimeout;
14
+ constructor(options: HttpModuleOptions);
15
+ get<T = unknown>(url: string, config?: RequestConfig): Promise<HttpResponse<T>>;
16
+ post<T = unknown>(url: string, body?: unknown, config?: RequestConfig): Promise<HttpResponse<T>>;
17
+ put<T = unknown>(url: string, body?: unknown, config?: RequestConfig): Promise<HttpResponse<T>>;
18
+ patch<T = unknown>(url: string, body?: unknown, config?: RequestConfig): Promise<HttpResponse<T>>;
19
+ delete<T = unknown>(url: string, config?: RequestConfig): Promise<HttpResponse<T>>;
20
+ head(url: string, config?: RequestConfig): Promise<HttpResponse<void>>;
21
+ request<T = unknown>(config: HttpRequestConfig): Promise<HttpResponse<T>>;
22
+ private buildUrl;
23
+ private parseBody;
24
+ }
@@ -0,0 +1,145 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ function _ts_param(paramIndex, decorator) {
11
+ return function(target, key) {
12
+ decorator(target, key, paramIndex);
13
+ };
14
+ }
15
+ import { Inject, Injectable, InjectionToken, Optional } from "../container/index.js";
16
+ export const HTTP_MODULE_OPTIONS = new InjectionToken('HTTP_MODULE_OPTIONS');
17
+ export class HttpRequestException extends Error {
18
+ status;
19
+ statusText;
20
+ response;
21
+ constructor(status, statusText, response){
22
+ super(`HTTP ${status} ${statusText}`), this.status = status, this.statusText = statusText, this.response = response;
23
+ this.name = 'HttpRequestException';
24
+ }
25
+ }
26
+ export class HttpService {
27
+ baseURL;
28
+ defaultHeaders;
29
+ defaultTimeout;
30
+ constructor(options){
31
+ const opts = options ?? {};
32
+ this.baseURL = opts.baseURL ?? '';
33
+ this.defaultHeaders = opts.headers ?? {};
34
+ this.defaultTimeout = opts.timeout;
35
+ }
36
+ get(url, config) {
37
+ return this.request({
38
+ method: 'GET',
39
+ url,
40
+ ...config
41
+ });
42
+ }
43
+ post(url, body, config) {
44
+ return this.request({
45
+ method: 'POST',
46
+ url,
47
+ body,
48
+ ...config
49
+ });
50
+ }
51
+ put(url, body, config) {
52
+ return this.request({
53
+ method: 'PUT',
54
+ url,
55
+ body,
56
+ ...config
57
+ });
58
+ }
59
+ patch(url, body, config) {
60
+ return this.request({
61
+ method: 'PATCH',
62
+ url,
63
+ body,
64
+ ...config
65
+ });
66
+ }
67
+ delete(url, config) {
68
+ return this.request({
69
+ method: 'DELETE',
70
+ url,
71
+ ...config
72
+ });
73
+ }
74
+ head(url, config) {
75
+ return this.request({
76
+ method: 'HEAD',
77
+ url,
78
+ ...config
79
+ });
80
+ }
81
+ async request(config) {
82
+ const fullUrl = this.buildUrl(config.url, config.params);
83
+ const headers = {
84
+ ...this.defaultHeaders,
85
+ ...config.headers
86
+ };
87
+ const init = {
88
+ method: config.method,
89
+ headers
90
+ };
91
+ if (config.body !== undefined) {
92
+ if (typeof config.body === 'string' || config.body instanceof FormData) {
93
+ init.body = config.body;
94
+ } else {
95
+ init.body = JSON.stringify(config.body);
96
+ if (!headers['Content-Type'] && !headers['content-type']) {
97
+ headers['Content-Type'] = 'application/json';
98
+ }
99
+ }
100
+ }
101
+ const timeout = config.timeout ?? this.defaultTimeout;
102
+ if (timeout !== undefined) {
103
+ init.signal = AbortSignal.timeout(timeout);
104
+ }
105
+ const response = await fetch(fullUrl, init);
106
+ if (!response.ok) {
107
+ throw new HttpRequestException(response.status, response.statusText, response);
108
+ }
109
+ const data = await this.parseBody(response);
110
+ return {
111
+ data,
112
+ status: response.status,
113
+ statusText: response.statusText,
114
+ headers: response.headers
115
+ };
116
+ }
117
+ buildUrl(url, params) {
118
+ const base = this.baseURL ? `${this.baseURL}${url}` : url;
119
+ if (!params || Object.keys(params).length === 0) return base;
120
+ const searchParams = new URLSearchParams(Object.entries(params).map(([k, v])=>[
121
+ k,
122
+ String(v)
123
+ ]));
124
+ return `${base}?${searchParams.toString()}`;
125
+ }
126
+ async parseBody(response) {
127
+ if (response.status === 204 || response.headers.get('content-length') === '0') {
128
+ return undefined;
129
+ }
130
+ const contentType = response.headers.get('content-type') ?? '';
131
+ if (contentType.includes('application/json')) {
132
+ return response.json();
133
+ }
134
+ return response.text();
135
+ }
136
+ }
137
+ HttpService = _ts_decorate([
138
+ Injectable(),
139
+ _ts_param(0, Optional()),
140
+ _ts_param(0, Inject(HTTP_MODULE_OPTIONS)),
141
+ _ts_metadata("design:type", Function),
142
+ _ts_metadata("design:paramtypes", [
143
+ typeof HttpModuleOptions === "undefined" ? Object : HttpModuleOptions
144
+ ])
145
+ ], HttpService);
@@ -0,0 +1,24 @@
1
+ export interface HttpModuleOptions {
2
+ /** Base URL prepended to all requests. */
3
+ baseURL?: string;
4
+ /** Default headers sent with every request. */
5
+ headers?: Record<string, string>;
6
+ /** Default timeout in milliseconds (uses AbortSignal.timeout). */
7
+ timeout?: number;
8
+ }
9
+ export interface RequestConfig {
10
+ headers?: Record<string, string>;
11
+ params?: Record<string, string | number | boolean>;
12
+ timeout?: number;
13
+ }
14
+ export interface HttpRequestConfig extends RequestConfig {
15
+ method: string;
16
+ url: string;
17
+ body?: unknown;
18
+ }
19
+ export interface HttpResponse<T = unknown> {
20
+ data: T;
21
+ status: number;
22
+ statusText: string;
23
+ headers: Headers;
24
+ }
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,3 @@
1
+ export { HttpModule } from './fetch.module';
2
+ export { HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } from './fetch.service';
3
+ export type { HttpModuleOptions, HttpRequestConfig, HttpResponse, RequestConfig } from './fetch.types';
@@ -0,0 +1,2 @@
1
+ export { HttpModule } from "./fetch.module.js";
2
+ export { HttpService, HTTP_MODULE_OPTIONS, HttpRequestException } from "./fetch.service.js";
@@ -44,6 +44,53 @@ export declare const Query: (nameOrPipe?: string | PipeType, ...pipes: PipeType[
44
44
  export declare const Body: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
45
45
  export declare const Headers: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
46
46
  export declare const Req: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
47
+ /**
48
+ * Injects the Hono `Context` as the response handle.
49
+ * In Hono, request and response state are unified in the `Context` object,
50
+ * so `@Res()` and `@Req()` both return it.
51
+ *
52
+ * Use `c.header()`, `c.setCookie()`, `c.redirect()`, etc. for response control.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * @Get('/set-cookie')
57
+ * handle(@Res() c: Context) {
58
+ * c.setCookie('session', 'abc123', { httpOnly: true });
59
+ * return { ok: true };
60
+ * }
61
+ * ```
62
+ */
63
+ export declare const Res: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
64
+ export declare const Ip: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
65
+ export declare const Cookie: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
66
+ /**
67
+ * Injects all cookies as a `Record<string, string>`, or a single cookie value by name.
68
+ *
69
+ * - `@Cookie()` — all cookies as an object
70
+ * - `@Cookie('token')` — the value of the `token` cookie
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * @Get('/me')
75
+ * handle(@Cookie('session') session: string) { ... }
76
+ * ```
77
+ */
78
+ export declare const Cookies: (nameOrPipe?: string | PipeType, ...pipes: PipeType[]) => ParameterDecorator;
79
+ /**
80
+ * Injects the raw request body as a `Uint8Array`.
81
+ * Useful for webhook HMAC verification (Stripe, GitHub, etc.) where you
82
+ * need the raw bytes before any JSON parsing.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * @Post('/webhook')
87
+ * async handle(@RawBody() body: Uint8Array) {
88
+ * const sig = new TextDecoder().decode(body);
89
+ * // verify HMAC...
90
+ * }
91
+ * ```
92
+ */
93
+ export declare function RawBody(): ParameterDecorator;
47
94
  /**
48
95
  * Factory for creating custom parameter decorators.
49
96
  *
@@ -120,4 +167,21 @@ export declare function getRedirect(target: Constructor, method: string | symbol
120
167
  url: string;
121
168
  statusCode: number;
122
169
  } | undefined;
170
+ /**
171
+ * Composes multiple decorators into one. Applies them in order (top to bottom),
172
+ * matching how stacked decorators behave when written separately.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const Auth = (...roles: string[]) => applyDecorators(
177
+ * UseGuards(JwtGuard, RolesGuard),
178
+ * SetMetadata('roles', roles),
179
+ * );
180
+ *
181
+ * @Auth('admin')
182
+ * @Get('/admin')
183
+ * handle() { ... }
184
+ * ```
185
+ */
186
+ export declare function applyDecorators(...decorators: Array<ClassDecorator | MethodDecorator | PropertyDecorator | ParameterDecorator>): ClassDecorator & MethodDecorator & PropertyDecorator;
123
187
  export declare function isController(target: Constructor): boolean;
@@ -136,6 +136,60 @@ export const Query = createBuiltinParamDecorator(ParamType.QUERY);
136
136
  export const Body = createBuiltinParamDecorator(ParamType.BODY);
137
137
  export const Headers = createBuiltinParamDecorator(ParamType.HEADERS);
138
138
  export const Req = createBuiltinParamDecorator(ParamType.REQUEST);
139
+ /**
140
+ * Injects the Hono `Context` as the response handle.
141
+ * In Hono, request and response state are unified in the `Context` object,
142
+ * so `@Res()` and `@Req()` both return it.
143
+ *
144
+ * Use `c.header()`, `c.setCookie()`, `c.redirect()`, etc. for response control.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * @Get('/set-cookie')
149
+ * handle(@Res() c: Context) {
150
+ * c.setCookie('session', 'abc123', { httpOnly: true });
151
+ * return { ok: true };
152
+ * }
153
+ * ```
154
+ */ export const Res = createBuiltinParamDecorator(ParamType.RESPONSE);
155
+ export const Ip = createBuiltinParamDecorator(ParamType.IP);
156
+ export const Cookie = createBuiltinParamDecorator(ParamType.COOKIE);
157
+ /**
158
+ * Injects all cookies as a `Record<string, string>`, or a single cookie value by name.
159
+ *
160
+ * - `@Cookie()` — all cookies as an object
161
+ * - `@Cookie('token')` — the value of the `token` cookie
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * @Get('/me')
166
+ * handle(@Cookie('session') session: string) { ... }
167
+ * ```
168
+ */ export const Cookies = Cookie;
169
+ /**
170
+ * Injects the raw request body as a `Uint8Array`.
171
+ * Useful for webhook HMAC verification (Stripe, GitHub, etc.) where you
172
+ * need the raw bytes before any JSON parsing.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * @Post('/webhook')
177
+ * async handle(@RawBody() body: Uint8Array) {
178
+ * const sig = new TextDecoder().decode(body);
179
+ * // verify HMAC...
180
+ * }
181
+ * ```
182
+ */ export function RawBody() {
183
+ return (target, propertyKey, parameterIndex)=>{
184
+ if (propertyKey === undefined) {
185
+ throw new Error('Parameter decorators can only be used on method parameters');
186
+ }
187
+ MetadataRegistry.addParameter(target.constructor, propertyKey, {
188
+ index: parameterIndex,
189
+ type: ParamType.RAW_BODY
190
+ });
191
+ };
192
+ }
139
193
  /**
140
194
  * Factory for creating custom parameter decorators.
141
195
  *
@@ -175,10 +229,15 @@ export const Req = createBuiltinParamDecorator(ParamType.REQUEST);
175
229
  factory: (_unused, ctx)=>{
176
230
  const honoCtx = ctx;
177
231
  const execCtx = {
232
+ getType: ()=>'http',
178
233
  getClass: ()=>target.constructor,
179
234
  getHandler: ()=>propertyKey,
180
235
  getContext: ()=>honoCtx,
181
- getRequest: ()=>honoCtx.req.raw
236
+ getRequest: ()=>honoCtx.req.raw,
237
+ switchToHttp: ()=>({
238
+ getRequest: ()=>honoCtx.req.raw,
239
+ getResponse: ()=>honoCtx
240
+ })
182
241
  };
183
242
  return factory(data, execCtx);
184
243
  },
@@ -271,6 +330,35 @@ export function getRedirect(target, method) {
271
330
  if (meta?.redirect) return meta.redirect;
272
331
  return getMetadata(METADATA_KEYS.REDIRECT, target, method);
273
332
  }
333
+ /**
334
+ * Composes multiple decorators into one. Applies them in order (top to bottom),
335
+ * matching how stacked decorators behave when written separately.
336
+ *
337
+ * @example
338
+ * ```ts
339
+ * const Auth = (...roles: string[]) => applyDecorators(
340
+ * UseGuards(JwtGuard, RolesGuard),
341
+ * SetMetadata('roles', roles),
342
+ * );
343
+ *
344
+ * @Auth('admin')
345
+ * @Get('/admin')
346
+ * handle() { ... }
347
+ * ```
348
+ */ export function applyDecorators(...decorators) {
349
+ const composed = (target, propertyKey, descriptor)=>{
350
+ for (const decorator of decorators){
351
+ if (propertyKey === undefined && typeof descriptor !== 'number') {
352
+ decorator(target);
353
+ } else if (typeof descriptor === 'number') {
354
+ decorator(target, propertyKey, descriptor);
355
+ } else {
356
+ decorator(target, propertyKey, descriptor);
357
+ }
358
+ }
359
+ };
360
+ return composed;
361
+ }
274
362
  // Helpers
275
363
  export function isController(target) {
276
364
  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, 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, 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
  }