@velajs/vela 0.4.2 → 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 (65) 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 +4 -0
  9. package/dist/container/container.js +52 -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 +10 -3
  19. package/dist/container/types.js +9 -0
  20. package/dist/cors/cors.module.js +2 -2
  21. package/dist/factory.js +36 -13
  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 +13 -1
  37. package/dist/http/route.manager.js +153 -53
  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 +9 -1
  46. package/dist/module/module-loader.js +107 -11
  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.executor.d.ts +11 -2
  59. package/dist/schedule/schedule.executor.js +134 -19
  60. package/dist/schedule/schedule.module.d.ts +4 -1
  61. package/dist/schedule/schedule.module.js +39 -7
  62. package/dist/testing/testing.builder.js +31 -17
  63. package/dist/throttler/throttler.module.d.ts +2 -1
  64. package/dist/throttler/throttler.module.js +47 -9
  65. package/package.json +1 -1
@@ -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,8 @@
1
1
  import { Hono } from 'hono';
2
2
  import type { Container } from '../container/container';
3
- import type { Type } from '../container/types';
3
+ import type { Token, Type } from '../container/types';
4
+ import type { MiddlewareRouteDefinition } from './middleware-consumer';
5
+ import type { CanActivate, ExceptionFilter, NestInterceptor, NestMiddleware, PipeTransform } from '../pipeline/types';
4
6
  import type { FilterType, GuardType, InterceptorType, MiddlewareType, PipeType } from '../registry/types';
5
7
  import type { ControllerRegistration } from './types';
