@carno.js/core 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Carno.d.ts +9 -7
- package/dist/Carno.js +14 -1
- package/dist/commons/decorators/index.d.ts +1 -0
- package/dist/commons/decorators/index.js +1 -0
- package/dist/commons/decorators/validation.decorator.d.ts +32 -0
- package/dist/commons/decorators/validation.decorator.js +40 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/container/InjectorService.d.ts +3 -1
- package/dist/container/InjectorService.js +4 -3
- package/dist/container/MethodInvoker.d.ts +3 -2
- package/dist/container/MethodInvoker.js +4 -17
- package/dist/exceptions/HttpException.js +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/route/ParamResolverFactory.d.ts +0 -5
- package/dist/route/ParamResolverFactory.js +0 -40
- package/dist/route/RouteCompiler.d.ts +3 -3
- package/dist/route/RouteCompiler.js +2 -11
- package/dist/route/memoirist.js +4 -0
- package/dist/utils/ValidationCache.d.ts +2 -0
- package/dist/utils/ValidationCache.js +10 -2
- package/dist/utils/formatValidationErrors.d.ts +5 -0
- package/dist/utils/formatValidationErrors.js +80 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/validation/ValidatorAdapter.d.ts +66 -0
- package/dist/validation/ValidatorAdapter.js +20 -0
- package/dist/validation/adapters/ClassValidatorAdapter.d.ts +23 -0
- package/dist/validation/adapters/ClassValidatorAdapter.js +47 -0
- package/dist/validation/adapters/ZodAdapter.d.ts +14 -0
- package/dist/validation/adapters/ZodAdapter.js +56 -0
- package/dist/validation/adapters/index.d.ts +4 -0
- package/dist/validation/adapters/index.js +7 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +20 -0
- package/package.json +17 -6
- package/dist/Cheetah.d.ts +0 -65
- package/dist/Cheetah.js +0 -307
- package/dist/default-routes-cheetah.d.ts +0 -3
- package/dist/default-routes-cheetah.js +0 -29
- package/dist/domain/CheetahClosure.d.ts +0 -1
- package/dist/domain/CheetahClosure.js +0 -2
- package/dist/domain/CheetahMiddleware.d.ts +0 -5
- package/dist/domain/CheetahMiddleware.js +0 -2
- package/dist/services/request-logger.service.d.ts +0 -15
- package/dist/services/request-logger.service.js +0 -50
- package/dist/utils/isClassValidator.d.ts +0 -6
- package/dist/utils/isClassValidator.js +0 -13
package/dist/Carno.d.ts
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { Server } from "bun";
|
|
2
|
-
import { ValidatorOptions } from "class-validator";
|
|
3
2
|
import * as pino from "pino";
|
|
3
|
+
import type { ValidationConfig, ValidatorAdapterConstructor } from "./validation/ValidatorAdapter";
|
|
4
4
|
import { TokenRouteWithProvider } from "./container/ContainerConfiguration";
|
|
5
5
|
import { CorsConfig } from "./domain/cors-config";
|
|
6
6
|
import Memoirist from "./route/memoirist";
|
|
7
7
|
import { type CompiledRoute } from "./route/CompiledRoute";
|
|
8
|
-
export interface ApplicationConfig {
|
|
9
|
-
validation?:
|
|
8
|
+
export interface ApplicationConfig<TAdapter extends ValidatorAdapterConstructor = ValidatorAdapterConstructor> {
|
|
9
|
+
validation?: ValidationConfig<TAdapter>;
|
|
10
10
|
logger?: pino.LoggerOptions;
|
|
11
11
|
exports?: any[];
|
|
12
12
|
providers?: any[];
|
|
13
13
|
cors?: CorsConfig;
|
|
14
14
|
globalMiddlewares?: any[];
|
|
15
15
|
}
|
|
16
|
-
export declare class Carno {
|
|
17
|
-
config: ApplicationConfig
|
|
16
|
+
export declare class Carno<TAdapter extends ValidatorAdapterConstructor = ValidatorAdapterConstructor> {
|
|
17
|
+
config: ApplicationConfig<TAdapter>;
|
|
18
18
|
router: Memoirist<CompiledRoute | TokenRouteWithProvider>;
|
|
19
19
|
private injector;
|
|
20
20
|
private corsCache?;
|
|
21
21
|
private readonly emptyLocals;
|
|
22
|
+
private validatorAdapter;
|
|
22
23
|
private fetch;
|
|
23
24
|
private server;
|
|
24
|
-
constructor(config?: ApplicationConfig);
|
|
25
|
+
constructor(config?: ApplicationConfig<TAdapter>);
|
|
26
|
+
private resolveValidatorAdapter;
|
|
25
27
|
/**
|
|
26
28
|
* Use the Carno plugin.
|
|
27
29
|
*
|
|
@@ -49,7 +51,7 @@ export declare class Carno {
|
|
|
49
51
|
listen(port?: number): Promise<void>;
|
|
50
52
|
private registerShutdownHandlers;
|
|
51
53
|
getHttpServer(): Server<any>;
|
|
52
|
-
getInjector(): import("
|
|
54
|
+
getInjector(): import("./container").InjectorService;
|
|
53
55
|
private createHttpServer;
|
|
54
56
|
private fetcher;
|
|
55
57
|
private catcher;
|
package/dist/Carno.js
CHANGED
|
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Carno = void 0;
|
|
7
7
|
const node_process_1 = __importDefault(require("node:process"));
|
|
8
|
+
const ZodAdapter_1 = require("./validation/adapters/ZodAdapter");
|
|
9
|
+
const ValidationCache_1 = require("./utils/ValidationCache");
|
|
8
10
|
const index_1 = require("./commons/index");
|
|
9
11
|
const constants_1 = require("./constants");
|
|
10
12
|
const createContainer_1 = require("./container/createContainer");
|
|
@@ -56,11 +58,21 @@ class Carno {
|
|
|
56
58
|
console.error("Unhandled error:", error);
|
|
57
59
|
return new Response("Internal Server Error", { status: 500 });
|
|
58
60
|
};
|
|
61
|
+
this.validatorAdapter = this.resolveValidatorAdapter();
|
|
59
62
|
if (config.cors) {
|
|
60
63
|
this.corsCache = new cors_headers_cache_1.CorsHeadersCache(config.cors);
|
|
61
64
|
}
|
|
62
65
|
void this.bootstrapApplication();
|
|
63
66
|
}
|
|
67
|
+
resolveValidatorAdapter() {
|
|
68
|
+
const config = this.config.validation;
|
|
69
|
+
if (!config?.adapter) {
|
|
70
|
+
return new ZodAdapter_1.ZodAdapter();
|
|
71
|
+
}
|
|
72
|
+
const AdapterClass = config.adapter;
|
|
73
|
+
const options = config.options || {};
|
|
74
|
+
return new AdapterClass(options);
|
|
75
|
+
}
|
|
64
76
|
/**
|
|
65
77
|
* Use the Carno plugin.
|
|
66
78
|
*
|
|
@@ -148,8 +160,9 @@ class Carno {
|
|
|
148
160
|
};
|
|
149
161
|
}
|
|
150
162
|
async init() {
|
|
163
|
+
(0, ValidationCache_1.setValidatorAdapter)(this.validatorAdapter);
|
|
151
164
|
this.loadProvidersAndControllers();
|
|
152
|
-
await this.injector.loadModule((0, createContainer_1.createContainer)(), this.config, this.router);
|
|
165
|
+
await this.injector.loadModule((0, createContainer_1.createContainer)(), this.config, this.router, this.validatorAdapter);
|
|
153
166
|
}
|
|
154
167
|
async listen(port = 3000) {
|
|
155
168
|
this.registerShutdownHandlers();
|
|
@@ -19,3 +19,4 @@ __exportStar(require("./http.decorators"), exports);
|
|
|
19
19
|
__exportStar(require("./service.decorator"), exports);
|
|
20
20
|
__exportStar(require("./middleware.decorator"), exports);
|
|
21
21
|
__exportStar(require("./Injectable.decorator"), exports);
|
|
22
|
+
__exportStar(require("./validation.decorator"), exports);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Decorator to attach a Zod schema to a DTO class
|
|
4
|
+
* The schema will be used for validation when the DTO is used in route handlers
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const CreateUserSchema = z.object({
|
|
9
|
+
* name: z.string().min(3),
|
|
10
|
+
* email: z.string().email()
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* @ZodSchema(CreateUserSchema)
|
|
14
|
+
* class CreateUserDto {
|
|
15
|
+
* name: string;
|
|
16
|
+
* email: string;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* @Controller('/users')
|
|
20
|
+
* class UserController {
|
|
21
|
+
* @Post()
|
|
22
|
+
* create(@Body() dto: CreateUserDto) {
|
|
23
|
+
* // dto is validated and typed
|
|
24
|
+
* return dto;
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @param schema - The Zod schema to use for validation
|
|
30
|
+
* @returns Class decorator
|
|
31
|
+
*/
|
|
32
|
+
export declare function ZodSchema<T extends z.ZodType>(schema: T): ClassDecorator;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZodSchema = ZodSchema;
|
|
4
|
+
const Metadata_1 = require("../../domain/Metadata");
|
|
5
|
+
const constants_1 = require("../../constants");
|
|
6
|
+
/**
|
|
7
|
+
* Decorator to attach a Zod schema to a DTO class
|
|
8
|
+
* The schema will be used for validation when the DTO is used in route handlers
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const CreateUserSchema = z.object({
|
|
13
|
+
* name: z.string().min(3),
|
|
14
|
+
* email: z.string().email()
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* @ZodSchema(CreateUserSchema)
|
|
18
|
+
* class CreateUserDto {
|
|
19
|
+
* name: string;
|
|
20
|
+
* email: string;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* @Controller('/users')
|
|
24
|
+
* class UserController {
|
|
25
|
+
* @Post()
|
|
26
|
+
* create(@Body() dto: CreateUserDto) {
|
|
27
|
+
* // dto is validated and typed
|
|
28
|
+
* return dto;
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @param schema - The Zod schema to use for validation
|
|
34
|
+
* @returns Class decorator
|
|
35
|
+
*/
|
|
36
|
+
function ZodSchema(schema) {
|
|
37
|
+
return (target) => {
|
|
38
|
+
Metadata_1.Metadata.set(constants_1.VALIDATION_ZOD_SCHEMA, schema, target);
|
|
39
|
+
};
|
|
40
|
+
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export declare const CONTROLLER_EVENTS = "carno:controller:events";
|
|
|
5
5
|
export declare const ROUTE_PARAM = "carno:route:param";
|
|
6
6
|
export declare const ROUTE_MIDDLEWARES = "carno:route:middlewares";
|
|
7
7
|
export declare const PROVIDER = "carno:provider";
|
|
8
|
+
export declare const VALIDATION_ZOD_SCHEMA = "carno:validation:zod";
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PROVIDER = exports.ROUTE_MIDDLEWARES = exports.ROUTE_PARAM = exports.CONTROLLER_EVENTS = exports.CONTROLLER_MIDDLEWARES = exports.CONTROLLER_ROUTES = exports.CONTROLLER = void 0;
|
|
3
|
+
exports.VALIDATION_ZOD_SCHEMA = exports.PROVIDER = exports.ROUTE_MIDDLEWARES = exports.ROUTE_PARAM = exports.CONTROLLER_EVENTS = exports.CONTROLLER_MIDDLEWARES = exports.CONTROLLER_ROUTES = exports.CONTROLLER = void 0;
|
|
4
4
|
exports.CONTROLLER = "carno:controller";
|
|
5
5
|
exports.CONTROLLER_ROUTES = "carno:controller:routes";
|
|
6
6
|
exports.CONTROLLER_MIDDLEWARES = "carno:controller:middlewares";
|
|
@@ -8,3 +8,4 @@ exports.CONTROLLER_EVENTS = "carno:controller:events";
|
|
|
8
8
|
exports.ROUTE_PARAM = "carno:route:param";
|
|
9
9
|
exports.ROUTE_MIDDLEWARES = "carno:route:middlewares";
|
|
10
10
|
exports.PROVIDER = "carno:provider";
|
|
11
|
+
exports.VALIDATION_ZOD_SCHEMA = "carno:validation:zod";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ApplicationConfig } from "../Carno";
|
|
2
2
|
import { TokenProvider } from "../commons/registries/ProviderControl";
|
|
3
|
+
import type { ValidatorAdapter } from "../validation/ValidatorAdapter";
|
|
3
4
|
import { Context } from "../domain/Context";
|
|
4
5
|
import { LocalsContainer } from "../domain/LocalsContainer";
|
|
5
6
|
import { Provider } from "../domain/provider";
|
|
@@ -20,7 +21,8 @@ export declare class InjectorService {
|
|
|
20
21
|
private routeResolver;
|
|
21
22
|
private dependencyResolver;
|
|
22
23
|
private methodInvoker;
|
|
23
|
-
|
|
24
|
+
private validatorAdapter;
|
|
25
|
+
loadModule(container: Container, applicationConfig: ApplicationConfig, router: Memoirist<any>, validatorAdapter: ValidatorAdapter): Promise<void>;
|
|
24
26
|
private initializeResolvers;
|
|
25
27
|
private ensureProvider;
|
|
26
28
|
get(token: TokenProvider): Provider | undefined;
|
|
@@ -40,10 +40,11 @@ let InjectorService = InjectorService_1 = class InjectorService {
|
|
|
40
40
|
this._hasOnResponseHook = false;
|
|
41
41
|
this.controllerScopes = new Map();
|
|
42
42
|
}
|
|
43
|
-
async loadModule(container, applicationConfig, router) {
|
|
43
|
+
async loadModule(container, applicationConfig, router, validatorAdapter) {
|
|
44
44
|
this.container = container;
|
|
45
45
|
this.router = router;
|
|
46
46
|
this.applicationConfig = applicationConfig;
|
|
47
|
+
this.validatorAdapter = validatorAdapter;
|
|
47
48
|
this.initializeResolvers();
|
|
48
49
|
this.removeUnknownProviders();
|
|
49
50
|
this.saveInjector();
|
|
@@ -57,7 +58,7 @@ let InjectorService = InjectorService_1 = class InjectorService {
|
|
|
57
58
|
initializeResolvers() {
|
|
58
59
|
this.routeResolver = new RouteResolver_1.RouteResolver(this.router, this.applicationConfig.globalMiddlewares);
|
|
59
60
|
this.dependencyResolver = new DependencyResolver_1.DependencyResolver(this.container);
|
|
60
|
-
this.methodInvoker = new MethodInvoker_1.MethodInvoker(this.applicationConfig);
|
|
61
|
+
this.methodInvoker = new MethodInvoker_1.MethodInvoker(this.applicationConfig, this.validatorAdapter);
|
|
61
62
|
}
|
|
62
63
|
ensureProvider(token) {
|
|
63
64
|
if (!this.container.has(token) && ProviderControl_1.GlobalProvider.has(token)) {
|
|
@@ -175,7 +176,7 @@ let InjectorService = InjectorService_1 = class InjectorService {
|
|
|
175
176
|
const compiler = new RouteCompiler_1.RouteCompiler({
|
|
176
177
|
container: this.container,
|
|
177
178
|
controllerScopes: this.controllerScopes,
|
|
178
|
-
|
|
179
|
+
validatorAdapter: this.validatorAdapter,
|
|
179
180
|
hasOnRequestHook: this._hasOnRequestHook,
|
|
180
181
|
hasOnResponseHook: this._hasOnResponseHook,
|
|
181
182
|
});
|
|
@@ -2,10 +2,12 @@ import { ApplicationConfig } from "../Carno";
|
|
|
2
2
|
import { TokenProvider } from "../commons/registries/ProviderControl";
|
|
3
3
|
import { Context } from "../domain/Context";
|
|
4
4
|
import { LocalsContainer } from "../domain/LocalsContainer";
|
|
5
|
+
import type { ValidatorAdapter } from "../validation/ValidatorAdapter";
|
|
5
6
|
export declare class MethodInvoker {
|
|
6
7
|
private applicationConfig;
|
|
8
|
+
private validatorAdapter;
|
|
7
9
|
private historyMethods;
|
|
8
|
-
constructor(applicationConfig: ApplicationConfig);
|
|
10
|
+
constructor(applicationConfig: ApplicationConfig, validatorAdapter: ValidatorAdapter);
|
|
9
11
|
invoke(instance: any, methodName: string, locals: LocalsContainer, context: Context, invokeCallback: (token: TokenProvider, locals: LocalsContainer) => any): Promise<any>;
|
|
10
12
|
private getMethodInfo;
|
|
11
13
|
private getCachedMethod;
|
|
@@ -16,5 +18,4 @@ export declare class MethodInvoker {
|
|
|
16
18
|
private hasBodyParam;
|
|
17
19
|
private isBodyParam;
|
|
18
20
|
private resolveService;
|
|
19
|
-
private validateAndTransform;
|
|
20
21
|
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MethodInvoker = void 0;
|
|
4
|
-
const class_transformer_1 = require("class-transformer");
|
|
5
|
-
const class_validator_1 = require("class-validator");
|
|
6
4
|
const Metadata_1 = require("../domain/Metadata");
|
|
7
|
-
const HttpException_1 = require("../exceptions/HttpException");
|
|
8
5
|
const getClassOrSymbol_1 = require("../utils/getClassOrSymbol");
|
|
9
6
|
const getMethodArgTypes_1 = require("../utils/getMethodArgTypes");
|
|
10
|
-
const isClassValidator_1 = require("../utils/isClassValidator");
|
|
11
7
|
class MethodInvoker {
|
|
12
|
-
constructor(applicationConfig) {
|
|
8
|
+
constructor(applicationConfig, validatorAdapter) {
|
|
13
9
|
this.applicationConfig = applicationConfig;
|
|
10
|
+
this.validatorAdapter = validatorAdapter;
|
|
14
11
|
this.historyMethods = new WeakMap();
|
|
15
12
|
}
|
|
16
13
|
async invoke(instance, methodName, locals, context, invokeCallback) {
|
|
@@ -78,19 +75,9 @@ class MethodInvoker {
|
|
|
78
75
|
return invokeCallback((0, getClassOrSymbol_1.getClassOrSymbol)(token), locals);
|
|
79
76
|
}
|
|
80
77
|
const value = param.fun(context, param.param);
|
|
81
|
-
return
|
|
82
|
-
? this.validateAndTransform(token, value)
|
|
78
|
+
return this.validatorAdapter.hasValidation(token)
|
|
79
|
+
? this.validatorAdapter.validateAndTransform(token, value)
|
|
83
80
|
: value;
|
|
84
81
|
}
|
|
85
|
-
validateAndTransform(token, value) {
|
|
86
|
-
const obj = (0, class_transformer_1.plainToInstance)(token, value);
|
|
87
|
-
const errors = (0, class_validator_1.validateSync)(obj, this.applicationConfig.validation);
|
|
88
|
-
// todo: deve retornar apenas os erros e no o objeto class-validator intei
|
|
89
|
-
// ro.
|
|
90
|
-
if (errors.length > 0) {
|
|
91
|
-
throw new HttpException_1.HttpException(errors, 400);
|
|
92
|
-
}
|
|
93
|
-
return obj;
|
|
94
|
-
}
|
|
95
82
|
}
|
|
96
83
|
exports.MethodInvoker = MethodInvoker;
|
|
@@ -9,12 +9,12 @@ class HttpException {
|
|
|
9
9
|
this.initMessage();
|
|
10
10
|
}
|
|
11
11
|
initMessage() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this.message = this.response;
|
|
12
|
+
const formatted = (0, utils_1.formatValidationErrors)(this.response);
|
|
13
|
+
if ((0, utils_1.isObject)(formatted)) {
|
|
14
|
+
this.message = formatted;
|
|
15
|
+
return;
|
|
17
16
|
}
|
|
17
|
+
this.message = formatted;
|
|
18
18
|
}
|
|
19
19
|
getResponse() {
|
|
20
20
|
return this.message;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -29,3 +29,4 @@ __exportStar(require("./services/logger.service"), exports);
|
|
|
29
29
|
__exportStar(require("./cache/cache.service"), exports);
|
|
30
30
|
__exportStar(require("./cache/bento-cache.driver"), exports);
|
|
31
31
|
__exportStar(require("./testing"), exports);
|
|
32
|
+
__exportStar(require("./validation"), exports);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { type ValidatorOptions } from 'class-validator';
|
|
2
1
|
import type { Context } from '../domain/Context';
|
|
3
|
-
import type { ParamResolver, AsyncParamResolver } from './CompiledRoute';
|
|
4
2
|
export type ParamDecoratorType = 'body' | 'query' | 'param' | 'headers' | 'req' | 'locals';
|
|
5
3
|
export interface ParamDecoratorMeta {
|
|
6
4
|
fun: (context: Context, data?: any) => any;
|
|
@@ -14,6 +12,3 @@ export interface ParamInfo {
|
|
|
14
12
|
token?: any;
|
|
15
13
|
}
|
|
16
14
|
export declare function analyzeParamDecorator(decoratorMeta: ParamDecoratorMeta | undefined, token: any): ParamInfo;
|
|
17
|
-
export declare function createParamResolver(decoratorMeta: ParamDecoratorMeta | undefined, token: any, validationConfig?: ValidatorOptions): ParamResolver | AsyncParamResolver | null;
|
|
18
|
-
export declare function createParamResolvers(paramMetas: Record<number, ParamDecoratorMeta> | undefined, argTypes: any[], validationConfig?: ValidatorOptions): (ParamResolver | AsyncParamResolver | null)[];
|
|
19
|
-
export declare function hasAnyDIParam(resolvers: (ParamResolver | AsyncParamResolver | null)[]): boolean;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
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
4
|
const ValidationCache_1 = require("../utils/ValidationCache");
|
|
11
5
|
function analyzeParamDecorator(decoratorMeta, token) {
|
|
12
6
|
if (!decoratorMeta) {
|
|
@@ -53,37 +47,3 @@ function inferTypeFromSource(resolver) {
|
|
|
53
47
|
}
|
|
54
48
|
return null;
|
|
55
49
|
}
|
|
56
|
-
function createValidationResolver(extractFn, token, validationConfig) {
|
|
57
|
-
return (context) => {
|
|
58
|
-
const value = extractFn(context);
|
|
59
|
-
const obj = (0, class_transformer_1.plainToInstance)(token, value);
|
|
60
|
-
const errors = (0, class_validator_1.validateSync)(obj, validationConfig);
|
|
61
|
-
if (errors.length > 0) {
|
|
62
|
-
throw new HttpException_1.HttpException(errors, 400);
|
|
63
|
-
}
|
|
64
|
-
return obj;
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function createParamResolver(decoratorMeta, token, validationConfig) {
|
|
68
|
-
if (!decoratorMeta) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
const extractFn = (context) => decoratorMeta.fun(context, decoratorMeta.param);
|
|
72
|
-
const needsValidation = typeof token === 'function' && (0, ValidationCache_1.isValidatable)(token);
|
|
73
|
-
if (needsValidation) {
|
|
74
|
-
return createValidationResolver(extractFn, token, validationConfig);
|
|
75
|
-
}
|
|
76
|
-
return extractFn;
|
|
77
|
-
}
|
|
78
|
-
function createParamResolvers(paramMetas, argTypes, validationConfig) {
|
|
79
|
-
const resolvers = [];
|
|
80
|
-
for (let i = 0; i < argTypes.length; i++) {
|
|
81
|
-
const meta = paramMetas?.[i];
|
|
82
|
-
const token = argTypes[i];
|
|
83
|
-
resolvers.push(createParamResolver(meta, token, validationConfig));
|
|
84
|
-
}
|
|
85
|
-
return resolvers;
|
|
86
|
-
}
|
|
87
|
-
function hasAnyDIParam(resolvers) {
|
|
88
|
-
return resolvers.some((r) => r === null);
|
|
89
|
-
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { type ValidatorOptions } from 'class-validator';
|
|
2
1
|
import type { TokenRouteWithProvider } from '../container/ContainerConfiguration';
|
|
2
|
+
import type { ValidatorAdapter } from '../validation/ValidatorAdapter';
|
|
3
3
|
import type { Container } from '../container/container';
|
|
4
4
|
import { ProviderScope } from '../domain/provider-scope';
|
|
5
5
|
import { type CompiledRoute } from './CompiledRoute';
|
|
6
6
|
export interface RouteCompilerOptions {
|
|
7
7
|
container: Container;
|
|
8
8
|
controllerScopes: Map<any, ProviderScope>;
|
|
9
|
-
|
|
9
|
+
validatorAdapter: ValidatorAdapter;
|
|
10
10
|
hasOnRequestHook: boolean;
|
|
11
11
|
hasOnResponseHook: boolean;
|
|
12
12
|
}
|
|
13
13
|
export declare class RouteCompiler {
|
|
14
14
|
private container;
|
|
15
15
|
private controllerScopes;
|
|
16
|
-
private
|
|
16
|
+
private validatorAdapter;
|
|
17
17
|
private hasOnRequestHook;
|
|
18
18
|
private hasOnResponseHook;
|
|
19
19
|
constructor(options: RouteCompilerOptions);
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RouteCompiler = void 0;
|
|
4
|
-
const class_transformer_1 = require("class-transformer");
|
|
5
|
-
const class_validator_1 = require("class-validator");
|
|
6
4
|
const provider_scope_1 = require("../domain/provider-scope");
|
|
7
5
|
const Metadata_1 = require("../domain/Metadata");
|
|
8
|
-
const HttpException_1 = require("../exceptions/HttpException");
|
|
9
6
|
const getMethodArgTypes_1 = require("../utils/getMethodArgTypes");
|
|
10
7
|
const CompiledRoute_1 = require("./CompiledRoute");
|
|
11
8
|
const ParamResolverFactory_1 = require("./ParamResolverFactory");
|
|
@@ -14,7 +11,7 @@ class RouteCompiler {
|
|
|
14
11
|
constructor(options) {
|
|
15
12
|
this.container = options.container;
|
|
16
13
|
this.controllerScopes = options.controllerScopes;
|
|
17
|
-
this.
|
|
14
|
+
this.validatorAdapter = options.validatorAdapter;
|
|
18
15
|
this.hasOnRequestHook = options.hasOnRequestHook;
|
|
19
16
|
this.hasOnResponseHook = options.hasOnResponseHook;
|
|
20
17
|
}
|
|
@@ -158,7 +155,6 @@ class RouteCompiler {
|
|
|
158
155
|
}
|
|
159
156
|
createValidatedHandler(instance, methodName, paramInfos, hasBodyParam) {
|
|
160
157
|
const handler = instance[methodName].bind(instance);
|
|
161
|
-
const config = this.validationConfig;
|
|
162
158
|
const resolveArg = (ctx, param) => {
|
|
163
159
|
let value;
|
|
164
160
|
switch (param.type) {
|
|
@@ -184,12 +180,7 @@ class RouteCompiler {
|
|
|
184
180
|
value = undefined;
|
|
185
181
|
}
|
|
186
182
|
if (param.needsValidation && param.token) {
|
|
187
|
-
|
|
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;
|
|
183
|
+
return this.validatorAdapter.validateAndTransform(param.token, value);
|
|
193
184
|
}
|
|
194
185
|
return value;
|
|
195
186
|
};
|
package/dist/route/memoirist.js
CHANGED
|
@@ -179,6 +179,10 @@ class Memoirist {
|
|
|
179
179
|
}
|
|
180
180
|
if (node.params?.store === oldStore) {
|
|
181
181
|
node.params.store = newStore;
|
|
182
|
+
const paramName = node.params.names.get(oldStore);
|
|
183
|
+
if (paramName) {
|
|
184
|
+
node.params.names.set(newStore, paramName);
|
|
185
|
+
}
|
|
182
186
|
this.updateHistoryStore(method, path, newStore);
|
|
183
187
|
return true;
|
|
184
188
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ValidatorAdapter } from '../validation/ValidatorAdapter';
|
|
2
|
+
export declare function setValidatorAdapter(adapter: ValidatorAdapter): void;
|
|
1
3
|
export declare function isValidatable(token: Function): boolean;
|
|
2
4
|
export declare function preloadValidationForParams(args: any[]): number[];
|
|
3
5
|
export declare function clearValidationCache(): void;
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setValidatorAdapter = setValidatorAdapter;
|
|
3
4
|
exports.isValidatable = isValidatable;
|
|
4
5
|
exports.preloadValidationForParams = preloadValidationForParams;
|
|
5
6
|
exports.clearValidationCache = clearValidationCache;
|
|
6
|
-
|
|
7
|
+
let currentAdapter = null;
|
|
7
8
|
const cache = new Map();
|
|
9
|
+
function setValidatorAdapter(adapter) {
|
|
10
|
+
currentAdapter = adapter;
|
|
11
|
+
cache.clear();
|
|
12
|
+
}
|
|
8
13
|
function isValidatable(token) {
|
|
14
|
+
if (!currentAdapter) {
|
|
15
|
+
throw new Error('Validator adapter not initialized. Call setValidatorAdapter() first.');
|
|
16
|
+
}
|
|
9
17
|
let result = cache.get(token);
|
|
10
18
|
if (result === undefined) {
|
|
11
|
-
result =
|
|
19
|
+
result = currentAdapter.hasValidation(token);
|
|
12
20
|
cache.set(token, result);
|
|
13
21
|
}
|
|
14
22
|
return result;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatValidationErrors = formatValidationErrors;
|
|
4
|
+
function formatValidationErrors(value) {
|
|
5
|
+
if (!shouldFormatErrors(value)) {
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
return collectIssues(value);
|
|
9
|
+
}
|
|
10
|
+
function shouldFormatErrors(value) {
|
|
11
|
+
if (!Array.isArray(value)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (value.length === 0) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return isValidationError(value[0]);
|
|
18
|
+
}
|
|
19
|
+
function isValidationError(value) {
|
|
20
|
+
if (!value) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (typeof value !== "object") {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return hasValidationShape(value);
|
|
27
|
+
}
|
|
28
|
+
function hasValidationShape(value) {
|
|
29
|
+
if ("constraints" in value) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
if ("property" in value) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if ("children" in value) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
function collectIssues(errors) {
|
|
41
|
+
const issues = [];
|
|
42
|
+
for (const error of errors) {
|
|
43
|
+
appendIssues(error, "", issues);
|
|
44
|
+
}
|
|
45
|
+
return issues;
|
|
46
|
+
}
|
|
47
|
+
function appendIssues(error, prefix, issues) {
|
|
48
|
+
const field = buildField(prefix, error.property);
|
|
49
|
+
appendConstraints(error, field, issues);
|
|
50
|
+
appendChildren(error, field, issues);
|
|
51
|
+
}
|
|
52
|
+
function appendConstraints(error, field, issues) {
|
|
53
|
+
const constraints = error.constraints;
|
|
54
|
+
if (!constraints) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const messages = Object.values(constraints);
|
|
58
|
+
if (messages.length === 0) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
issues.push({ field, messages });
|
|
62
|
+
}
|
|
63
|
+
function appendChildren(error, prefix, issues) {
|
|
64
|
+
const children = error.children;
|
|
65
|
+
if (!children || children.length === 0) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const child of children) {
|
|
69
|
+
appendIssues(child, prefix, issues);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function buildField(prefix, property) {
|
|
73
|
+
if (!property) {
|
|
74
|
+
return prefix || "body";
|
|
75
|
+
}
|
|
76
|
+
if (!prefix) {
|
|
77
|
+
return property;
|
|
78
|
+
}
|
|
79
|
+
return `${prefix}.${property}`;
|
|
80
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export * from './isString';
|
|
|
4
4
|
export * from './isFunction';
|
|
5
5
|
export * from './getConstructorArgNames';
|
|
6
6
|
export * from './getValue';
|
|
7
|
-
export * from './isClassValidator';
|
|
8
7
|
export * from './getMethodArgTypes';
|
|
9
8
|
export * from './getClassOrSymbol';
|
|
10
9
|
export * from './isRequestScope';
|
|
@@ -13,3 +12,4 @@ export * from './isPrimitiveType';
|
|
|
13
12
|
export * from './setValue';
|
|
14
13
|
export * from './isClass';
|
|
15
14
|
export * from './methodsOf';
|
|
15
|
+
export * from './formatValidationErrors';
|
package/dist/utils/index.js
CHANGED
|
@@ -20,7 +20,6 @@ __exportStar(require("./isString"), exports);
|
|
|
20
20
|
__exportStar(require("./isFunction"), exports);
|
|
21
21
|
__exportStar(require("./getConstructorArgNames"), exports);
|
|
22
22
|
__exportStar(require("./getValue"), exports);
|
|
23
|
-
__exportStar(require("./isClassValidator"), exports);
|
|
24
23
|
__exportStar(require("./getMethodArgTypes"), exports);
|
|
25
24
|
__exportStar(require("./getClassOrSymbol"), exports);
|
|
26
25
|
__exportStar(require("./isRequestScope"), exports);
|
|
@@ -29,3 +28,4 @@ __exportStar(require("./isPrimitiveType"), exports);
|
|
|
29
28
|
__exportStar(require("./setValue"), exports);
|
|
30
29
|
__exportStar(require("./isClass"), exports);
|
|
31
30
|
__exportStar(require("./methodsOf"), exports);
|
|
31
|
+
__exportStar(require("./formatValidationErrors"), exports);
|