@velajs/vela 0.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +84 -0
  4. package/dist/application.d.ts +44 -0
  5. package/dist/application.js +112 -0
  6. package/dist/constants.d.ts +35 -0
  7. package/dist/constants.js +43 -0
  8. package/dist/container/container.d.ts +25 -0
  9. package/dist/container/container.js +195 -0
  10. package/dist/container/decorators.d.ts +8 -0
  11. package/dist/container/decorators.js +36 -0
  12. package/dist/container/index.d.ts +4 -0
  13. package/dist/container/index.js +3 -0
  14. package/dist/container/types.d.ts +37 -0
  15. package/dist/container/types.js +11 -0
  16. package/dist/errors/http-exception.d.ts +61 -0
  17. package/dist/errors/http-exception.js +128 -0
  18. package/dist/errors/index.d.ts +1 -0
  19. package/dist/errors/index.js +1 -0
  20. package/dist/factory.d.ts +5 -0
  21. package/dist/factory.js +39 -0
  22. package/dist/http/decorators.d.ts +122 -0
  23. package/dist/http/decorators.js +276 -0
  24. package/dist/http/index.d.ts +3 -0
  25. package/dist/http/index.js +2 -0
  26. package/dist/http/route.manager.d.ts +34 -0
  27. package/dist/http/route.manager.js +373 -0
  28. package/dist/http/types.d.ts +29 -0
  29. package/dist/http/types.js +1 -0
  30. package/dist/index.d.ts +20 -0
  31. package/dist/index.js +26 -0
  32. package/dist/lifecycle/index.d.ts +20 -0
  33. package/dist/lifecycle/index.js +15 -0
  34. package/dist/metadata.d.ts +10 -0
  35. package/dist/metadata.js +29 -0
  36. package/dist/module/decorators.d.ts +5 -0
  37. package/dist/module/decorators.js +32 -0
  38. package/dist/module/index.d.ts +3 -0
  39. package/dist/module/index.js +2 -0
  40. package/dist/module/module-loader.d.ts +20 -0
  41. package/dist/module/module-loader.js +159 -0
  42. package/dist/module/types.d.ts +19 -0
  43. package/dist/module/types.js +1 -0
  44. package/dist/pipeline/component.manager.d.ts +18 -0
  45. package/dist/pipeline/component.manager.js +105 -0
  46. package/dist/pipeline/decorators.d.ts +10 -0
  47. package/dist/pipeline/decorators.js +50 -0
  48. package/dist/pipeline/index.d.ts +7 -0
  49. package/dist/pipeline/index.js +5 -0
  50. package/dist/pipeline/pipes.d.ts +25 -0
  51. package/dist/pipeline/pipes.js +52 -0
  52. package/dist/pipeline/reflector.d.ts +102 -0
  53. package/dist/pipeline/reflector.js +166 -0
  54. package/dist/pipeline/tokens.d.ts +33 -0
  55. package/dist/pipeline/tokens.js +27 -0
  56. package/dist/pipeline/types.d.ts +31 -0
  57. package/dist/pipeline/types.js +1 -0
  58. package/dist/registry/index.d.ts +2 -0
  59. package/dist/registry/index.js +1 -0
  60. package/dist/registry/metadata.registry.d.ts +61 -0
  61. package/dist/registry/metadata.registry.js +276 -0
  62. package/dist/registry/types.d.ts +55 -0
  63. package/dist/registry/types.js +2 -0
  64. package/package.json +72 -0
