@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.
- package/dist/cache/cache.module.d.ts +4 -1
- package/dist/cache/cache.module.js +51 -9
- package/dist/config/config.module.d.ts +4 -1
- package/dist/config/config.module.js +40 -3
- package/dist/config/config.types.d.ts +1 -0
- package/dist/constants.d.ts +6 -1
- package/dist/constants.js +5 -0
- package/dist/container/container.d.ts +4 -0
- package/dist/container/container.js +52 -15
- package/dist/container/decorators.d.ts +3 -1
- package/dist/container/decorators.js +27 -6
- package/dist/container/index.d.ts +4 -2
- package/dist/container/index.js +4 -2
- package/dist/container/mixin.d.ts +24 -0
- package/dist/container/mixin.js +26 -0
- package/dist/container/module-ref.d.ts +21 -0
- package/dist/container/module-ref.js +48 -0
- package/dist/container/types.d.ts +10 -3
- package/dist/container/types.js +9 -0
- package/dist/cors/cors.module.js +2 -2
- package/dist/factory.js +36 -13
- package/dist/fetch/fetch.module.d.ts +6 -0
- package/dist/fetch/fetch.module.js +77 -0
- package/dist/fetch/fetch.service.d.ts +24 -0
- package/dist/fetch/fetch.service.js +145 -0
- package/dist/fetch/fetch.types.d.ts +24 -0
- package/dist/fetch/fetch.types.js +1 -0
- package/dist/fetch/index.d.ts +3 -0
- package/dist/fetch/index.js +2 -0
- package/dist/http/decorators.d.ts +64 -0
- package/dist/http/decorators.js +89 -1
- package/dist/http/index.d.ts +3 -1
- package/dist/http/index.js +2 -1
- package/dist/http/middleware-consumer.d.ts +36 -0
- package/dist/http/middleware-consumer.js +71 -0
- package/dist/http/route.manager.d.ts +13 -1
- package/dist/http/route.manager.js +153 -53
- package/dist/index.d.ts +11 -6
- package/dist/index.js +7 -4
- package/dist/metadata.d.ts +1 -1
- package/dist/module/decorators.d.ts +1 -0
- package/dist/module/decorators.js +24 -8
- package/dist/module/index.d.ts +2 -2
- package/dist/module/index.js +1 -1
- package/dist/module/module-loader.d.ts +9 -1
- package/dist/module/module-loader.js +107 -11
- package/dist/module/types.d.ts +13 -3
- package/dist/pipeline/index.d.ts +3 -2
- package/dist/pipeline/index.js +1 -1
- package/dist/pipeline/pipes.d.ts +22 -0
- package/dist/pipeline/pipes.js +50 -0
- package/dist/pipeline/tokens.d.ts +1 -1
- package/dist/pipeline/tokens.js +1 -1
- package/dist/pipeline/types.d.ts +16 -0
- package/dist/registry/metadata.registry.d.ts +7 -6
- package/dist/registry/metadata.registry.js +13 -0
- package/dist/registry/types.d.ts +1 -0
- package/dist/schedule/schedule.executor.d.ts +11 -2
- package/dist/schedule/schedule.executor.js +134 -19
- package/dist/schedule/schedule.module.d.ts +4 -1
- package/dist/schedule/schedule.module.js +39 -7
- package/dist/testing/testing.builder.js +31 -17
- package/dist/throttler/throttler.module.d.ts +2 -1
- package/dist/throttler/throttler.module.js +47 -9
- 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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
51
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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
|
|
69
|
-
|
|
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 (
|
|
72
|
-
return
|
|
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
|
-
|
|
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)=>
|
|
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
|
|
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
|
|
115
|
-
app.use(fullPath, (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(
|
|
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',
|
|
153
|
-
//
|
|
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
|
|
163
|
-
...
|
|
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
|
-
...
|
|
242
|
+
...this.instantiateMany(this.globalGuards, requestContainer),
|
|
243
|
+
...this.instantiateMany(methodGuards, requestContainer)
|
|
177
244
|
];
|
|
178
245
|
const pipes = [
|
|
179
|
-
...this.globalPipes,
|
|
180
|
-
...
|
|
246
|
+
...this.instantiateMany(this.globalPipes, requestContainer),
|
|
247
|
+
...this.instantiateMany(methodPipes, requestContainer)
|
|
181
248
|
];
|
|
182
249
|
const interceptors = [
|
|
183
|
-
...this.globalInterceptors,
|
|
184
|
-
...
|
|
250
|
+
...this.instantiateMany(this.globalInterceptors, requestContainer),
|
|
251
|
+
...this.instantiateMany(methodInterceptors, requestContainer)
|
|
185
252
|
];
|
|
186
253
|
const filters = [
|
|
187
|
-
...
|
|
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)
|
package/dist/metadata.d.ts
CHANGED
|
@@ -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):
|
|
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
|
|
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
|
}
|
package/dist/module/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/module/index.js
CHANGED
|
@@ -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
|
-
|
|
25
|
+
getAppProviderTokens(token: Token): Token[];
|
|
26
|
+
getConsumerMiddlewareDefinitions(): MiddlewareRouteDefinition[];
|
|
27
|
+
resolveAllInstances(): Promise<unknown[]>;
|
|
20
28
|
}
|