6
8
  export declare class RouteManager {
@@ -12,14 +14,23 @@ export declare class RouteManager {
12
14
  private globalInterceptors;
13
15
  private globalFilters;
14
16
  private globalPrefix;
17
+ private consumerMiddlewareDefinitions;
15
18
  constructor(container: Container);
19
+ registerConsumerMiddleware(definitions: MiddlewareRouteDefinition[]): this;
16
20
  setGlobalPrefix(prefix: string): this;
17
21
  useGlobalMiddleware(...middleware: MiddlewareType[]): this;
22
+ useGlobalMiddlewareTokens(...middlewareTokens: Array<Token<NestMiddleware>>): this;
18
23
  useGlobalPipes(...pipes: PipeType[]): this;
24
+ useGlobalPipeTokens(...pipeTokens: Array<Token<PipeTransform>>): this;
19
25
  useGlobalGuards(...guards: GuardType[]): this;
26
+ useGlobalGuardTokens(...guardTokens: Array<Token<CanActivate>>): this;
20
27
  useGlobalInterceptors(...interceptors: InterceptorType[]): this;
28
+ useGlobalInterceptorTokens(...interceptorTokens: Array<Token<NestInterceptor>>): this;
21
29
  useGlobalFilters(...filters: FilterType[]): this;
30
+ useGlobalFilterTokens(...filterTokens: Array<Token<ExceptionFilter>>): this;
22
31
  private instantiate;
32
+ private instantiateMany;
33
+ private getRequestContainer;
23
34
  registerController(controller: Type): this;
24
35
  build(): Promise<Hono>;
25
36
  private createExecutionContext;
@@ -30,5 +41,6 @@ export declare class RouteManager {
30
41
  private registerRoute;
31
42
  private buildVersionedPaths;
32
43
  private joinPaths;
44
+ private matchesConsumerPath;
33
45
  getControllers(): ControllerRegistration[];
34
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,51 +28,81 @@ 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;
36
42
  }
37
43
  useGlobalMiddleware(...middleware) {
38
- for (const mw of middleware){
39
- this.globalMiddleware.push(this.instantiate(mw));
40
- }
44
+ this.globalMiddleware.push(...middleware);
45
+ return this;
46
+ }
47
+ useGlobalMiddlewareTokens(...middlewareTokens) {
48
+ this.globalMiddleware.push(...middlewareTokens);
41
49
  return this;
42
50
  }
43
51
  useGlobalPipes(...pipes) {
44
- for (const pipe of pipes){
45
- this.globalPipes.push(this.instantiate(pipe));
46
- }
52
+ this.globalPipes.push(...pipes);
53
+ return this;
54
+ }
55
+ useGlobalPipeTokens(...pipeTokens) {
56
+ this.globalPipes.push(...pipeTokens);
47
57
  return this;
48
58
  }
49
59
  useGlobalGuards(...guards) {
50
- for (const guard of guards){
51
- this.globalGuards.push(this.instantiate(guard));
52
- }
60
+ this.globalGuards.push(...guards);
61
+ return this;
62
+ }
63
+ useGlobalGuardTokens(...guardTokens) {
64
+ this.globalGuards.push(...guardTokens);
53
65
  return this;
54
66
  }
55
67
  useGlobalInterceptors(...interceptors) {
56
- for (const interceptor of interceptors){
57
- this.globalInterceptors.push(this.instantiate(interceptor));
58
- }
68
+ this.globalInterceptors.push(...interceptors);
69
+ return this;
70
+ }
71
+ useGlobalInterceptorTokens(...interceptorTokens) {
72
+ this.globalInterceptors.push(...interceptorTokens);
59
73
  return this;
60
74
  }
61
75
  useGlobalFilters(...filters) {
62
- for (const filter of filters){
63
- this.globalFilters.push(this.instantiate(filter));
64
- }
76
+ this.globalFilters.push(...filters);
77
+ return this;
78
+ }
79
+ useGlobalFilterTokens(...filterTokens) {
80
+ this.globalFilters.push(...filterTokens);
65
81
  return this;
66
82
  }
67
- instantiate(classOrInstance) {
68
- if (typeof classOrInstance !== 'function') {
69
- return classOrInstance;
83
+ instantiate(classOrInstance, container) {
84
+ if (typeof classOrInstance === 'function') {
85
+ if (container.has(classOrInstance)) {
86
+ return container.resolve(classOrInstance);
87
+ }
88
+ return new classOrInstance();
70
89
  }
71
- if (this.container.has(classOrInstance)) {
72
- return this.container.resolve(classOrInstance);
90
+ if (container.has(classOrInstance)) {
91
+ return container.resolve(classOrInstance);
92
+ }
93
+ return classOrInstance;
94
+ }
95
+ instantiateMany(items, container) {
96
+ return items.map((item)=>this.instantiate(item, container));
97
+ }
98
+ getRequestContainer(c) {
99
+ const existing = c.get('container');
100
+ if (existing) {
101
+ return existing;
73
102
  }
74
- return new classOrInstance();
103
+ const child = this.container.createChild();
104
+ c.set('container', child);
105
+ return child;
75
106
  }
76
107
  registerController(controller) {
77
108
  const prefix = MetadataRegistry.getControllerPath(controller);
@@ -94,12 +125,46 @@ export class RouteManager {
94
125
  const app = new Hono();
95
126
  // Register global middleware on the Hono app
96
127
  for (const mw of this.globalMiddleware){
97
- app.use('*', (c, next)=>mw.use(c, next));
128
+ app.use('*', (c, next)=>{
129
+ const requestContainer = this.getRequestContainer(c);
130
+ const resolved = this.instantiate(mw, requestContainer);
131
+ return resolved.use(c, next);
132
+ });
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
+ });
98
164
  }
99
165
  // First pass: register all custom routes (must come before CRUD /:id routes)
100
166
  for (const { controller, metadata, routes } of this.controllers){
101
167
  if (routes.length > 0) {
102
- const instance = this.container.resolve(controller);
103
168
  const allParamMetadata = MetadataRegistry.getParameters(controller);
104
169
  for (const route of routes){
105
170
  // Determine effective version: route-level overrides controller-level
@@ -108,11 +173,14 @@ export class RouteManager {
108
173
  const versionedPaths = this.buildVersionedPaths(this.globalPrefix, metadata.prefix, route.path, effectiveVersion);
109
174
  // Register per-route middleware as Hono middleware before the handler
110
175
  const middlewareItems = ComponentManager.getComponents('middleware', controller, route.handlerName);
111
- const resolvedMw = ComponentManager.resolveMiddleware(middlewareItems);
112
- const handler = this.createHandler(instance, route, controller, allParamMetadata);
176
+ const handler = this.createHandler(route, controller, allParamMetadata);
113
177
  for (const fullPath of versionedPaths){
114
- for (const mw of resolvedMw){
115
- app.use(fullPath, (c, next)=>mw.use(c, next));
178
+ for (const middlewareItem of middlewareItems){
179
+ app.use(fullPath, (c, next)=>{
180
+ const requestContainer = this.getRequestContainer(c);
181
+ const resolved = this.instantiate(middlewareItem, requestContainer);
182
+ return resolved.use(c, next);
183
+ });
116
184
  }
117
185
  this.registerRoute(app, route.method, fullPath, handler);
118
186
  }
@@ -128,7 +196,7 @@ export class RouteManager {
128
196
  const { buildCrudRoutes } = await import(pkg);
129
197
  await buildCrudRoutes(app, controller, metadata.prefix, crudConfig, {
130
198
  globalPrefix: this.globalPrefix,
131
- globalGuards: this.globalGuards,
199
+ globalGuards: this.instantiateMany(this.globalGuards, this.container),
132
200
  joinPaths: this.joinPaths.bind(this)
133
201
  });
134
202
  } catch {
@@ -140,57 +208,57 @@ export class RouteManager {
140
208
  }
141
209
  createExecutionContext(c, controller, route) {
142
210
  return {
211
+ getType: ()=>'http',
143
212
  getClass: ()=>controller,
144
213
  getHandler: ()=>route.handlerName,
145
214
  getContext: ()=>c,
146
- getRequest: ()=>c.req.raw
215
+ getRequest: ()=>c.req.raw,
216
+ switchToHttp: ()=>({
217
+ getRequest: ()=>c.req.raw,
218
+ getResponse: ()=>c
219
+ })
147
220
  };
148
221
  }
149
- createHandler(instance, route, controller, allParamMetadata) {
222
+ createHandler(route, controller, allParamMetadata) {
150
223
  const paramMetadata = (allParamMetadata.get(route.handlerName) || []).sort((a, b)=>a.index - b.index);
151
224
  // Read param types once at build time for metatype population
152
- const paramTypes = Reflect.getMetadata('design:paramtypes', instance.constructor.prototype, route.handlerName);
153
- // Pre-resolve controller + method level components at build time
225
+ const paramTypes = Reflect.getMetadata('design:paramtypes', controller.prototype, route.handlerName);
226
+ // Collect controller + method level components at build time
154
227
  const methodGuards = ComponentManager.getComponents('guard', controller, route.handlerName);
155
228
  const methodPipes = ComponentManager.getComponents('pipe', controller, route.handlerName);
156
229
  const methodInterceptors = ComponentManager.getComponents('interceptor', controller, route.handlerName);
157
- const methodFilters = ComponentManager.getComponents('filter', controller, route.handlerName);
158
- const resolvedMethodGuards = ComponentManager.resolveGuards(methodGuards);
159
- const resolvedMethodPipes = ComponentManager.resolvePipes(methodPipes);
160
- const resolvedMethodInterceptors = ComponentManager.resolveInterceptors(methodInterceptors);
161
230
  // Filters: reverse order (handler → controller → global) — closest to handler runs first
162
- const resolvedMethodFilters = ComponentManager.resolveFilters([
163
- ...methodFilters
164
- ].reverse());
231
+ const methodFilters = [
232
+ ...ComponentManager.getComponents('filter', controller, route.handlerName)
233
+ ].reverse();
165
234
  // Read response decorators at build time
166
235
  const httpCode = getHttpCode(controller, route.handlerName);
167
236
  const responseHeaders = getResponseHeaders(controller, route.handlerName);
168
237
  const redirect = getRedirect(controller, route.handlerName);
169
238
  return async (c)=>{
170
- // Create a child container for request-scoped providers
171
- const requestContainer = this.container.createChild();
172
- c.set('container', requestContainer);
173
239
  // Combine global + method at request time (allows post-create registration)
240
+ const requestContainer = this.getRequestContainer(c);
174
241
  const guards = [
175
- ...this.globalGuards,
176
- ...resolvedMethodGuards
242
+ ...this.instantiateMany(this.globalGuards, requestContainer),
243
+ ...this.instantiateMany(methodGuards, requestContainer)
177
244
  ];
178
245
  const pipes = [
179
- ...this.globalPipes,
180
- ...resolvedMethodPipes
246
+ ...this.instantiateMany(this.globalPipes, requestContainer),
247
+ ...this.instantiateMany(methodPipes, requestContainer)
181
248
  ];
182
249
  const interceptors = [
183
- ...this.globalInterceptors,
184
- ...resolvedMethodInterceptors
250
+ ...this.instantiateMany(this.globalInterceptors, requestContainer),
251
+ ...this.instantiateMany(methodInterceptors, requestContainer)
185
252
  ];
186
253
  const filters = [
187
- ...resolvedMethodFilters,
188
- ...this.globalFilters
254
+ ...this.instantiateMany(methodFilters, requestContainer),
255
+ ...this.instantiateMany(this.globalFilters, requestContainer)
189
256
  ];
190
257
  const executionContext = this.createExecutionContext(c, controller, route);
191
258
  try {
259
+ const instance = requestContainer.resolve(controller);
192
260
  // 1. Extract args + run pipes
193
- const args = await this.extractArguments(c, paramMetadata, pipes, paramTypes);
261
+ const args = await this.extractArguments(c, paramMetadata, pipes, requestContainer, paramTypes);
194
262
  // 2. Guards (fail-fast)
195
263
  for (const guard of guards){
196
264
  const canActivate = await guard.canActivate(executionContext);
@@ -247,7 +315,7 @@ export class RouteManager {
247
315
  }
248
316
  };
249
317
  }
250
- async extractArguments(c, paramMetadata, pipes, paramTypes) {
318
+ async extractArguments(c, paramMetadata, pipes, requestContainer, paramTypes) {
251
319
  if (paramMetadata.length === 0) {
252
320
  return [
253
321
  c
@@ -269,7 +337,7 @@ export class RouteManager {
269
337
  // Run param-level pipes
270
338
  if (param.pipes && param.pipes.length > 0) {
271
339
  for (const paramPipe of param.pipes){
272
- const pipeInstance = this.instantiate(paramPipe);
340
+ const pipeInstance = this.instantiate(paramPipe, requestContainer);
273
341
  value = await pipeInstance.transform(value, metadata);
274
342
  }
275
343
  }
@@ -300,6 +368,28 @@ export class RouteManager {
300
368
  return headers;
301
369
  case ParamType.REQUEST:
302
370
  return c;
371
+ case ParamType.RESPONSE:
372
+ return c;
373
+ case ParamType.IP:
374
+ return c.req.raw.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? c.req.raw.headers.get('x-real-ip') ?? null;
375
+ case ParamType.COOKIE:
376
+ {
377
+ const cookieHeader = c.req.raw.headers.get('cookie') ?? '';
378
+ const cookies = {};
379
+ for (const pair of cookieHeader.split(';')){
380
+ const eqIdx = pair.indexOf('=');
381
+ if (eqIdx === -1) continue;
382
+ const name = pair.slice(0, eqIdx).trim();
383
+ const value = pair.slice(eqIdx + 1).trim();
384
+ if (name) cookies[name] = decodeURIComponent(value);
385
+ }
386
+ return param.name ? cookies[param.name] ?? undefined : cookies;
387
+ }
388
+ case ParamType.RAW_BODY:
389
+ {
390
+ const buffer = await c.req.arrayBuffer();
391
+ return new Uint8Array(buffer);
392
+ }
303
393
  default:
304
394
  // Custom param decorator — use factory if available
305
395
  if (param.factory) {
@@ -367,6 +457,16 @@ export class RouteManager {
367
457
  const cleanPath = path && !path.startsWith('/') ? `/${path}` : path;
368
458
  return `${cleanPrefix}${cleanPath}` || '/';
369
459
  }
460
+ matchesConsumerPath(reqPath, routePath) {
461
+ if (routePath === '*') return true;
462
+ const normalized = routePath.startsWith('/') ? routePath : `/${routePath}`;
463
+ if (reqPath === normalized) return true;
464
+ if (reqPath.startsWith(`${normalized}/`)) return true;
465
+ if (normalized.endsWith('*')) {
466
+ return reqPath.startsWith(normalized.slice(0, -1));
467
+ }
468
+ return false;
469
+ }
370
470
  getControllers() {
371
471
  return [
372
472
  ...this.controllers
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, 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, 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;
@@ -1,32 +1,48 @@
1
1
  import { METADATA_KEYS } from "../constants.js";
2
- import { getMetadata } from "../metadata.js";
2
+ import { defineMetadata, getMetadata } from "../metadata.js";
3
3
  import { MetadataRegistry } from "../registry/metadata.registry.js";
4
- export function Module(options = {}) {
4
+ export function Global() {
5
5
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
6
6
  return (target)=>{
7
+ const existing = MetadataRegistry.getModuleOptions(target);
7
8
  MetadataRegistry.setModuleOptions(target, {
9
+ ...existing,
10
+ isGlobal: true
11
+ });
12
+ };
13
+ }
14
+ export function Module(options = {}) {
15
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
16
+ return (target)=>{
17
+ const normalized = {
8
18
  imports: options.imports,
9
19
  providers: options.providers,
10
20
  controllers: options.controllers,
11
- exports: options.exports
12
- });
21
+ exports: options.exports,
22
+ isGlobal: options.isGlobal
23
+ };
24
+ // WeakMap store survives MetadataRegistry.clear() — needed for framework modules
25
+ // decorated at import time (e.g. HttpModule, CorsModule).
26
+ defineMetadata(METADATA_KEYS.MODULE_OPTIONS, normalized, target);
27
+ MetadataRegistry.setModuleOptions(target, normalized);
13
28
  };
14
29
  }
15
30
  export function isModule(target) {
16
- return MetadataRegistry.getModuleOptions(target) !== undefined || getMetadata(METADATA_KEYS.MODULE, target) === true;
31
+ return MetadataRegistry.getModuleOptions(target) !== undefined || getMetadata(METADATA_KEYS.MODULE, target) === true || getMetadata(METADATA_KEYS.MODULE_OPTIONS, target) !== undefined;
17
32
  }
18
33
  export function getModuleMetadata(target) {
19
34
  if (!isModule(target)) {
20
35
  return undefined;
21
36
  }
22
- const options = MetadataRegistry.getModuleOptions(target);
23
- if (!options) {
37
+ const options = MetadataRegistry.getModuleOptions(target) ?? getMetadata(METADATA_KEYS.MODULE_OPTIONS, target);
38
+ if (!options || typeof options !== 'object') {
24
39
  return undefined;
25
40
  }
26
41
  return {
27
42
  providers: options.providers ?? [],
28
43
  controllers: options.controllers ?? [],
29
44
  imports: options.imports ?? [],
30
- exports: options.exports ?? []
45
+ exports: options.exports ?? [],
46
+ isGlobal: options.isGlobal === true
31
47
  };
32
48
  }
@@ -1,3 +1,3 @@
1
- export { Module, isModule, getModuleMetadata } from './decorators';
1
+ export { Global, Module, isModule, getModuleMetadata } from './decorators';
2
2
  export { ModuleLoader } from './module-loader';
3
- export type { ModuleOptions, ModuleMetadata, DynamicModule } from './types';
3
+ export type { ModuleOptions, ModuleMetadata, DynamicModule, AsyncModuleOptions, ModuleImport } from './types';
@@ -1,2 +1,2 @@
1
- export { Module, isModule, getModuleMetadata } from "./decorators.js";
1
+ export { Global, Module, isModule, getModuleMetadata } from "./decorators.js";
2
2
  export { ModuleLoader } from "./module-loader.js";
@@ -1,5 +1,6 @@
1
1
  import type { Container } from '../container/container';
2
2
  import type { Token, Type } from '../container/types';
3
+ import type { MiddlewareRouteDefinition } from '../http/middleware-consumer';
3
4
  import type { RouteManager } from '../http/route.manager';
4
5
  export declare class ModuleLoader {
5
6
  private container;
@@ -9,12 +10,19 @@ export declare class ModuleLoader {
9
10
  private collectedControllers;
10
11
  private registeredProviders;
11
12
  private moduleExportsCache;
13
+ private globalExports;
14
+ private consumerMiddlewareDefinitions;
15
+ private appProviderCounter;
16
+ private appProviderTokens;
12
17
  constructor(container: Container, router: RouteManager);
13
18
  load(rootModule: Type): void;
14
19
  private processModule;
15
20
  private registerProvider;
21
+ private isAppToken;
16
22
  private buildExportSet;
17
23
  getControllers(): Type[];
18
24
  getRegisteredProviders(): Token[];
19
- resolveAllInstances(): unknown[];
25
+ getAppProviderTokens(token: Token): Token[];
26
+ getConsumerMiddlewareDefinitions(): MiddlewareRouteDefinition[];
27
+ resolveAllInstances(): Promise<unknown[]>;
20
28
  }