@@ -0,0 +1,34 @@
1
+ import { Hono } from 'hono';
2
+ import type { Container } from '../container/container';
3
+ import type { Type } from '../container/types';
4
+ import type { FilterType, GuardType, InterceptorType, MiddlewareType, PipeType } from '../registry/types';
5
+ import type { ControllerRegistration } from './types';
6
+ export declare class RouteManager {
7
+ private container;
8
+ private controllers;
9
+ private globalMiddleware;
10
+ private globalPipes;
11
+ private globalGuards;
12
+ private globalInterceptors;
13
+ private globalFilters;
14
+ private globalPrefix;
15
+ constructor(container: Container);
16
+ setGlobalPrefix(prefix: string): this;
17
+ useGlobalMiddleware(...middleware: MiddlewareType[]): this;
18
+ useGlobalPipes(...pipes: PipeType[]): this;
19
+ useGlobalGuards(...guards: GuardType[]): this;
20
+ useGlobalInterceptors(...interceptors: InterceptorType[]): this;
21
+ useGlobalFilters(...filters: FilterType[]): this;
22
+ private instantiate;
23
+ registerController(controller: Type): this;
24
+ build(): Promise<Hono>;
25
+ private createExecutionContext;
26
+ private createHandler;
27
+ private extractArguments;
28
+ private extractParam;
29
+ private createResponse;
30
+ private registerRoute;
31
+ private buildVersionedPaths;
32
+ private joinPaths;
33
+ getControllers(): ControllerRegistration[];
34
+ }
@@ -0,0 +1,373 @@
1
+ import { Hono } from "hono";
2
+ import { HttpMethod, ParamType } from "../constants.js";
3
+ import { getMetadata } from "../metadata.js";
4
+ import { ForbiddenException, HttpException } from "../errors/http-exception.js";
5
+ import { ComponentManager } from "../pipeline/component.manager.js";
6
+ import { shouldFilterCatch } from "../pipeline/decorators.js";
7
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
8
+ import { getHttpCode, getRedirect, getResponseHeaders } from "./decorators.js";
9
+ function parseRedirectResult(result) {
10
+ if (typeof result !== 'object' || result === null) return undefined;
11
+ if (!('url' in result)) return undefined;
12
+ const obj = result;
13
+ if (typeof obj.url !== 'string') return undefined;
14
+ return {
15
+ url: obj.url,
16
+ ...typeof obj.statusCode === 'number' ? {
17
+ statusCode: obj.statusCode
18
+ } : {}
19
+ };
20
+ }
21
+ export class RouteManager {
22
+ container;
23
+ controllers = [];
24
+ globalMiddleware = [];
25
+ globalPipes = [];
26
+ globalGuards = [];
27
+ globalInterceptors = [];
28
+ globalFilters = [];
29
+ globalPrefix = '';
30
+ constructor(container){
31
+ this.container = container;
32
+ }
33
+ setGlobalPrefix(prefix) {
34
+ this.globalPrefix = prefix && !prefix.startsWith('/') ? `/${prefix}` : prefix;
35
+ return this;
36
+ }
37
+ useGlobalMiddleware(...middleware) {
38
+ for (const mw of middleware){
39
+ this.globalMiddleware.push(this.instantiate(mw));
40
+ }
41
+ return this;
42
+ }
43
+ useGlobalPipes(...pipes) {
44
+ for (const pipe of pipes){
45
+ this.globalPipes.push(this.instantiate(pipe));
46
+ }
47
+ return this;
48
+ }
49
+ useGlobalGuards(...guards) {
50
+ for (const guard of guards){
51
+ this.globalGuards.push(this.instantiate(guard));
52
+ }
53
+ return this;
54
+ }
55
+ useGlobalInterceptors(...interceptors) {
56
+ for (const interceptor of interceptors){
57
+ this.globalInterceptors.push(this.instantiate(interceptor));
58
+ }
59
+ return this;
60
+ }
61
+ useGlobalFilters(...filters) {
62
+ for (const filter of filters){
63
+ this.globalFilters.push(this.instantiate(filter));
64
+ }
65
+ return this;
66
+ }
67
+ instantiate(classOrInstance) {
68
+ if (typeof classOrInstance !== 'function') {
69
+ return classOrInstance;
70
+ }
71
+ if (this.container.has(classOrInstance)) {
72
+ return this.container.resolve(classOrInstance);
73
+ }
74
+ return new classOrInstance();
75
+ }
76
+ registerController(controller) {
77
+ const prefix = MetadataRegistry.getControllerPath(controller);
78
+ const options = MetadataRegistry.getControllerOptions(controller);
79
+ const routes = MetadataRegistry.getRoutes(controller);
80
+ if (!this.container.has(controller)) {
81
+ this.container.register(controller);
82
+ }
83
+ this.controllers.push({
84
+ controller,
85
+ metadata: {
86
+ prefix,
87
+ version: options.version
88
+ },
89
+ routes: routes
90
+ });
91
+ return this;
92
+ }
93
+ async build() {
94
+ const app = new Hono();
95
+ // Register global middleware on the Hono app
96
+ for (const mw of this.globalMiddleware){
97
+ app.use('*', (c, next)=>mw.use(c, next));
98
+ }
99
+ // First pass: register all custom routes (must come before CRUD /:id routes)
100
+ for (const { controller, metadata, routes } of this.controllers){
101
+ if (routes.length > 0) {
102
+ const instance = this.container.resolve(controller);
103
+ const allParamMetadata = MetadataRegistry.getParameters(controller);
104
+ for (const route of routes){
105
+ // Determine effective version: route-level overrides controller-level
106
+ const effectiveVersion = route.version ?? metadata.version;
107
+ // Build versioned paths
108
+ const versionedPaths = this.buildVersionedPaths(this.globalPrefix, metadata.prefix, route.path, effectiveVersion);
109
+ // Register per-route middleware as Hono middleware before the handler
110
+ const middlewareItems = ComponentManager.getComponents('middleware', controller, route.handlerName);
111
+ const resolvedMw = ComponentManager.resolveMiddleware(middlewareItems);
112
+ const handler = this.createHandler(instance, route, controller, allParamMetadata);
113
+ for (const fullPath of versionedPaths){
114
+ for (const mw of resolvedMw){
115
+ app.use(fullPath, (c, next)=>mw.use(c, next));
116
+ }
117
+ this.registerRoute(app, route.method, fullPath, handler);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ // Second pass: mount CRUD sub-apps (/:id routes registered last)
123
+ for (const { controller, metadata } of this.controllers){
124
+ const crudConfig = getMetadata('vela:crud', controller);
125
+ if (crudConfig) {
126
+ try {
127
+ const pkg = '@velajs/crud';
128
+ const { buildCrudRoutes } = await import(pkg);
129
+ await buildCrudRoutes(app, controller, metadata.prefix, crudConfig, {
130
+ globalPrefix: this.globalPrefix,
131
+ globalGuards: this.globalGuards,
132
+ joinPaths: this.joinPaths.bind(this)
133
+ });
134
+ } catch {
135
+ throw new Error(`@Crud() requires '@velajs/crud'. Install it: bun add @velajs/crud`);
136
+ }
137
+ }
138
+ }
139
+ return app;
140
+ }
141
+ createExecutionContext(c, controller, route) {
142
+ return {
143
+ getClass: ()=>controller,
144
+ getHandler: ()=>route.handlerName,
145
+ getContext: ()=>c,
146
+ getRequest: ()=>c.req.raw
147
+ };
148
+ }
149
+ createHandler(instance, route, controller, allParamMetadata) {
150
+ const paramMetadata = (allParamMetadata.get(route.handlerName) || []).sort((a, b)=>a.index - b.index);
151
+ // Pre-resolve controller + method level components at build time
152
+ const methodGuards = ComponentManager.getComponents('guard', controller, route.handlerName);
153
+ const methodPipes = ComponentManager.getComponents('pipe', controller, route.handlerName);
154
+ const methodInterceptors = ComponentManager.getComponents('interceptor', controller, route.handlerName);
155
+ const methodFilters = ComponentManager.getComponents('filter', controller, route.handlerName);
156
+ const resolvedMethodGuards = ComponentManager.resolveGuards(methodGuards);
157
+ const resolvedMethodPipes = ComponentManager.resolvePipes(methodPipes);
158
+ const resolvedMethodInterceptors = ComponentManager.resolveInterceptors(methodInterceptors);
159
+ // Filters: reverse order (handler → controller → global) — closest to handler runs first
160
+ const resolvedMethodFilters = ComponentManager.resolveFilters([
161
+ ...methodFilters
162
+ ].reverse());
163
+ // Read response decorators at build time
164
+ const httpCode = getHttpCode(controller, route.handlerName);
165
+ const responseHeaders = getResponseHeaders(controller, route.handlerName);
166
+ const redirect = getRedirect(controller, route.handlerName);
167
+ return async (c)=>{
168
+ // Create a child container for request-scoped providers
169
+ const requestContainer = this.container.createChild();
170
+ c.set('container', requestContainer);
171
+ // Combine global + method at request time (allows post-create registration)
172
+ const guards = [
173
+ ...this.globalGuards,
174
+ ...resolvedMethodGuards
175
+ ];
176
+ const pipes = [
177
+ ...this.globalPipes,
178
+ ...resolvedMethodPipes
179
+ ];
180
+ const interceptors = [
181
+ ...this.globalInterceptors,
182
+ ...resolvedMethodInterceptors
183
+ ];
184
+ const filters = [
185
+ ...resolvedMethodFilters,
186
+ ...this.globalFilters
187
+ ];
188
+ const executionContext = this.createExecutionContext(c, controller, route);
189
+ try {
190
+ // 1. Extract args + run pipes
191
+ const args = await this.extractArguments(c, paramMetadata, pipes);
192
+ // 2. Guards (fail-fast)
193
+ for (const guard of guards){
194
+ const canActivate = await guard.canActivate(executionContext);
195
+ if (!canActivate) {
196
+ throw new ForbiddenException();
197
+ }
198
+ }
199
+ // 3. Get handler method
200
+ const method = Reflect.get(instance, route.handlerName);
201
+ if (typeof method !== 'function') {
202
+ throw new Error(`Method ${String(route.handlerName)} not found on controller`);
203
+ }
204
+ // 4. Build core handler
205
+ const coreHandler = async ()=>Reflect.apply(method, instance, args);
206
+ // 5. Run interceptor chain
207
+ const result = await ComponentManager.runInterceptorChain(interceptors, executionContext, coreHandler);
208
+ // Handle @Redirect
209
+ if (redirect) {
210
+ const overrides = parseRedirectResult(result);
211
+ const finalUrl = overrides?.url ?? redirect.url;
212
+ const finalStatus = overrides?.statusCode ?? redirect.statusCode;
213
+ return c.redirect(finalUrl, finalStatus);
214
+ }
215
+ // Build response with @HttpCode and @Header support
216
+ const response = this.createResponse(c, result, httpCode);
217
+ // Apply @Header decorators
218
+ for (const [headerName, headerValue] of responseHeaders){
219
+ response.headers.set(headerName, headerValue);
220
+ }
221
+ return response;
222
+ } catch (error) {
223
+ // Run exception filters
224
+ for (const filter of filters){
225
+ if (shouldFilterCatch(filter, error)) {
226
+ try {
227
+ const result = await filter.catch(error, executionContext);
228
+ return this.createResponse(c, result);
229
+ } catch {
230
+ break;
231
+ }
232
+ }
233
+ }
234
+ // Default HttpException handling
235
+ if (error instanceof HttpException) {
236
+ const response = error.getResponse();
237
+ const status = error.getStatus();
238
+ return c.json(response, status);
239
+ }
240
+ // Default 500
241
+ return c.json({
242
+ statusCode: 500,
243
+ message: 'Internal Server Error'
244
+ }, 500);
245
+ }
246
+ };
247
+ }
248
+ async extractArguments(c, paramMetadata, pipes) {
249
+ if (paramMetadata.length === 0) {
250
+ return [
251
+ c
252
+ ];
253
+ }
254
+ const maxIndex = Math.max(...paramMetadata.map((p)=>p.index));
255
+ const args = new Array(maxIndex + 1).fill(undefined);
256
+ for (const param of paramMetadata){
257
+ let value = await this.extractParam(c, param);
258
+ const metadata = {
259
+ type: param.type,
260
+ data: param.name,
261
+ metatype: undefined
262
+ };
263
+ // Run shared pipes (global + controller + method)
264
+ for (const pipe of pipes){
265
+ value = await pipe.transform(value, metadata);
266
+ }
267
+ // Run param-level pipes
268
+ if (param.pipes && param.pipes.length > 0) {
269
+ for (const paramPipe of param.pipes){
270
+ const pipeInstance = this.instantiate(paramPipe);
271
+ value = await pipeInstance.transform(value, metadata);
272
+ }
273
+ }
274
+ args[param.index] = value;
275
+ }
276
+ return args;
277
+ }
278
+ async extractParam(c, param) {
279
+ switch(param.type){
280
+ case ParamType.PARAM:
281
+ return param.name ? c.req.param(param.name) : c.req.param();
282
+ case ParamType.QUERY:
283
+ return param.name ? c.req.query(param.name) : c.req.query();
284
+ case ParamType.BODY:
285
+ try {
286
+ return await c.req.json();
287
+ } catch {
288
+ return undefined;
289
+ }
290
+ case ParamType.HEADERS:
291
+ if (param.name) {
292
+ return c.req.header(param.name);
293
+ }
294
+ const headers = {};
295
+ c.req.raw.headers.forEach((value, key)=>{
296
+ headers[key] = value;
297
+ });
298
+ return headers;
299
+ case ParamType.REQUEST:
300
+ return c;
301
+ default:
302
+ // Custom param decorator — use factory if available
303
+ if (param.factory) {
304
+ return param.factory(param.name, c);
305
+ }
306
+ return undefined;
307
+ }
308
+ }
309
+ createResponse(c, result, statusCode) {
310
+ if (result instanceof Response) {
311
+ return result;
312
+ }
313
+ if (result === null || result === undefined) {
314
+ return c.body(null, statusCode ?? 204);
315
+ }
316
+ if (typeof result === 'string') {
317
+ return c.text(result, statusCode ?? 200);
318
+ }
319
+ return c.json(result, statusCode ?? 200);
320
+ }
321
+ registerRoute(app, method, path, handler) {
322
+ const normalizedPath = path || '/';
323
+ switch(method){
324
+ case HttpMethod.GET:
325
+ app.get(normalizedPath, handler);
326
+ break;
327
+ case HttpMethod.POST:
328
+ app.post(normalizedPath, handler);
329
+ break;
330
+ case HttpMethod.PUT:
331
+ app.put(normalizedPath, handler);
332
+ break;
333
+ case HttpMethod.PATCH:
334
+ app.patch(normalizedPath, handler);
335
+ break;
336
+ case HttpMethod.DELETE:
337
+ app.delete(normalizedPath, handler);
338
+ break;
339
+ case HttpMethod.OPTIONS:
340
+ app.options(normalizedPath, handler);
341
+ break;
342
+ case HttpMethod.HEAD:
343
+ app.on('HEAD', normalizedPath, handler);
344
+ break;
345
+ default:
346
+ app.on(method.toUpperCase(), normalizedPath, handler);
347
+ }
348
+ }
349
+ buildVersionedPaths(globalPrefix, controllerPrefix, routePath, version) {
350
+ if (version === undefined) {
351
+ return [
352
+ this.joinPaths(globalPrefix, this.joinPaths(controllerPrefix, routePath))
353
+ ];
354
+ }
355
+ const versions = Array.isArray(version) ? version : [
356
+ version
357
+ ];
358
+ return versions.map((v)=>{
359
+ const versionSegment = `/v${v}`;
360
+ return this.joinPaths(globalPrefix, this.joinPaths(versionSegment, this.joinPaths(controllerPrefix, routePath)));
361
+ });
362
+ }
363
+ joinPaths(prefix, path) {
364
+ const cleanPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
365
+ const cleanPath = path && !path.startsWith('/') ? `/${path}` : path;
366
+ return `${cleanPrefix}${cleanPath}` || '/';
367
+ }
368
+ getControllers() {
369
+ return [
370
+ ...this.controllers
371
+ ];
372
+ }
373
+ }
@@ -0,0 +1,29 @@
1
+ import type { HttpMethod } from '../constants';
2
+ import type { Type } from '../container/types';
3
+ import type { PipeType } from '../registry/types';
4
+ export interface RouteMetadata {
5
+ method: HttpMethod;
6
+ path: string;
7
+ handlerName: string | symbol;
8
+ version?: number | number[];
9
+ }
10
+ export interface ControllerOptions {
11
+ prefix?: string;
12
+ version?: number | number[];
13
+ }
14
+ export interface ControllerMetadata {
15
+ prefix: string;
16
+ version?: number | number[];
17
+ }
18
+ export interface ParamMetadata {
19
+ index: number;
20
+ type: string;
21
+ name?: string;
22
+ pipes?: PipeType[];
23
+ factory?: (data: unknown, ctx: import('hono').Context) => unknown;
24
+ }
25
+ export interface ControllerRegistration {
26
+ controller: Type;
27
+ metadata: ControllerMetadata;
28
+ routes: RouteMetadata[];
29
+ }
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,20 @@
1
+ import './metadata';
2
+ export { defineMetadata, getMetadata } from './metadata';
3
+ export { VelaFactory } from './factory';
4
+ export { VelaApplication } from './application';
5
+ export { Container, Injectable, Inject, InjectionToken } from './container/index';
6
+ export type { Type, Token, InjectableOptions, ProviderOptions, } from './container/index';
7
+ export { METADATA_KEYS, HttpMethod, ParamType, Scope } from './constants';
8
+ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, Param, Query, Body, Headers, Req, HttpCode, Header, Redirect, createParamDecorator, } from './http/index';
9
+ export { Module } from './module/index';
10
+ export type { ModuleOptions, DynamicModule } from './module/index';
11
+ export { UseMiddleware, UseGuards, UsePipes, UseInterceptors, UseFilters, Catch, SetMetadata, Reflector, APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE, } from './pipeline/index';
12
+ export type { ExecutionContext, CanActivate, CallHandler, NestInterceptor, NestMiddleware, PipeTransform, ExceptionFilter, ArgumentMetadata, ReflectableDecorator, CreateDecoratorOptions, } from './pipeline/index';
13
+ export type { Constructor, MiddlewareType, GuardType, PipeType, InterceptorType, FilterType, } from './registry/index';
14
+ export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe, } from './pipeline/index';
15
+ export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, MethodNotAllowedException, NotAcceptableException, RequestTimeoutException, ConflictException, GoneException, PayloadTooLargeException, UnsupportedMediaTypeException, UnprocessableEntityException, TooManyRequestsException, InternalServerErrorException, NotImplementedException, BadGatewayException, ServiceUnavailableException, GatewayTimeoutException, } from './errors/index';
16
+ export type { OnModuleInit, OnApplicationBootstrap, OnModuleDestroy, OnApplicationShutdown, BeforeApplicationShutdown, } from './lifecycle/index';
17
+ export { MetadataRegistry } from './registry/index';
18
+ export { RouteManager } from './http/index';
19
+ export { ModuleLoader } from './module/index';
20
+ export { ComponentManager } from './pipeline/index';
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import "./metadata.js";
2
+ export { defineMetadata, getMetadata } from "./metadata.js";
3
+ // Factory & Application
4
+ export { VelaFactory } from "./factory.js";
5
+ export { VelaApplication } from "./application.js";
6
+ // DI Container
7
+ export { Container, Injectable, Inject, InjectionToken } from "./container/index.js";
8
+ // Constants
9
+ export { METADATA_KEYS, HttpMethod, ParamType, Scope } from "./constants.js";
10
+ // HTTP Decorators
11
+ export { Controller, Version, Get, Post, Put, Patch, Delete, Options, Head, Param, Query, Body, Headers, Req, HttpCode, Header, Redirect, createParamDecorator } from "./http/index.js";
12
+ // Module
13
+ export { Module } from "./module/index.js";
14
+ // Pipeline Decorators
15
+ export { UseMiddleware, UseGuards, UsePipes, UseInterceptors, UseFilters, Catch, SetMetadata, Reflector, APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER, APP_MIDDLEWARE } from "./pipeline/index.js";
16
+ // Built-in Pipes
17
+ export { ParseIntPipe, ParseFloatPipe, ParseBoolPipe, DefaultValuePipe, RequiredPipe, ZodValidationPipe } from "./pipeline/index.js";
18
+ // Errors
19
+ export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, MethodNotAllowedException, NotAcceptableException, RequestTimeoutException, ConflictException, GoneException, PayloadTooLargeException, UnsupportedMediaTypeException, UnprocessableEntityException, TooManyRequestsException, InternalServerErrorException, NotImplementedException, BadGatewayException, ServiceUnavailableException, GatewayTimeoutException } from "./errors/index.js";
20
+ // Registry (for advanced usage)
21
+ export { MetadataRegistry } from "./registry/index.js";
22
+ // Module internals (for @velajs/testing and advanced usage)
23
+ export { RouteManager } from "./http/index.js";
24
+ export { ModuleLoader } from "./module/index.js";
25
+ // Component Manager (for advanced usage)
26
+ export { ComponentManager } from "./pipeline/index.js";
@@ -0,0 +1,20 @@
1
+ export interface OnModuleInit {
2
+ onModuleInit(): void | Promise<void>;
3
+ }
4
+ export interface OnApplicationBootstrap {
5
+ onApplicationBootstrap(): void | Promise<void>;
6
+ }
7
+ export interface OnModuleDestroy {
8
+ onModuleDestroy(): void | Promise<void>;
9
+ }
10
+ export interface OnApplicationShutdown {
11
+ onApplicationShutdown(signal?: string): void | Promise<void>;
12
+ }
13
+ export interface BeforeApplicationShutdown {
14
+ beforeApplicationShutdown(signal?: string): void | Promise<void>;
15
+ }
16
+ export declare function hasOnModuleInit(instance: unknown): instance is OnModuleInit;
17
+ export declare function hasOnApplicationBootstrap(instance: unknown): instance is OnApplicationBootstrap;
18
+ export declare function hasOnModuleDestroy(instance: unknown): instance is OnModuleDestroy;
19
+ export declare function hasBeforeApplicationShutdown(instance: unknown): instance is BeforeApplicationShutdown;
20
+ export declare function hasOnApplicationShutdown(instance: unknown): instance is OnApplicationShutdown;
@@ -0,0 +1,15 @@
1
+ export function hasOnModuleInit(instance) {
2
+ return instance !== null && typeof instance === 'object' && typeof instance.onModuleInit === 'function';
3
+ }
4
+ export function hasOnApplicationBootstrap(instance) {
5
+ return instance !== null && typeof instance === 'object' && typeof instance.onApplicationBootstrap === 'function';
6
+ }
7
+ export function hasOnModuleDestroy(instance) {
8
+ return instance !== null && typeof instance === 'object' && typeof instance.onModuleDestroy === 'function';
9
+ }
10
+ export function hasBeforeApplicationShutdown(instance) {
11
+ return instance !== null && typeof instance === 'object' && typeof instance.beforeApplicationShutdown === 'function';
12
+ }
13
+ export function hasOnApplicationShutdown(instance) {
14
+ return instance !== null && typeof instance === 'object' && typeof instance.onApplicationShutdown === 'function';
15
+ }
@@ -0,0 +1,10 @@
1
+ declare global {
2
+ namespace Reflect {
3
+ function defineMetadata(key: string, value: unknown, target: object, propertyKey?: string | symbol): void;
4
+ function getMetadata(key: string, target: object, propertyKey?: string | symbol): unknown;
5
+ function getOwnMetadata(key: string, target: object, propertyKey?: string | symbol): unknown;
6
+ function metadata(key: string, value: unknown): (target: object, propertyKey?: string | symbol) => void;
7
+ }
8
+ }
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;
@@ -0,0 +1,29 @@
1
+ // Lightweight metadata store — replaces the `reflect-metadata` npm package.
2
+ // All custom vela:* keys go through defineMetadata/getMetadata.
3
+ // The Reflect.metadata polyfill keeps SWC's auto-emitted design:paramtypes working.
4
+ const store = new WeakMap();
5
+ function compositeKey(key, prop) {
6
+ return prop !== undefined ? `${key}\0${String(prop)}` : key;
7
+ }
8
+ export function defineMetadata(key, value, target, propertyKey) {
9
+ let map = store.get(target);
10
+ if (!map) {
11
+ map = new Map();
12
+ store.set(target, map);
13
+ }
14
+ map.set(compositeKey(key, propertyKey), value);
15
+ }
16
+ export function getMetadata(key, target, propertyKey) {
17
+ return store.get(target)?.get(compositeKey(key, propertyKey));
18
+ }
19
+ // Minimal Reflect polyfill so the compiler's `Reflect.metadata(...)` calls work.
20
+ if (typeof Reflect.defineMetadata !== 'function') {
21
+ Reflect.defineMetadata = defineMetadata;
22
+ Reflect.getMetadata = getMetadata;
23
+ Reflect.getOwnMetadata = getMetadata;
24
+ Reflect.metadata = (key, value)=>{
25
+ return (target, propertyKey)=>{
26
+ defineMetadata(key, value, target, propertyKey);
27
+ };
28
+ };
29
+ }
@@ -0,0 +1,5 @@
1
+ import type { Constructor } from '../registry/types';
2
+ import type { ModuleMetadata, ModuleOptions } from './types';
3
+ export declare function Module(options?: ModuleOptions): ClassDecorator;
4
+ export declare function isModule(target: Constructor): boolean;
5
+ export declare function getModuleMetadata(target: Constructor): ModuleMetadata | undefined;
@@ -0,0 +1,32 @@
1
+ import { METADATA_KEYS } from "../constants.js";
2
+ import { getMetadata } from "../metadata.js";
3
+ import { MetadataRegistry } from "../registry/metadata.registry.js";
4
+ export function Module(options = {}) {
5
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
6
+ return (target)=>{
7
+ MetadataRegistry.setModuleOptions(target, {
8
+ imports: options.imports,
9
+ providers: options.providers,
10
+ controllers: options.controllers,
11
+ exports: options.exports
12
+ });
13
+ };
14
+ }
15
+ export function isModule(target) {
16
+ return MetadataRegistry.getModuleOptions(target) !== undefined || getMetadata(METADATA_KEYS.MODULE, target) === true;
17
+ }
18
+ export function getModuleMetadata(target) {
19
+ if (!isModule(target)) {
20
+ return undefined;
21
+ }
22
+ const options = MetadataRegistry.getModuleOptions(target);
23
+ if (!options) {
24
+ return undefined;
25
+ }
26
+ return {
27
+ providers: options.providers ?? [],
28
+ controllers: options.controllers ?? [],
29
+ imports: options.imports ?? [],
30
+ exports: options.exports ?? []
31
+ };
32
+ }
@@ -0,0 +1,3 @@
1
+ export { Module, isModule, getModuleMetadata } from './decorators';
2
+ export { ModuleLoader } from './module-loader';
3
+ export type { ModuleOptions, ModuleMetadata, DynamicModule } from './types';
@@ -0,0 +1,2 @@
1
+ export { Module, isModule, getModuleMetadata } from "./decorators.js";
2
+ export { ModuleLoader } from "./module-loader.js";
@@ -0,0 +1,20 @@
1
+ import type { Container } from '../container/container';
2
+ import type { Token, Type } from '../container/types';
3
+ import type { RouteManager } from '../http/route.manager';
4
+ export declare class ModuleLoader {
5
+ private container;
6
+ private router;
7
+ private processedModules;
8
+ private processingStack;
9
+ private collectedControllers;
10
+ private registeredProviders;
11
+ private moduleExportsCache;
12
+ constructor(container: Container, router: RouteManager);
13
+ load(rootModule: Type): void;
14
+ private processModule;
15
+ private registerProvider;
16
+ private buildExportSet;
17
+ getControllers(): Type[];
18
+ getRegisteredProviders(): Token[];
19
+ resolveAllInstances(): unknown[];
20
+ }