@carno.js/core 0.2.3 → 0.2.5

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.
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CorsHeadersCache = void 0;
4
+ const cors_config_1 = require("./cors-config");
5
+ class CorsHeadersCache {
6
+ constructor(config) {
7
+ this.config = config;
8
+ this.cache = new Map();
9
+ const methods = config.methods || cors_config_1.DEFAULT_CORS_METHODS;
10
+ this.methodsString = methods.join(', ');
11
+ const allowedHeaders = config.allowedHeaders || cors_config_1.DEFAULT_CORS_ALLOWED_HEADERS;
12
+ this.allowedHeadersString = allowedHeaders.join(', ');
13
+ this.exposedHeadersString = config.exposedHeaders?.length
14
+ ? config.exposedHeaders.join(', ')
15
+ : null;
16
+ this.maxAgeString = config.maxAge !== undefined
17
+ ? config.maxAge.toString()
18
+ : null;
19
+ this.hasCredentials = !!config.credentials;
20
+ this.isWildcard = config.origins === '*';
21
+ }
22
+ get(origin) {
23
+ const cacheKey = this.isWildcard ? '*' : origin;
24
+ let cached = this.cache.get(cacheKey);
25
+ if (cached) {
26
+ return cached;
27
+ }
28
+ cached = this.buildHeaders(origin);
29
+ this.cache.set(cacheKey, cached);
30
+ return cached;
31
+ }
32
+ buildHeaders(origin) {
33
+ const headers = {
34
+ 'Access-Control-Allow-Origin': this.isWildcard ? '*' : origin,
35
+ 'Access-Control-Allow-Methods': this.methodsString,
36
+ 'Access-Control-Allow-Headers': this.allowedHeadersString,
37
+ };
38
+ if (this.hasCredentials) {
39
+ headers['Access-Control-Allow-Credentials'] = 'true';
40
+ }
41
+ if (this.exposedHeadersString) {
42
+ headers['Access-Control-Expose-Headers'] = this.exposedHeadersString;
43
+ }
44
+ if (this.maxAgeString) {
45
+ headers['Access-Control-Max-Age'] = this.maxAgeString;
46
+ }
47
+ return headers;
48
+ }
49
+ applyToResponse(response, origin) {
50
+ const corsHeaders = this.get(origin);
51
+ for (const key in corsHeaders) {
52
+ response.headers.set(key, corsHeaders[key]);
53
+ }
54
+ return response;
55
+ }
56
+ }
57
+ exports.CorsHeadersCache = CorsHeadersCache;
package/dist/index.d.ts CHANGED
@@ -10,7 +10,6 @@ export * from "./constants";
10
10
  export * from "./utils";
11
11
  export * from "./default-routes-carno";
12
12
  export * from "./services/logger.service";
13
- export * from "./services/request-logger.service";
14
13
  export * from "./cache/cache.service";
15
14
  export * from "./cache/bento-cache.driver";
16
15
  export * from "./testing";
package/dist/index.js CHANGED
@@ -26,7 +26,6 @@ __exportStar(require("./constants"), exports);
26
26
  __exportStar(require("./utils"), exports);
27
27
  __exportStar(require("./default-routes-carno"), exports);
28
28
  __exportStar(require("./services/logger.service"), exports);
29
- __exportStar(require("./services/request-logger.service"), exports);
30
29
  __exportStar(require("./cache/cache.service"), exports);
31
30
  __exportStar(require("./cache/bento-cache.driver"), exports);
32
31
  __exportStar(require("./testing"), exports);
