@velajs/vela 0.10.0 → 1.1.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/CHANGELOG.md +113 -0
- package/README.md +36 -2
- package/dist/cache/cache.decorators.d.ts +2 -2
- package/dist/cache/cache.module.d.ts +1 -1
- package/dist/cache/cache.module.js +1 -1
- package/dist/constants.d.ts +29 -26
- package/dist/constants.js +26 -29
- package/dist/container/container.js +2 -2
- package/dist/container/decorators.js +8 -11
- package/dist/container/types.d.ts +1 -0
- package/dist/errors/http-exception.d.ts +21 -20
- package/dist/errors/http-exception.js +6 -6
- package/dist/event-emitter/event-emitter.decorators.js +2 -3
- package/dist/event-emitter/event-emitter.subscriber.js +2 -1
- package/dist/factory.d.ts +0 -1
- package/dist/factory.js +2 -32
- package/dist/fetch/fetch.module.d.ts +2 -2
- package/dist/fetch/fetch.module.js +2 -2
- package/dist/health/health.service.js +6 -2
- package/dist/http/decorators.d.ts +6 -5
- package/dist/http/decorators.js +28 -76
- package/dist/http/execution-context.d.ts +4 -0
- package/dist/http/execution-context.js +15 -0
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.js +1 -1
- package/dist/http/route.manager.d.ts +1 -2
- package/dist/http/route.manager.js +20 -31
- package/dist/http/types.d.ts +0 -1
- package/dist/index.d.ts +4 -10
- package/dist/index.js +7 -12
- package/dist/internal.d.ts +11 -0
- package/dist/internal.js +13 -0
- package/dist/metadata.js +6 -15
- package/dist/module/decorators.d.ts +1 -3
- package/dist/module/decorators.js +8 -20
- package/dist/module/graph.d.ts +10 -0
- package/dist/module/graph.js +35 -0
- package/dist/module/index.d.ts +2 -0
- package/dist/module/index.js +1 -0
- package/dist/{http/middleware-consumer.d.ts → module/middleware.d.ts} +4 -13
- package/dist/{http/middleware-consumer.js → module/middleware.js} +0 -13
- package/dist/module/module-loader.d.ts +1 -1
- package/dist/module/module-loader.js +17 -13
- package/dist/module/types.d.ts +1 -29
- package/dist/openapi/decorators.js +15 -10
- package/dist/openapi/document.js +7 -42
- package/dist/pipeline/app-providers.d.ts +10 -0
- package/dist/pipeline/app-providers.js +43 -0
- package/dist/pipeline/component.manager.d.ts +1 -0
- package/dist/pipeline/component.manager.js +10 -34
- package/dist/pipeline/decorators.d.ts +5 -5
- package/dist/pipeline/decorators.js +1 -9
- package/dist/pipeline/reflector.d.ts +8 -24
- package/dist/pipeline/reflector.js +10 -55
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/metadata.registry.d.ts +20 -15
- package/dist/registry/metadata.registry.js +135 -154
- package/dist/registry/paths.d.ts +3 -0
- package/dist/registry/paths.js +15 -0
- package/dist/registry/types.d.ts +24 -14
- package/dist/registry/types.js +0 -1
- package/dist/registry/util.d.ts +3 -0
- package/dist/registry/util.js +8 -0
- package/dist/schedule/cron-matcher.d.ts +2 -0
- package/dist/schedule/cron-matcher.js +62 -0
- package/dist/schedule/index.d.ts +4 -3
- package/dist/schedule/index.js +2 -2
- package/dist/schedule/schedule.decorators.js +3 -6
- package/dist/schedule/schedule.module.d.ts +2 -6
- package/dist/schedule/schedule.module.js +4 -42
- package/dist/schedule/schedule.registry.js +3 -2
- package/dist/schedule/schedule.tokens.d.ts +0 -3
- package/dist/schedule/schedule.tokens.js +0 -2
- package/dist/schedule/schedule.types.d.ts +0 -3
- package/dist/schedule-node/index.d.ts +2 -0
- package/dist/schedule-node/index.js +2 -0
- package/dist/schedule-node/schedule-node.module.d.ts +4 -0
- package/dist/schedule-node/schedule-node.module.js +18 -0
- package/dist/{schedule → schedule-node}/schedule.executor.d.ts +2 -5
- package/dist/schedule-node/schedule.executor.js +91 -0
- package/dist/services/logger.d.ts +9 -8
- package/dist/services/logger.js +14 -15
- package/dist/throttler/throttler.decorators.d.ts +2 -2
- package/package.json +9 -9
- package/dist/schedule/schedule.executor.js +0 -169
- package/dist/testing/index.d.ts +0 -2
- package/dist/testing/index.js +0 -2
- package/dist/testing/testing.builder.d.ts +0 -29
- package/dist/testing/testing.builder.js +0 -148
- package/dist/testing/testing.module.d.ts +0 -9
- package/dist/testing/testing.module.js +0 -15
|
@@ -3,16 +3,16 @@ import type { ControllerOptions } from './types';
|
|
|
3
3
|
import type { ExecutionContext } from '../pipeline/types';
|
|
4
4
|
/**
|
|
5
5
|
* Marks a class as a controller.
|
|
6
|
-
* Accepts a
|
|
6
|
+
* Accepts a path string or an options object with `path` and `version`.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
10
|
* @Controller('/users')
|
|
11
|
-
* @Controller({
|
|
12
|
-
* @Controller({
|
|
11
|
+
* @Controller({ path: '/users', version: 1 })
|
|
12
|
+
* @Controller({ path: '/users', version: [1, 2] })
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export declare function Controller(
|
|
15
|
+
export declare function Controller(pathOrOptions?: string | ControllerOptions): ClassDecorator;
|
|
16
16
|
/**
|
|
17
17
|
* Override the version for a specific route method.
|
|
18
18
|
*
|
|
@@ -184,5 +184,6 @@ export declare function getRedirect(target: Constructor, method: string | symbol
|
|
|
184
184
|
* handle() { ... }
|
|
185
185
|
* ```
|
|
186
186
|
*/
|
|
187
|
-
export
|
|
187
|
+
export type ComposedDecorator = <T>(target: T, propertyKey?: string | symbol, descriptor?: PropertyDescriptor | number) => void;
|
|
188
|
+
export declare function applyDecorators(...decorators: Array<ClassDecorator | MethodDecorator | PropertyDecorator | ParameterDecorator>): ComposedDecorator;
|
|
188
189
|
export declare function isController(target: Constructor): boolean;
|
package/dist/http/decorators.js
CHANGED
|
@@ -1,43 +1,30 @@
|
|
|
1
|
-
import { HttpMethod,
|
|
2
|
-
import { defineMetadata, getMetadata } from "../metadata.js";
|
|
1
|
+
import { HttpMethod, ParamType, Scope } from "../constants.js";
|
|
3
2
|
import { MetadataRegistry } from "../registry/metadata.registry.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
3
|
+
import { normalizePath } from "../registry/paths.js";
|
|
4
|
+
import { buildExecutionContext } from "./execution-context.js";
|
|
7
5
|
/**
|
|
8
6
|
* Marks a class as a controller.
|
|
9
|
-
* Accepts a
|
|
7
|
+
* Accepts a path string or an options object with `path` and `version`.
|
|
10
8
|
*
|
|
11
9
|
* @example
|
|
12
10
|
* ```ts
|
|
13
11
|
* @Controller('/users')
|
|
14
|
-
* @Controller({
|
|
15
|
-
* @Controller({
|
|
12
|
+
* @Controller({ path: '/users', version: 1 })
|
|
13
|
+
* @Controller({ path: '/users', version: [1, 2] })
|
|
16
14
|
* ```
|
|
17
|
-
*/ export function Controller(
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
15
|
+
*/ export function Controller(pathOrOptions) {
|
|
19
16
|
return (target)=>{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} else if (prefixOrOptions) {
|
|
25
|
-
prefix = prefixOrOptions.path ?? prefixOrOptions.prefix ?? '';
|
|
26
|
-
version = prefixOrOptions.version;
|
|
27
|
-
} else {
|
|
28
|
-
prefix = '';
|
|
29
|
-
}
|
|
30
|
-
MetadataRegistry.setControllerPath(target, normalizePath(prefix));
|
|
17
|
+
const ctor = target;
|
|
18
|
+
const path = typeof pathOrOptions === 'string' ? pathOrOptions : pathOrOptions?.path ?? '';
|
|
19
|
+
const version = typeof pathOrOptions === 'object' ? pathOrOptions?.version : undefined;
|
|
20
|
+
MetadataRegistry.setControllerPath(ctor, normalizePath(path));
|
|
31
21
|
if (version !== undefined) {
|
|
32
|
-
MetadataRegistry.setControllerOptions(
|
|
22
|
+
MetadataRegistry.setControllerOptions(ctor, {
|
|
33
23
|
version
|
|
34
24
|
});
|
|
35
25
|
}
|
|
36
|
-
MetadataRegistry.markInjectable(
|
|
37
|
-
MetadataRegistry.setScope(
|
|
38
|
-
// Keep WeakMap write for external package compat
|
|
39
|
-
defineMetadata(METADATA_KEYS.INJECTABLE, true, target);
|
|
40
|
-
defineMetadata(METADATA_KEYS.SCOPE, Scope.SINGLETON, target);
|
|
26
|
+
MetadataRegistry.markInjectable(ctor);
|
|
27
|
+
MetadataRegistry.setScope(ctor, Scope.SINGLETON);
|
|
41
28
|
};
|
|
42
29
|
}
|
|
43
30
|
/**
|
|
@@ -57,28 +44,25 @@ function normalizePath(path) {
|
|
|
57
44
|
* ```
|
|
58
45
|
*/ export function Version(version) {
|
|
59
46
|
return (target, propertyKey, _descriptor)=>{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// If route was already registered (decorator ran after @Get), patch it
|
|
65
|
-
const routes = MetadataRegistry.getRoutes(target.constructor);
|
|
66
|
-
const route = routes.find((r)=>r.handlerName === propertyKey);
|
|
47
|
+
const ctor = target.constructor;
|
|
48
|
+
MetadataRegistry.setRouteVersion(ctor, propertyKey, version);
|
|
49
|
+
// If route was already registered (decorator ran after @Get), patch it.
|
|
50
|
+
const route = MetadataRegistry.getRoutes(ctor).find((r)=>r.handlerName === propertyKey);
|
|
67
51
|
if (route) {
|
|
68
52
|
route.version = version;
|
|
69
53
|
}
|
|
70
54
|
};
|
|
71
55
|
}
|
|
72
56
|
export function getRouteVersion(target, propertyKey) {
|
|
73
|
-
return MetadataRegistry.getRouteVersion(target, propertyKey)
|
|
57
|
+
return MetadataRegistry.getRouteVersion(target, propertyKey);
|
|
74
58
|
}
|
|
75
59
|
function createMethodDecorator(method) {
|
|
76
60
|
return (path = '')=>{
|
|
77
61
|
return (target, propertyKey, _descriptor)=>{
|
|
62
|
+
const ctor = target.constructor;
|
|
78
63
|
const normalizedPath = normalizePath(path);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
MetadataRegistry.addRoute(target.constructor, {
|
|
64
|
+
const version = MetadataRegistry.getRouteVersion(ctor, propertyKey);
|
|
65
|
+
MetadataRegistry.addRoute(ctor, {
|
|
82
66
|
method: method,
|
|
83
67
|
path: normalizedPath,
|
|
84
68
|
handlerName: propertyKey,
|
|
@@ -229,17 +213,7 @@ export const Cookie = createBuiltinParamDecorator(ParamType.COOKIE);
|
|
|
229
213
|
name: undefined,
|
|
230
214
|
factory: (_unused, ctx)=>{
|
|
231
215
|
const honoCtx = ctx;
|
|
232
|
-
const execCtx =
|
|
233
|
-
getType: ()=>'http',
|
|
234
|
-
getClass: ()=>target.constructor,
|
|
235
|
-
getHandler: ()=>propertyKey,
|
|
236
|
-
getContext: ()=>honoCtx,
|
|
237
|
-
getRequest: ()=>honoCtx.req.raw,
|
|
238
|
-
switchToHttp: ()=>({
|
|
239
|
-
getRequest: ()=>honoCtx.req.raw,
|
|
240
|
-
getResponse: ()=>honoCtx
|
|
241
|
-
})
|
|
242
|
-
};
|
|
216
|
+
const execCtx = buildExecutionContext(honoCtx, target.constructor, propertyKey);
|
|
243
217
|
return factory(data, execCtx);
|
|
244
218
|
},
|
|
245
219
|
...pipes.length > 0 ? {
|
|
@@ -317,37 +291,16 @@ export const Cookie = createBuiltinParamDecorator(ParamType.COOKIE);
|
|
|
317
291
|
}
|
|
318
292
|
// Metadata readers (used by RouteManager)
|
|
319
293
|
export function getHttpCode(target, method) {
|
|
320
|
-
|
|
321
|
-
if (meta?.httpCode !== undefined) return meta.httpCode;
|
|
322
|
-
return getMetadata(METADATA_KEYS.HTTP_CODE, target, method);
|
|
294
|
+
return MetadataRegistry.getHandlerHttpMeta(target, method)?.httpCode;
|
|
323
295
|
}
|
|
324
296
|
export function getResponseHeaders(target, method) {
|
|
325
|
-
|
|
326
|
-
if (meta?.responseHeaders) return meta.responseHeaders;
|
|
327
|
-
return getMetadata(METADATA_KEYS.RESPONSE_HEADERS, target, method) ?? [];
|
|
297
|
+
return MetadataRegistry.getHandlerHttpMeta(target, method)?.responseHeaders ?? [];
|
|
328
298
|
}
|
|
329
299
|
export function getRedirect(target, method) {
|
|
330
|
-
|
|
331
|
-
if (meta?.redirect) return meta.redirect;
|
|
332
|
-
return getMetadata(METADATA_KEYS.REDIRECT, target, method);
|
|
300
|
+
return MetadataRegistry.getHandlerHttpMeta(target, method)?.redirect;
|
|
333
301
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
* matching how stacked decorators behave when written separately.
|
|
337
|
-
*
|
|
338
|
-
* @example
|
|
339
|
-
* ```ts
|
|
340
|
-
* const Auth = (...roles: string[]) => applyDecorators(
|
|
341
|
-
* UseGuards(JwtGuard, RolesGuard),
|
|
342
|
-
* SetMetadata('roles', roles),
|
|
343
|
-
* );
|
|
344
|
-
*
|
|
345
|
-
* @Auth('admin')
|
|
346
|
-
* @Get('/admin')
|
|
347
|
-
* handle() { ... }
|
|
348
|
-
* ```
|
|
349
|
-
*/ export function applyDecorators(...decorators) {
|
|
350
|
-
const composed = (target, propertyKey, descriptor)=>{
|
|
302
|
+
export function applyDecorators(...decorators) {
|
|
303
|
+
return (target, propertyKey, descriptor)=>{
|
|
351
304
|
for (const decorator of decorators){
|
|
352
305
|
if (propertyKey === undefined && typeof descriptor !== 'number') {
|
|
353
306
|
decorator(target);
|
|
@@ -358,7 +311,6 @@ export function getRedirect(target, method) {
|
|
|
358
311
|
}
|
|
359
312
|
}
|
|
360
313
|
};
|
|
361
|
-
return composed;
|
|
362
314
|
}
|
|
363
315
|
// Helpers
|
|
364
316
|
export function isController(target) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import type { Type } from '../container/types';
|
|
3
|
+
import type { ExecutionContext } from '../pipeline/types';
|
|
4
|
+
export declare function buildExecutionContext(c: Context, controller: Type, handlerName: string | symbol): ExecutionContext;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Single source of ExecutionContext shape — used by the route pipeline AND
|
|
2
|
+
// by createParamDecorator's deferred factory call.
|
|
3
|
+
export function buildExecutionContext(c, controller, handlerName) {
|
|
4
|
+
return {
|
|
5
|
+
getType: ()=>'http',
|
|
6
|
+
getClass: ()=>controller,
|
|
7
|
+
getHandler: ()=>handlerName,
|
|
8
|
+
getContext: ()=>c,
|
|
9
|
+
getRequest: ()=>c.req.raw,
|
|
10
|
+
switchToHttp: ()=>({
|
|
11
|
+
getRequest: ()=>c.req.raw,
|
|
12
|
+
getResponse: ()=>c
|
|
13
|
+
})
|
|
14
|
+
};
|
|
15
|
+
}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { RouteManager } from './route.manager';
|
|
2
2
|
export type { RouteManagerOptions } from './route.manager';
|
|
3
|
-
export { MiddlewareBuilder
|
|
4
|
-
export type { MiddlewareConsumer, MiddlewareConfigProxy, RouteInfo, NestModule, MiddlewareRouteDefinition } from '
|
|
3
|
+
export { MiddlewareBuilder } from '../module/middleware';
|
|
4
|
+
export type { MiddlewareConsumer, MiddlewareConfigProxy, RouteInfo, NestModule, MiddlewareRouteDefinition } from '../module/middleware';
|
|
5
5
|
export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, applyDecorators, isController, } from './decorators';
|
|
6
6
|
export type { RouteMetadata, ControllerMetadata, ControllerOptions, ParamMetadata, ControllerRegistration, } from './types';
|
package/dist/http/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { RouteManager } from "./route.manager.js";
|
|
2
|
-
export { MiddlewareBuilder
|
|
2
|
+
export { MiddlewareBuilder } from "../module/middleware.js";
|
|
3
3
|
export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, All, Sse, Param, Query, Body, Headers, Req, Res, Ip, Cookie, Cookies, RawBody, HttpCode, Header, Redirect, createParamDecorator, applyDecorators, isController } from "./decorators.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Context, type MiddlewareHandler, 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 '
|
|
4
|
+
import type { MiddlewareRouteDefinition } from '../module/middleware';
|
|
5
5
|
import type { CanActivate, ExceptionFilter, NestInterceptor, NestMiddleware, PipeTransform } from '../pipeline/types';
|
|
6
6
|
import type { FilterType, GuardType, InterceptorType, MiddlewareType, PipeType } from '../registry/types';
|
|
7
7
|
import type { ControllerRegistration } from './types';
|
|
@@ -49,7 +49,6 @@ export declare class RouteManager {
|
|
|
49
49
|
private createResponse;
|
|
50
50
|
private registerRoute;
|
|
51
51
|
private buildVersionedPaths;
|
|
52
|
-
private joinPaths;
|
|
53
52
|
private compilePathMatcher;
|
|
54
53
|
private compileRouteMatcher;
|
|
55
54
|
getControllers(): ControllerRegistration[];
|
|
@@ -2,7 +2,8 @@ import { Hono } from "hono";
|
|
|
2
2
|
import { getCookie } from "hono/cookie";
|
|
3
3
|
import { HttpMethod, ParamType } from "../constants.js";
|
|
4
4
|
import { getMetadata } from "../metadata.js";
|
|
5
|
-
import {
|
|
5
|
+
import { joinPaths } from "../registry/paths.js";
|
|
6
|
+
import { buildExecutionContext } from "./execution-context.js";
|
|
6
7
|
import { ForbiddenException, HttpException } from "../errors/http-exception.js";
|
|
7
8
|
import { ComponentManager } from "../pipeline/component.manager.js";
|
|
8
9
|
import { shouldFilterCatch } from "../pipeline/decorators.js";
|
|
@@ -50,7 +51,7 @@ export class RouteManager {
|
|
|
50
51
|
],
|
|
51
52
|
[
|
|
52
53
|
HttpMethod.HEAD,
|
|
53
|
-
(app, p, h)=>app.get(p, h)
|
|
54
|
+
(app, p, h)=>app.get(p, (c, next)=>c.req.method === 'HEAD' ? h(c) : next())
|
|
54
55
|
],
|
|
55
56
|
[
|
|
56
57
|
HttpMethod.ALL,
|
|
@@ -175,11 +176,6 @@ export class RouteManager {
|
|
|
175
176
|
instantiateMany(items, container) {
|
|
176
177
|
return items.map((item)=>this.instantiate(item, container));
|
|
177
178
|
}
|
|
178
|
-
// Resolve middleware priority at build time. Supports three sources:
|
|
179
|
-
// 1. static priority on the class constructor
|
|
180
|
-
// 2. priority property on the instance
|
|
181
|
-
// 3. for container tokens, resolve and inspect the instance (+ its ctor)
|
|
182
|
-
// Falls back to 0 on any error or when no priority is set.
|
|
183
179
|
getMiddlewarePriority(entry) {
|
|
184
180
|
if (entry == null) return 0;
|
|
185
181
|
if (typeof entry === 'function') {
|
|
@@ -306,31 +302,25 @@ export class RouteManager {
|
|
|
306
302
|
await buildCrudRoutes(app, controller, metadata.prefix, crudConfig, {
|
|
307
303
|
globalPrefix: this.globalPrefix,
|
|
308
304
|
globalGuards: this.instantiateMany(this.globalGuards, this.container),
|
|
309
|
-
joinPaths
|
|
305
|
+
joinPaths
|
|
306
|
+
});
|
|
307
|
+
} catch (err) {
|
|
308
|
+
throw new Error(`@Crud() requires '@velajs/crud'. Install it: pnpm add @velajs/crud`, {
|
|
309
|
+
cause: err
|
|
310
310
|
});
|
|
311
|
-
} catch {
|
|
312
|
-
throw new Error(`@Crud() requires '@velajs/crud'. Install it: bun add @velajs/crud`);
|
|
313
311
|
}
|
|
314
312
|
}
|
|
315
313
|
}
|
|
316
314
|
return app;
|
|
317
315
|
}
|
|
318
316
|
createExecutionContext(c, controller, route) {
|
|
319
|
-
return
|
|
320
|
-
getType: ()=>'http',
|
|
321
|
-
getClass: ()=>controller,
|
|
322
|
-
getHandler: ()=>route.handlerName,
|
|
323
|
-
getContext: ()=>c,
|
|
324
|
-
getRequest: ()=>c.req.raw,
|
|
325
|
-
switchToHttp: ()=>({
|
|
326
|
-
getRequest: ()=>c.req.raw,
|
|
327
|
-
getResponse: ()=>c
|
|
328
|
-
})
|
|
329
|
-
};
|
|
317
|
+
return buildExecutionContext(c, controller, route.handlerName);
|
|
330
318
|
}
|
|
331
319
|
createHandler(route, controller, allParamMetadata) {
|
|
332
320
|
const paramMetadata = (allParamMetadata.get(route.handlerName) || []).sort((a, b)=>a.index - b.index);
|
|
333
|
-
// Read param types once at build time for metatype population
|
|
321
|
+
// Read param types once at build time for metatype population.
|
|
322
|
+
// Routed via Reflect so the polyfill funnels both src-level and dist-level
|
|
323
|
+
// consumers to the same registry (matters in tests that import from dist).
|
|
334
324
|
const paramTypes = Reflect.getMetadata('design:paramtypes', controller.prototype, route.handlerName);
|
|
335
325
|
// Collect controller + method level components at build time
|
|
336
326
|
const methodGuards = ComponentManager.getComponents('guard', controller, route.handlerName);
|
|
@@ -475,12 +465,16 @@ export class RouteManager {
|
|
|
475
465
|
registerRoute(app, method, path, handler) {
|
|
476
466
|
const normalizedPath = path || '/';
|
|
477
467
|
const registrar = RouteManager.METHOD_REGISTRAR.get(method);
|
|
478
|
-
|
|
468
|
+
if (registrar) {
|
|
469
|
+
registrar(app, normalizedPath, handler);
|
|
470
|
+
} else {
|
|
471
|
+
app.on(method, normalizedPath, handler);
|
|
472
|
+
}
|
|
479
473
|
}
|
|
480
474
|
buildVersionedPaths(globalPrefix, controllerPrefix, routePath, version) {
|
|
481
475
|
if (version === undefined) {
|
|
482
476
|
return [
|
|
483
|
-
|
|
477
|
+
joinPaths(globalPrefix, joinPaths(controllerPrefix, routePath))
|
|
484
478
|
];
|
|
485
479
|
}
|
|
486
480
|
const versions = Array.isArray(version) ? version : [
|
|
@@ -488,14 +482,9 @@ export class RouteManager {
|
|
|
488
482
|
];
|
|
489
483
|
return versions.map((v)=>{
|
|
490
484
|
const versionSegment = `/v${v}`;
|
|
491
|
-
return
|
|
485
|
+
return joinPaths(globalPrefix, joinPaths(versionSegment, joinPaths(controllerPrefix, routePath)));
|
|
492
486
|
});
|
|
493
487
|
}
|
|
494
|
-
joinPaths(prefix, path) {
|
|
495
|
-
const cleanPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
|
|
496
|
-
const cleanPath = path && !path.startsWith('/') ? `/${path}` : path;
|
|
497
|
-
return `${cleanPrefix}${cleanPath}` || '/';
|
|
498
|
-
}
|
|
499
488
|
compilePathMatcher(routePath) {
|
|
500
489
|
if (routePath === '*') return ()=>true;
|
|
501
490
|
const norm = routePath.startsWith('/') ? routePath : `/${routePath}`;
|
|
@@ -510,7 +499,7 @@ export class RouteManager {
|
|
|
510
499
|
const matchPath = this.compilePathMatcher(route.path);
|
|
511
500
|
return (path, method)=>{
|
|
512
501
|
if (!matchPath(path)) return false;
|
|
513
|
-
if (route.method && route.method !==
|
|
502
|
+
if (route.method && route.method !== HttpMethod.ALL) return method === route.method;
|
|
514
503
|
return true;
|
|
515
504
|
};
|
|
516
505
|
});
|
package/dist/http/types.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './metadata';
|
|
2
2
|
export { defineMetadata, getMetadata } from './metadata';
|
|
3
|
-
export { VelaFactory
|
|
3
|
+
export { VelaFactory } from './factory';
|
|
4
4
|
export { VelaApplication } from './application';
|
|
5
5
|
export { createOpenApiDocument, ApiDoc, ApiTags, ApiResponse, zodToJsonSchema, } from './openapi/index';
|
|
6
6
|
export type { OpenApiDocument, OpenApiInfo, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiRequestBody, OpenApiResponse, ApiDocMetadata, ApiResponseEntry, ApiResponseOptions, CreateOpenApiDocumentOptions, HttpVerb, JsonSchema, } from './openapi/index';
|
|
@@ -20,15 +20,14 @@ export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, CacheKey
|
|
|
20
20
|
export type { CacheModuleOptions, CacheStore, CacheEntry } from './cache/index';
|
|
21
21
|
export { EventEmitterModule, EventEmitter, EventEmitterSubscriber, OnEvent, ON_EVENT_METADATA, } from './event-emitter/index';
|
|
22
22
|
export type { EventHandler, OnEventMetadata } from './event-emitter/index';
|
|
23
|
-
export { ScheduleModule, ScheduleRegistry,
|
|
24
|
-
export type { RegisteredCronJob, RegisteredIntervalJob, CronMetadata, IntervalMetadata,
|
|
23
|
+
export { ScheduleModule, ScheduleRegistry, Cron, Interval, parseCron, CRON_METADATA, INTERVAL_METADATA, } from './schedule/index';
|
|
24
|
+
export type { RegisteredCronJob, RegisteredIntervalJob, CronMetadata, IntervalMetadata, CronMatcher, } from './schedule/index';
|
|
25
25
|
export { HealthModule, HealthCheckService, HealthIndicatorService, HttpHealthIndicator, } from './health/index';
|
|
26
26
|
export type { HealthCheckResult, HealthCheckStatus, HealthIndicatorResult, HealthIndicatorFunction, ResponseCheckCallback, HttpPingOptions, } from './health/index';
|
|
27
27
|
export { ThrottlerModule, ThrottlerGuard, ThrottlerStorage, Throttle, SkipThrottle, THROTTLER_OPTIONS, THROTTLER_STORAGE, THROTTLE_METADATA, SKIP_THROTTLE_METADATA, } from './throttler/index';
|
|
28
28
|
export type { ThrottlerModuleOptions, ThrottleConfig, ThrottlerStore, ThrottlerStorageRecord, RateLimitInfo, } from './throttler/index';
|
|
29
29
|
export { Global, Module, createModuleRef } from './module/index';
|
|
30
30
|
export type { ModuleOptions, DynamicModule, AsyncModuleOptions, ModuleImport } from './module/index';
|
|
31
|
-
export { RequestMethod } from './http/index';
|
|
32
31
|
export type { MiddlewareConsumer, NestModule, RouteInfo } from './http/index';
|
|
33
32
|
export { UseMiddleware, UseGuards, UsePipes, UseInterceptors, UseFilters, Catch, SetMetadata, Reflector, APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE, } from './pipeline/index';
|
|
34
33
|
export type { HttpArgumentsHost, ExecutionContext, CanActivate, CallHandler, NestInterceptor, NestMiddleware, PipeTransform, ExceptionFilter, ArgumentMetadata, ReflectableDecorator, CreateDecoratorOptions, } from './pipeline/index';
|
|
@@ -37,13 +36,8 @@ export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, ParseUUIDPipe, ParseEnumPi
|
|
|
37
36
|
export type { ParseUUIDPipeOptions, ParseArrayPipeOptions } from './pipeline/index';
|
|
38
37
|
export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, MethodNotAllowedException, NotAcceptableException, RequestTimeoutException, ConflictException, GoneException, PayloadTooLargeException, UnsupportedMediaTypeException, UnprocessableEntityException, TooManyRequestsException, InternalServerErrorException, NotImplementedException, BadGatewayException, ServiceUnavailableException, GatewayTimeoutException, } from './errors/index';
|
|
39
38
|
export type { OnModuleInit, OnApplicationBootstrap, OnModuleDestroy, OnApplicationShutdown, BeforeApplicationShutdown, } from './lifecycle/index';
|
|
40
|
-
export { MetadataRegistry } from './registry/
|
|
41
|
-
export { RouteManager } from './http/index';
|
|
42
|
-
export type { RouteManagerOptions } from './http/index';
|
|
43
|
-
export { ModuleLoader } from './module/index';
|
|
44
|
-
export { ComponentManager } from './pipeline/index';
|
|
39
|
+
export { MetadataRegistry } from './registry/metadata.registry';
|
|
45
40
|
export { createZodDto, ValidationPipe } from './validation/index';
|
|
46
41
|
export type { CreateZodDtoOptions } from './validation/index';
|
|
47
42
|
export { Serialize, SerializerInterceptor, SERIALIZE_METADATA } from './serialization/index';
|
|
48
|
-
export { Test, TestingModule, TestingModuleBuilder } from './testing/index';
|
|
49
43
|
export { getRuntimeKey, env } from 'hono/adapter';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./metadata.js";
|
|
2
2
|
export { defineMetadata, getMetadata } from "./metadata.js";
|
|
3
3
|
// Factory & Application
|
|
4
|
-
export { VelaFactory
|
|
4
|
+
export { VelaFactory } from "./factory.js";
|
|
5
5
|
export { VelaApplication } from "./application.js";
|
|
6
6
|
// OpenAPI
|
|
7
7
|
export { createOpenApiDocument, ApiDoc, ApiTags, ApiResponse, zodToJsonSchema } from "./openapi/index.js";
|
|
@@ -24,32 +24,27 @@ export { CacheModule, CacheService, CacheInterceptor, MemoryCacheStore, CacheKey
|
|
|
24
24
|
// Event Emitter
|
|
25
25
|
export { EventEmitterModule, EventEmitter, EventEmitterSubscriber, OnEvent, ON_EVENT_METADATA } from "./event-emitter/index.js";
|
|
26
26
|
// Schedule
|
|
27
|
-
export { ScheduleModule, ScheduleRegistry,
|
|
27
|
+
export { ScheduleModule, ScheduleRegistry, Cron, Interval, parseCron, CRON_METADATA, INTERVAL_METADATA } from "./schedule/index.js";
|
|
28
28
|
// Health
|
|
29
29
|
export { HealthModule, HealthCheckService, HealthIndicatorService, HttpHealthIndicator } from "./health/index.js";
|
|
30
30
|
// Throttler
|
|
31
31
|
export { ThrottlerModule, ThrottlerGuard, ThrottlerStorage, Throttle, SkipThrottle, THROTTLER_OPTIONS, THROTTLER_STORAGE, THROTTLE_METADATA, SKIP_THROTTLE_METADATA } from "./throttler/index.js";
|
|
32
32
|
// Module
|
|
33
33
|
export { Global, Module, createModuleRef } from "./module/index.js";
|
|
34
|
-
export { RequestMethod } from "./http/index.js";
|
|
35
34
|
// Pipeline Decorators
|
|
36
35
|
export { UseMiddleware, UseGuards, UsePipes, UseInterceptors, UseFilters, Catch, SetMetadata, Reflector, APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE } from "./pipeline/index.js";
|
|
37
36
|
// Built-in Pipes
|
|
38
37
|
export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, ParseUUIDPipe, ParseEnumPipe, ParseArrayPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe } from "./pipeline/index.js";
|
|
39
38
|
// Errors
|
|
40
39
|
export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, MethodNotAllowedException, NotAcceptableException, RequestTimeoutException, ConflictException, GoneException, PayloadTooLargeException, UnsupportedMediaTypeException, UnprocessableEntityException, TooManyRequestsException, InternalServerErrorException, NotImplementedException, BadGatewayException, ServiceUnavailableException, GatewayTimeoutException } from "./errors/index.js";
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
export {
|
|
45
|
-
export { ModuleLoader } from "./module/index.js";
|
|
46
|
-
// Component Manager (for advanced usage)
|
|
47
|
-
export { ComponentManager } from "./pipeline/index.js";
|
|
40
|
+
// MetadataRegistry — the central decoration store. Test setup typically
|
|
41
|
+
// uses `MetadataRegistry.clear()` between cases. Internal primitives like
|
|
42
|
+
// RouteManager/ModuleLoader/ComponentManager live only at @velajs/vela/internal.
|
|
43
|
+
export { MetadataRegistry } from "./registry/metadata.registry.js";
|
|
48
44
|
// Validation
|
|
49
45
|
export { createZodDto, ValidationPipe } from "./validation/index.js";
|
|
50
46
|
// Serialization
|
|
51
47
|
export { Serialize, SerializerInterceptor, SERIALIZE_METADATA } from "./serialization/index.js";
|
|
52
|
-
// Testing
|
|
53
|
-
export { Test, TestingModule, TestingModuleBuilder } from "./testing/index.js";
|
|
48
|
+
// Testing utilities live in @velajs/testing — see https://github.com/velajs/testing
|
|
54
49
|
// Hono Adapter Utilities
|
|
55
50
|
export { getRuntimeKey, env } from "hono/adapter";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { Container } from './container/container';
|
|
2
|
+
export { ModuleRef } from './container/module-ref';
|
|
3
|
+
export { bindAppProviders } from './pipeline/app-providers';
|
|
4
|
+
export { RouteManager } from './http/route.manager';
|
|
5
|
+
export type { RouteManagerOptions } from './http/route.manager';
|
|
6
|
+
export { ModuleLoader } from './module/module-loader';
|
|
7
|
+
export { ComponentManager } from './pipeline/component.manager';
|
|
8
|
+
export { VelaApplication } from './application';
|
|
9
|
+
export { MetadataRegistry } from './registry/metadata.registry';
|
|
10
|
+
export { APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE, } from './pipeline/tokens';
|
|
11
|
+
export { getModuleMetadata, isModule } from './module/decorators';
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Internal framework primitives — exposed for first-party consumers like
|
|
2
|
+
// @velajs/testing and advanced integration. Not covered by semver guarantees
|
|
3
|
+
// to the same degree as the public surface (./index).
|
|
4
|
+
export { Container } from "./container/container.js";
|
|
5
|
+
export { ModuleRef } from "./container/module-ref.js";
|
|
6
|
+
export { bindAppProviders } from "./pipeline/app-providers.js";
|
|
7
|
+
export { RouteManager } from "./http/route.manager.js";
|
|
8
|
+
export { ModuleLoader } from "./module/module-loader.js";
|
|
9
|
+
export { ComponentManager } from "./pipeline/component.manager.js";
|
|
10
|
+
export { VelaApplication } from "./application.js";
|
|
11
|
+
export { MetadataRegistry } from "./registry/metadata.registry.js";
|
|
12
|
+
export { APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE } from "./pipeline/tokens.js";
|
|
13
|
+
export { getModuleMetadata, isModule } from "./module/decorators.js";
|
package/dist/metadata.js
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
function compositeKey(key, prop) {
|
|
6
|
-
return prop !== undefined ? `${key}\0${String(prop)}` : key;
|
|
7
|
-
}
|
|
1
|
+
// Single funnel: every Reflect.* metadata write/read routes into MetadataRegistry.
|
|
2
|
+
// SWC emits Reflect.metadata('design:paramtypes', ...) calls in compiled code;
|
|
3
|
+
// the polyfill catches those and parks them in the registry alongside vela's typed slots.
|
|
4
|
+
import { MetadataRegistry } from "./registry/metadata.registry.js";
|
|
8
5
|
export function defineMetadata(key, value, target, propertyKey) {
|
|
9
|
-
|
|
10
|
-
if (!map) {
|
|
11
|
-
map = new Map();
|
|
12
|
-
store.set(target, map);
|
|
13
|
-
}
|
|
14
|
-
map.set(compositeKey(key, propertyKey), value);
|
|
6
|
+
MetadataRegistry.setReflectMetadata(target, key, value, propertyKey);
|
|
15
7
|
}
|
|
16
8
|
export function getMetadata(key, target, propertyKey) {
|
|
17
|
-
return
|
|
9
|
+
return MetadataRegistry.getReflectMetadata(target, key, propertyKey);
|
|
18
10
|
}
|
|
19
|
-
// Minimal Reflect polyfill so the compiler's `Reflect.metadata(...)` calls work.
|
|
20
11
|
if (typeof Reflect.defineMetadata !== 'function') {
|
|
21
12
|
Reflect.defineMetadata = defineMetadata;
|
|
22
13
|
Reflect.getMetadata = getMetadata;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { Constructor } from '../registry/types';
|
|
2
|
-
import type { Type } from '../container/types';
|
|
3
|
-
import type { ModuleMetadata, ModuleOptions } from './types';
|
|
1
|
+
import type { Constructor, ModuleMetadata, ModuleOptions, Type } from '../registry/types';
|
|
4
2
|
export declare function Global(): ClassDecorator;
|
|
5
3
|
export declare function Module(options?: ModuleOptions): ClassDecorator;
|
|
6
4
|
export declare function isModule(target: Constructor): boolean;
|
|
@@ -1,34 +1,27 @@
|
|
|
1
|
-
import { METADATA_KEYS } from "../constants.js";
|
|
2
|
-
import { defineMetadata, getMetadata } from "../metadata.js";
|
|
3
1
|
import { MetadataRegistry } from "../registry/metadata.registry.js";
|
|
4
2
|
export function Global() {
|
|
5
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
6
3
|
return (target)=>{
|
|
7
|
-
const
|
|
8
|
-
MetadataRegistry.
|
|
4
|
+
const ctor = target;
|
|
5
|
+
const existing = MetadataRegistry.getModuleOptions(ctor);
|
|
6
|
+
MetadataRegistry.setModuleOptions(ctor, {
|
|
9
7
|
...existing,
|
|
10
8
|
isGlobal: true
|
|
11
9
|
});
|
|
12
10
|
};
|
|
13
11
|
}
|
|
14
12
|
export function Module(options = {}) {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
16
13
|
return (target)=>{
|
|
17
|
-
|
|
14
|
+
MetadataRegistry.setModuleOptions(target, {
|
|
18
15
|
imports: options.imports,
|
|
19
16
|
providers: options.providers,
|
|
20
17
|
controllers: options.controllers,
|
|
21
18
|
exports: options.exports,
|
|
22
19
|
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);
|
|
20
|
+
});
|
|
28
21
|
};
|
|
29
22
|
}
|
|
30
23
|
export function isModule(target) {
|
|
31
|
-
return MetadataRegistry.getModuleOptions(target) !== undefined
|
|
24
|
+
return MetadataRegistry.getModuleOptions(target) !== undefined;
|
|
32
25
|
}
|
|
33
26
|
export function createModuleRef(name) {
|
|
34
27
|
const moduleClass = class {
|
|
@@ -39,13 +32,8 @@ export function createModuleRef(name) {
|
|
|
39
32
|
return moduleClass;
|
|
40
33
|
}
|
|
41
34
|
export function getModuleMetadata(target) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
const options = MetadataRegistry.getModuleOptions(target) ?? getMetadata(METADATA_KEYS.MODULE_OPTIONS, target);
|
|
46
|
-
if (!options || typeof options !== 'object') {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
35
|
+
const options = MetadataRegistry.getModuleOptions(target);
|
|
36
|
+
if (!options) return undefined;
|
|
49
37
|
return {
|
|
50
38
|
providers: options.providers ?? [],
|
|
51
39
|
controllers: options.controllers ?? [],
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Type } from '../container/types';
|
|
2
|
+
/**
|
|
3
|
+
* Walks the module dependency graph from a root, unwrapping ForwardRef and
|
|
4
|
+
* dynamic-module imports along the way, and returns every controller
|
|
5
|
+
* reachable from it. Pure metadata read — no Container, no side effects.
|
|
6
|
+
*
|
|
7
|
+
* Used by createOpenApiDocument and any other consumer that needs a
|
|
8
|
+
* controller list without bootstrapping the application.
|
|
9
|
+
*/
|
|
10
|
+
export declare function collectControllers(rootModule: Type): Type[];
|