@@ -0,0 +1,23 @@
1
+ import type { Context } from '../domain/Context';
2
+ import type { TokenRouteWithProvider } from '../container/ContainerConfiguration';
3
+ export declare enum RouteType {
4
+ SIMPLE = 0,
5
+ STANDARD = 1,
6
+ COMPLEX = 2
7
+ }
8
+ export type ParamResolver = (context: Context) => any;
9
+ export type AsyncParamResolver = (context: Context) => Promise<any>;
10
+ export type CompiledHandler = (context: Context) => any;
11
+ export type AsyncCompiledHandler = (context: Context) => Promise<any>;
12
+ export interface CompiledRoute {
13
+ routeType: RouteType;
14
+ controllerInstance: any | null;
15
+ boundHandler: CompiledHandler | AsyncCompiledHandler | null;
16
+ paramResolvers: (ParamResolver | AsyncParamResolver | null)[];
17
+ needsLocalsContainer: boolean;
18
+ hasMiddlewares: boolean;
19
+ hasValidation: boolean;
20
+ validationIndices: number[];
21
+ isAsync: boolean;
22
+ original: TokenRouteWithProvider;
23
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RouteType = void 0;
4
+ var RouteType;
5
+ (function (RouteType) {
6
+ RouteType[RouteType["SIMPLE"] = 0] = "SIMPLE";
7
+ RouteType[RouteType["STANDARD"] = 1] = "STANDARD";
8
+ RouteType[RouteType["COMPLEX"] = 2] = "COMPLEX";
9
+ })(RouteType || (exports.RouteType = RouteType = {}));
@@ -0,0 +1,4 @@
1
+ import type { Context } from '../domain/Context';
2
+ import type { CompiledRoute } from './CompiledRoute';
3
+ export declare function executeSimpleRoute(compiled: CompiledRoute, context: Context): Promise<any>;
4
+ export declare function executeSimpleRouteSync(compiled: CompiledRoute, context: Context): any;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeSimpleRoute = executeSimpleRoute;
4
+ exports.executeSimpleRouteSync = executeSimpleRouteSync;
5
+ async function executeSimpleRoute(compiled, context) {
6
+ if (!compiled.boundHandler) {
7
+ throw new Error('Simple route must have a bound handler');
8
+ }
9
+ if (compiled.isAsync) {
10
+ return compiled.boundHandler(context);
11
+ }
12
+ return compiled.boundHandler(context);
13
+ }
14
+ function executeSimpleRouteSync(compiled, context) {
15
+ if (!compiled.boundHandler) {
16
+ throw new Error('Simple route must have a bound handler');
17
+ }
18
+ return compiled.boundHandler(context);
19
+ }
@@ -0,0 +1,4 @@
1
+ import type { ParamInfo } from './ParamResolverFactory';
2
+ import type { CompiledHandler, AsyncCompiledHandler } from './CompiledRoute';
3
+ export declare function compileRouteHandler(instance: any, methodName: string, paramInfos: ParamInfo[]): CompiledHandler | AsyncCompiledHandler;
4
+ export declare function compileValidatedHandler(instance: any, methodName: string, paramInfos: ParamInfo[], validators: ((value: any) => any)[]): CompiledHandler | AsyncCompiledHandler;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compileRouteHandler = compileRouteHandler;
4
+ exports.compileValidatedHandler = compileValidatedHandler;
5
+ function escapeKey(key) {
6
+ return key.replace(/['"\\]/g, '\\$&');
7
+ }
8
+ function buildArgExpression(param, index) {
9
+ const key = param.key ? escapeKey(param.key) : undefined;
10
+ switch (param.type) {
11
+ case 'param':
12
+ return key ? `ctx.param['${key}']` : 'ctx.param';
13
+ case 'query':
14
+ return key ? `ctx.query['${key}']` : 'ctx.query';
15
+ case 'body':
16
+ return key ? `ctx.body['${key}']` : 'ctx.body';
17
+ case 'headers':
18
+ return key
19
+ ? `ctx.headers.get('${key}')`
20
+ : 'ctx.headers';
21
+ case 'req':
22
+ return 'ctx.req';
23
+ case 'locals':
24
+ return 'ctx.locals';
25
+ case 'di':
26
+ return `resolvers[${index}](ctx)`;
27
+ default:
28
+ return `resolvers[${index}](ctx)`;
29
+ }
30
+ }
31
+ function compileRouteHandler(instance, methodName, paramInfos) {
32
+ const handler = instance[methodName].bind(instance);
33
+ if (paramInfos.length === 0) {
34
+ return () => handler();
35
+ }
36
+ const hasBodyParam = paramInfos.some((p) => p.type === 'body');
37
+ const hasDIParam = paramInfos.some((p) => p.type === 'di');
38
+ if (hasDIParam) {
39
+ return createFallbackHandler(handler, paramInfos);
40
+ }
41
+ const argExpressions = paramInfos.map(buildArgExpression);
42
+ if (hasBodyParam) {
43
+ return createAsyncHandler(handler, argExpressions);
44
+ }
45
+ return createSyncHandler(handler, argExpressions);
46
+ }
47
+ function createSyncHandler(handler, argExpressions) {
48
+ const code = `
49
+ return function compiledHandler(ctx) {
50
+ return handler(${argExpressions.join(', ')});
51
+ }
52
+ `;
53
+ return new Function('handler', code)(handler);
54
+ }
55
+ function createAsyncHandler(handler, argExpressions) {
56
+ const code = `
57
+ return async function compiledHandler(ctx) {
58
+ await ctx.getBody();
59
+ return handler(${argExpressions.join(', ')});
60
+ }
61
+ `;
62
+ return new Function('handler', code)(handler);
63
+ }
64
+ function createFallbackHandler(handler, paramInfos) {
65
+ return (ctx) => {
66
+ const args = [];
67
+ for (const param of paramInfos) {
68
+ switch (param.type) {
69
+ case 'param':
70
+ args.push(param.key ? ctx.param[param.key] : ctx.param);
71
+ break;
72
+ case 'query':
73
+ args.push(param.key ? ctx.query[param.key] : ctx.query);
74
+ break;
75
+ case 'body':
76
+ args.push(param.key ? ctx.body[param.key] : ctx.body);
77
+ break;
78
+ case 'headers':
79
+ args.push(param.key ? ctx.headers.get(param.key) : ctx.headers);
80
+ break;
81
+ case 'req':
82
+ args.push(ctx.req);
83
+ break;
84
+ case 'locals':
85
+ args.push(ctx.locals);
86
+ break;
87
+ default:
88
+ args.push(undefined);
89
+ break;
90
+ }
91
+ }
92
+ return handler(...args);
93
+ };
94
+ }
95
+ function compileValidatedHandler(instance, methodName, paramInfos, validators) {
96
+ const handler = instance[methodName].bind(instance);
97
+ const hasBodyParam = paramInfos.some((p) => p.type === 'body');
98
+ const resolveArg = (ctx, param, index) => {
99
+ let value;
100
+ switch (param.type) {
101
+ case 'param':
102
+ value = param.key ? ctx.param[param.key] : ctx.param;
103
+ break;
104
+ case 'query':
105
+ value = param.key ? ctx.query[param.key] : ctx.query;
106
+ break;
107
+ case 'body':
108
+ value = param.key ? ctx.body[param.key] : ctx.body;
109
+ break;
110
+ case 'headers':
111
+ value = param.key ? ctx.headers.get(param.key) : ctx.headers;
112
+ break;
113
+ case 'req':
114
+ value = ctx.req;
115
+ break;
116
+ case 'locals':
117
+ value = ctx.locals;
118
+ break;
119
+ default:
120
+ value = undefined;
121
+ }
122
+ if (param.needsValidation && validators[index]) {
123
+ return validators[index](value);
124
+ }
125
+ return value;
126
+ };
127
+ if (hasBodyParam) {
128
+ return async (ctx) => {
129
+ await ctx.getBody();
130
+ const args = paramInfos.map((p, i) => resolveArg(ctx, p, i));
131
+ return handler(...args);
132
+ };
133
+ }
134
+ return (ctx) => {
135
+ const args = paramInfos.map((p, i) => resolveArg(ctx, p, i));
136
+ return handler(...args);
137
+ };
138
+ }
@@ -0,0 +1,17 @@
1
+ import { type ValidatorOptions } from 'class-validator';
2
+ import type { Context } from '../domain/Context';
3
+ import type { ParamResolver, AsyncParamResolver } from './CompiledRoute';
4
+ export interface ParamDecoratorMeta {
5
+ fun: (context: Context, data?: any) => any;
6
+ param?: any;
7
+ }
8
+ export interface ParamInfo {
9
+ type: 'body' | 'query' | 'param' | 'headers' | 'req' | 'locals' | 'di';
10
+ key?: string;
11
+ needsValidation: boolean;
12
+ token?: any;
13
+ }
14
+ export declare function analyzeParamDecorator(decoratorMeta: ParamDecoratorMeta | undefined, token: any): ParamInfo;
15
+ export declare function createParamResolver(decoratorMeta: ParamDecoratorMeta | undefined, token: any, validationConfig?: ValidatorOptions): ParamResolver | AsyncParamResolver | null;
16
+ export declare function createParamResolvers(paramMetas: Record<number, ParamDecoratorMeta> | undefined, argTypes: any[], validationConfig?: ValidatorOptions): (ParamResolver | AsyncParamResolver | null)[];
17
+ export declare function hasAnyDIParam(resolvers: (ParamResolver | AsyncParamResolver | null)[]): boolean;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeParamDecorator = analyzeParamDecorator;
4
+ exports.createParamResolver = createParamResolver;
5
+ exports.createParamResolvers = createParamResolvers;
6
+ exports.hasAnyDIParam = hasAnyDIParam;
7
+ const class_transformer_1 = require("class-transformer");
8
+ const class_validator_1 = require("class-validator");
9
+ const HttpException_1 = require("../exceptions/HttpException");
10
+ const ValidationCache_1 = require("../utils/ValidationCache");
11
+ function analyzeParamDecorator(decoratorMeta, token) {
12
+ if (!decoratorMeta) {
13
+ return { type: 'di', needsValidation: false, token };
14
+ }
15
+ const funcStr = decoratorMeta.fun.toString();
16
+ const key = decoratorMeta.param;
17
+ const needsValidation = typeof token === 'function' && (0, ValidationCache_1.isValidatable)(token);
18
+ if (funcStr.includes('context.body')) {
19
+ return { type: 'body', key, needsValidation, token };
20
+ }
21
+ if (funcStr.includes('context.query')) {
22
+ return { type: 'query', key, needsValidation, token };
23
+ }
24
+ if (funcStr.includes('context.param')) {
25
+ return { type: 'param', key, needsValidation, token };
26
+ }
27
+ if (funcStr.includes('context.headers')) {
28
+ return { type: 'headers', key, needsValidation, token };
29
+ }
30
+ if (funcStr.includes('context.req')) {
31
+ return { type: 'req', needsValidation: false, token };
32
+ }
33
+ if (funcStr.includes('context.locals')) {
34
+ return { type: 'locals', needsValidation: false, token };
35
+ }
36
+ return { type: 'di', needsValidation: false, token };
37
+ }
38
+ function createValidationResolver(extractFn, token, validationConfig) {
39
+ return (context) => {
40
+ const value = extractFn(context);
41
+ const obj = (0, class_transformer_1.plainToInstance)(token, value);
42
+ const errors = (0, class_validator_1.validateSync)(obj, validationConfig);
43
+ if (errors.length > 0) {
44
+ throw new HttpException_1.HttpException(errors, 400);
45
+ }
46
+ return obj;
47
+ };
48
+ }
49
+ function createParamResolver(decoratorMeta, token, validationConfig) {
50
+ if (!decoratorMeta) {
51
+ return null;
52
+ }
53
+ const extractFn = (context) => decoratorMeta.fun(context, decoratorMeta.param);
54
+ const needsValidation = typeof token === 'function' && (0, ValidationCache_1.isValidatable)(token);
55
+ if (needsValidation) {
56
+ return createValidationResolver(extractFn, token, validationConfig);
57
+ }
58
+ return extractFn;
59
+ }
60
+ function createParamResolvers(paramMetas, argTypes, validationConfig) {
61
+ const resolvers = [];
62
+ for (let i = 0; i < argTypes.length; i++) {
63
+ const meta = paramMetas?.[i];
64
+ const token = argTypes[i];
65
+ resolvers.push(createParamResolver(meta, token, validationConfig));
66
+ }
67
+ return resolvers;
68
+ }
69
+ function hasAnyDIParam(resolvers) {
70
+ return resolvers.some((r) => r === null);
71
+ }
@@ -0,0 +1,29 @@
1
+ import { type ValidatorOptions } from 'class-validator';
2
+ import type { TokenRouteWithProvider } from '../container/ContainerConfiguration';
3
+ import type { Container } from '../container/container';
4
+ import { ProviderScope } from '../domain/provider-scope';
5
+ import { type CompiledRoute } from './CompiledRoute';
6
+ export interface RouteCompilerOptions {
7
+ container: Container;
8
+ controllerScopes: Map<any, ProviderScope>;
9
+ validationConfig?: ValidatorOptions;
10
+ hasOnRequestHook: boolean;
11
+ hasOnResponseHook: boolean;
12
+ }
13
+ export declare class RouteCompiler {
14
+ private container;
15
+ private controllerScopes;
16
+ private validationConfig?;
17
+ private hasOnRequestHook;
18
+ private hasOnResponseHook;
19
+ constructor(options: RouteCompilerOptions);
20
+ compile(route: TokenRouteWithProvider): CompiledRoute | null;
21
+ private classifyRoute;
22
+ private analyzeMethodParams;
23
+ private createSimpleRoute;
24
+ private createStandardRouteWithInstance;
25
+ private createStandardRoute;
26
+ private createComplexRoute;
27
+ private createFallbackRoute;
28
+ private createValidatedHandler;
29
+ }
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RouteCompiler = void 0;
4
+ const class_transformer_1 = require("class-transformer");
5
+ const class_validator_1 = require("class-validator");
6
+ const provider_scope_1 = require("../domain/provider-scope");
7
+ const Metadata_1 = require("../domain/Metadata");
8
+ const HttpException_1 = require("../exceptions/HttpException");
9
+ const getMethodArgTypes_1 = require("../utils/getMethodArgTypes");
10
+ const CompiledRoute_1 = require("./CompiledRoute");
11
+ const ParamResolverFactory_1 = require("./ParamResolverFactory");
12
+ const JITCompiler_1 = require("./JITCompiler");
13
+ class RouteCompiler {
14
+ constructor(options) {
15
+ this.container = options.container;
16
+ this.controllerScopes = options.controllerScopes;
17
+ this.validationConfig = options.validationConfig;
18
+ this.hasOnRequestHook = options.hasOnRequestHook;
19
+ this.hasOnResponseHook = options.hasOnResponseHook;
20
+ }
21
+ compile(route) {
22
+ if (!route || !route.provider) {
23
+ return null;
24
+ }
25
+ const provider = this.container.get(route.provider);
26
+ if (!provider) {
27
+ return this.createFallbackRoute(route);
28
+ }
29
+ const scope = this.controllerScopes.get(provider.token);
30
+ const isSingleton = scope === provider_scope_1.ProviderScope.SINGLETON;
31
+ const instance = isSingleton ? provider.instance : null;
32
+ if (!instance) {
33
+ return this.createStandardRoute(route, provider);
34
+ }
35
+ const paramInfos = this.analyzeMethodParams(instance, route.methodName);
36
+ const routeType = this.classifyRoute(route, paramInfos, isSingleton);
37
+ if (routeType === CompiledRoute_1.RouteType.SIMPLE) {
38
+ return this.createSimpleRoute(route, instance, paramInfos);
39
+ }
40
+ if (routeType === CompiledRoute_1.RouteType.STANDARD) {
41
+ return this.createStandardRouteWithInstance(route, instance, paramInfos);
42
+ }
43
+ return this.createComplexRoute(route, paramInfos);
44
+ }
45
+ classifyRoute(route, paramInfos, isSingleton) {
46
+ if (!isSingleton) {
47
+ return CompiledRoute_1.RouteType.COMPLEX;
48
+ }
49
+ const hasMiddlewares = route.middlewares.length > 0;
50
+ const hasDIParams = paramInfos.some((p) => p.type === 'di');
51
+ const hasHooks = this.hasOnRequestHook || this.hasOnResponseHook;
52
+ if (hasMiddlewares || hasDIParams || hasHooks) {
53
+ return CompiledRoute_1.RouteType.STANDARD;
54
+ }
55
+ return CompiledRoute_1.RouteType.SIMPLE;
56
+ }
57
+ analyzeMethodParams(instance, methodName) {
58
+ const argTypes = (0, getMethodArgTypes_1.getMethodArgTypes)(instance, methodName);
59
+ const decoratorMetas = Metadata_1.Metadata.getParamDecoratorFunc(instance, methodName);
60
+ return argTypes.map((token, index) => {
61
+ const meta = decoratorMetas?.[index];
62
+ return (0, ParamResolverFactory_1.analyzeParamDecorator)(meta, token);
63
+ });
64
+ }
65
+ createSimpleRoute(route, instance, paramInfos) {
66
+ const hasValidation = paramInfos.some((p) => p.needsValidation);
67
+ const validationIndices = paramInfos
68
+ .map((p, i) => (p.needsValidation ? i : -1))
69
+ .filter((i) => i >= 0);
70
+ const hasBodyParam = paramInfos.some((p) => p.type === 'body');
71
+ let boundHandler;
72
+ if (hasValidation) {
73
+ boundHandler = this.createValidatedHandler(instance, route.methodName, paramInfos, hasBodyParam);
74
+ }
75
+ else {
76
+ boundHandler = (0, JITCompiler_1.compileRouteHandler)(instance, route.methodName, paramInfos);
77
+ }
78
+ return {
79
+ routeType: CompiledRoute_1.RouteType.SIMPLE,
80
+ controllerInstance: instance,
81
+ boundHandler,
82
+ paramResolvers: [],
83
+ needsLocalsContainer: false,
84
+ hasMiddlewares: false,
85
+ hasValidation,
86
+ validationIndices,
87
+ isAsync: hasBodyParam,
88
+ original: route,
89
+ };
90
+ }
91
+ createStandardRouteWithInstance(route, instance, paramInfos) {
92
+ const hasValidation = paramInfos.some((p) => p.needsValidation);
93
+ const validationIndices = paramInfos
94
+ .map((p, i) => (p.needsValidation ? i : -1))
95
+ .filter((i) => i >= 0);
96
+ const hasDIParams = paramInfos.some((p) => p.type === 'di');
97
+ const hasBodyParam = paramInfos.some((p) => p.type === 'body');
98
+ const hasMiddlewares = route.middlewares.length > 0;
99
+ const needsLocalsContainer = hasDIParams || hasMiddlewares;
100
+ return {
101
+ routeType: CompiledRoute_1.RouteType.STANDARD,
102
+ controllerInstance: instance,
103
+ boundHandler: null,
104
+ paramResolvers: [],
105
+ needsLocalsContainer,
106
+ hasMiddlewares,
107
+ hasValidation,
108
+ validationIndices,
109
+ isAsync: hasBodyParam || hasDIParams,
110
+ original: route,
111
+ };
112
+ }
113
+ createStandardRoute(route, provider) {
114
+ return {
115
+ routeType: CompiledRoute_1.RouteType.STANDARD,
116
+ controllerInstance: null,
117
+ boundHandler: null,
118
+ paramResolvers: [],
119
+ needsLocalsContainer: true,
120
+ hasMiddlewares: route.middlewares.length > 0,
121
+ hasValidation: false,
122
+ validationIndices: [],
123
+ isAsync: true,
124
+ original: route,
125
+ };
126
+ }
127
+ createComplexRoute(route, paramInfos) {
128
+ const hasValidation = paramInfos.some((p) => p.needsValidation);
129
+ const validationIndices = paramInfos
130
+ .map((p, i) => (p.needsValidation ? i : -1))
131
+ .filter((i) => i >= 0);
132
+ return {
133
+ routeType: CompiledRoute_1.RouteType.COMPLEX,
134
+ controllerInstance: null,
135
+ boundHandler: null,
136
+ paramResolvers: [],
137
+ needsLocalsContainer: true,
138
+ hasMiddlewares: route.middlewares.length > 0,
139
+ hasValidation,
140
+ validationIndices,
141
+ isAsync: true,
142
+ original: route,
143
+ };
144
+ }
145
+ createFallbackRoute(route) {
146
+ return {
147
+ routeType: CompiledRoute_1.RouteType.COMPLEX,
148
+ controllerInstance: null,
149
+ boundHandler: null,
150
+ paramResolvers: [],
151
+ needsLocalsContainer: true,
152
+ hasMiddlewares: route.middlewares.length > 0,
153
+ hasValidation: false,
154
+ validationIndices: [],
155
+ isAsync: true,
156
+ original: route,
157
+ };
158
+ }
159
+ createValidatedHandler(instance, methodName, paramInfos, hasBodyParam) {
160
+ const handler = instance[methodName].bind(instance);
161
+ const config = this.validationConfig;
162
+ const resolveArg = (ctx, param) => {
163
+ let value;
164
+ switch (param.type) {
165
+ case 'param':
166
+ value = param.key ? ctx.param[param.key] : ctx.param;
167
+ break;
168
+ case 'query':
169
+ value = param.key ? ctx.query[param.key] : ctx.query;
170
+ break;
171
+ case 'body':
172
+ value = param.key ? ctx.body[param.key] : ctx.body;
173
+ break;
174
+ case 'headers':
175
+ value = param.key ? ctx.headers.get(param.key) : ctx.headers;
176
+ break;
177
+ case 'req':
178
+ value = ctx.req;
179
+ break;
180
+ case 'locals':
181
+ value = ctx.locals;
182
+ break;
183
+ default:
184
+ value = undefined;
185
+ }
186
+ if (param.needsValidation && param.token) {
187
+ const obj = (0, class_transformer_1.plainToInstance)(param.token, value);
188
+ const errors = (0, class_validator_1.validateSync)(obj, config);
189
+ if (errors.length > 0) {
190
+ throw new HttpException_1.HttpException(errors, 400);
191
+ }
192
+ return obj;
193
+ }
194
+ return value;
195
+ };
196
+ if (hasBodyParam) {
197
+ return async (ctx) => {
198
+ await ctx.getBody();
199
+ const args = paramInfos.map((p) => resolveArg(ctx, p));
200
+ return handler(...args);
201
+ };
202
+ }
203
+ return (ctx) => {
204
+ const args = paramInfos.map((p) => resolveArg(ctx, p));
205
+ return handler(...args);
206
+ };
207
+ }
208
+ }
209
+ exports.RouteCompiler = RouteCompiler;
@@ -1,10 +1,11 @@
1
1
  import { InjectorService, TokenRouteWithProvider } from "../container";
2
2
  import { Context, LocalsContainer } from "../domain";
3
+ import type { CompiledRoute } from "./CompiledRoute";
3
4
  declare class Router {
4
5
  private readonly jsonHeaders;
5
6
  private readonly textHeaders;
6
- executeRoute(route: TokenRouteWithProvider, injector: InjectorService, context: Context, locals: LocalsContainer): Promise<Response>;
7
- private mountResponse;
7
+ executeRoute(routeStore: CompiledRoute | TokenRouteWithProvider, injector: InjectorService, context: Context, locals: LocalsContainer): Promise<Response>;
8
+ mountResponse(result: unknown, context: Context): Response;
8
9
  private isNativeResponse;
9
10
  private isBodyInit;
10
11
  private createJsonResponse;
@@ -7,15 +7,23 @@ class Router {
7
7
  this.jsonHeaders = { "Content-Type": "application/json" };
8
8
  this.textHeaders = { "Content-Type": "text/html" };
9
9
  }
10
- async executeRoute(route, injector, context, locals) {
11
- const provider = injector.invoke(route.provider, locals);
12
- route.provider.instance = provider;
13
- // @ts-ignore
14
- if (!provider[route.methodName]) {
10
+ async executeRoute(routeStore, injector, context, locals) {
11
+ const isCompiled = routeStore.routeType !== undefined;
12
+ const tokenRoute = isCompiled
13
+ ? routeStore.original
14
+ : routeStore;
15
+ const controllerInstance = isCompiled
16
+ ? routeStore.controllerInstance
17
+ : null;
18
+ const controller = controllerInstance
19
+ ?? injector.resolveControllerInstance(tokenRoute.provider, locals);
20
+ if (!controller[tokenRoute.methodName]) {
15
21
  throw new Error("Controller not found");
16
22
  }
17
- const result = await injector.invokeRoute(route, context, locals);
18
- await injector.callHook(events_1.EventType.OnResponse, { context, result });
23
+ const result = await injector.invokeRoute(tokenRoute, context, locals, controller);
24
+ if (injector.hasOnResponseHook()) {
25
+ await injector.callHook(events_1.EventType.OnResponse, { context, result });
26
+ }
19
27
  return this.mountResponse(result, context);
20
28
  }
21
29
  mountResponse(result, context) {
@@ -21,5 +21,9 @@ export declare class Memoirist<T> {
21
21
  private static regex;
22
22
  add(method: string, path: string, store: T): FindResult<T>['store'];
23
23
  find(method: string, url: string): FindResult<T> | null;
24
+ updateStore(method: string, path: string, oldStore: T, newStore: T): boolean;
25
+ private updateHistoryStore;
26
+ private normalizePath;
27
+ private findNode;
24
28
  }
25
29
  export default Memoirist;