codeweaver 1.0.14 → 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/README.md CHANGED
@@ -2,25 +2,19 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- **Codeweaver** is a lightweight framework built on top of `Express` and `TypeScript`, integrating `Swagger` for API documentation. The application utilizes `async handlers` for improved error management and follows a modular structure for routers, enabling easy expansion and organization of the application.
5
+ **Codeweaver** is a lightweight microframework created with `Express`, `TypeScript`, and `Zod` (v4), seamlessly integrated with `Swagger` for comprehensive API documentation. Its modular architecture for routers promotes scalability and organized development, making it easy to expand and maintain.
6
6
 
7
- ## Features
8
-
9
- - **Modular Router Structure**: Each router is automatically imported and mounted, providing clean separation of endpoints and logic.
10
- - **Express Framework**: A lightweight web application framework for building web applications in Node.js.
11
- - **TypeScript**: Provides strong typing for better development experience and less runtime errors.
12
- - **Swagger Integration**: Automatically generates interactive API documentation, making it easy for developers and consumers to understand the available endpoints.
13
- - **Async Handlers**: Supports async/await syntax for writing cleaner and more maintainable asynchronous code without deeply nested callbacks.
14
-
15
- ## Technologies Used
7
+ ## Features and Technologies Used
16
8
 
17
9
  - **Node.js**
18
- - **Express**
19
- - **TypeScript**
20
- - **Zod** (for input validation)
21
- - **ts-zod-decorators** (for validation using Zod with decorators)
22
- - **utils-decorators** (for middleware utilities like throttling and error handling)
23
- - **Swagger** (for API documentation)
10
+ - **Express**: A lightweight web framework for building server-side applications in Node.js.
11
+ - **TypeScript**: Adds strong typing for enhanced development experience and reduced runtime errors.
12
+ - **Modular Router Structure**: Automates importing and mounting routers, ensuring a clean separation of endpoints and logic for easier scalability.
13
+ - **Swagger Integration**: Automatically generates interactive API documentation, facilitating easier understanding of available endpoints for developers and consumers.
14
+ - **Async Handlers**: Utilizes async/await syntax for cleaner, more maintainable asynchronous code without callback nesting.
15
+ - **Zod**: Implements schema validation for input data.
16
+ - **ts-zod-decorators**: Enables validation using Zod schemas through decorators.
17
+ - **utils-decorators**: Provides middleware utilities such as throttling and error handling for a more robust application.
24
18
 
25
19
  ## Installation
26
20
 
@@ -29,6 +23,7 @@ To get started with the project, follow these steps:
29
23
  1. **Clone the repository**:
30
24
 
31
25
  ```bash
26
+ npm install -g codeweaver
32
27
  npx create-codeweaver-app my-app
33
28
  cd my-app
34
29
  ```
@@ -51,6 +46,7 @@ To get started with the project, follow these steps:
51
46
 
52
47
  ```bash
53
48
  npm run build
49
+ npm run serve
54
50
  ```
55
51
 
56
52
  ## Sample Project Structure
@@ -84,30 +80,106 @@ To get started with the project, follow these steps:
84
80
 
85
81
  Each router file in the `/routers` directory is organized to handle related endpoints. The `app.ts` file automatically imports all routers and mounts them to the main Express application, making it simple to add new routes without modifying central files.
86
82
 
87
- Files that end with `.controller`, `.service`, `.spec`, `.dto`, `.middleware`, `.error`, or `.decorator`, as well as those that start with `_` or `@`, are excluded from the router list and can be utilized for various other purposes within the application.
83
+ Files that end with `.controller`, `.service`, `.spec`, `.dto`, `.middleware`, `.error`, `.class`, or `.decorator`, as well as those that start with `_` or `@`, are excluded from the router list and can be utilized for various other purposes within the application.
88
84
 
89
85
  Example of a basic router:
90
86
 
91
87
  ```typescript
92
88
  import { Router, Request, Response } from "express";
93
89
  import asyncHandler from "express-async-handler";
90
+ import UserController from "./user.controller";
91
+ import { sendError } from "@src/utilities";
94
92
 
95
93
  const router = Router();
94
+ const userController = new UserController();
95
+
96
+ /**
97
+ * @swagger
98
+ * /users:
99
+ * post:
100
+ * summary: Create a user
101
+ * description: Create a new user.
102
+ * consumes:
103
+ * - application/json
104
+ * produces:
105
+ * - application/json
106
+ * parameters:
107
+ * - in: body
108
+ * name: user
109
+ * required: true
110
+ * schema:
111
+ * type: object
112
+ * required:
113
+ * - username
114
+ * - email
115
+ * - password
116
+ * properties:
117
+ * username:
118
+ * type: string
119
+ * minLength: 3
120
+ * example: JessicaSmith
121
+ * email:
122
+ * type: string
123
+ * format: email
124
+ * example: user@example.com
125
+ * password:
126
+ * type: string
127
+ * minLength: 6
128
+ * example: securePassword123
129
+ * responses:
130
+ * 201:
131
+ * description: User created
132
+ */
133
+ router.post(
134
+ "/",
135
+ asyncHandler(async (req: Request, res: Response) => {
136
+ const user = await userController.create(req.body);
137
+ res.status(201).json(user);
138
+ })
139
+ );
140
+
141
+ /**
142
+ * @swagger
143
+ * /users/{id}:
144
+ * get:
145
+ * summary: Get a user by ID
146
+ * parameters:
147
+ * - name: id
148
+ * in: path
149
+ * required: true
150
+ * description: The ID of the product
151
+ * schema:
152
+ * type: integer
153
+ * responses:
154
+ * 200:
155
+ * description: A user object
156
+ * 404:
157
+ * description: user not found
158
+ */
159
+ router.get(
160
+ "/:id",
161
+ asyncHandler(async (req: Request, res: Response) => {
162
+ const user = await userController.get(req.params.id);
163
+
164
+ if ("id" in user == false) sendError(res, user);
165
+ else res.json(user);
166
+ })
167
+ );
96
168
 
97
169
  /**
98
170
  * @swagger
99
- * /:
171
+ * /users:
100
172
  * get:
101
- * summary: Get the home page
102
- * description: Returns the home page.
173
+ * summary: Get users
174
+ * description: Returns a list of user objects.
103
175
  * responses:
104
176
  * 200:
105
- * description: home page
177
+ * description: A list of user objects
106
178
  */
107
179
  router.get(
108
180
  "/",
109
181
  asyncHandler(async (req: Request, res: Response) => {
110
- res.send("Home");
182
+ res.json(await userController.getAll());
111
183
  })
112
184
  );
113
185
 
@@ -131,13 +203,25 @@ Here’s a brief breakdown of key components used in the `UserController`:
131
203
  ```typescript
132
204
  import { z } from "zod";
133
205
 
134
- export const createUserDto = z.object({
206
+ /**
207
+ * Zod schema for User entity
208
+ * @typedef {Object} ZodUser
209
+ * @property {number} id - Unique identifier (min 1)
210
+ * @property {string} username - Username (min 3 chars)
211
+ * @property {string} email - Valid email format
212
+ * @property {string} password - Password (min 6 chars)
213
+ */
214
+ export const ZodUser = z.object({
215
+ id: z.number().min(1).int(),
135
216
  username: z.string().min(3),
136
217
  email: z.string().email(),
137
218
  password: z.string().min(6),
138
219
  });
139
220
 
140
- export type CreateUser = z.infer<typeof createUserDto>;
221
+ export const ZodUserCreationDto = ZodUser.omit({ id: true });
222
+
223
+ export type User = z.infer<typeof ZodUser>;
224
+ export type UserCreationDto = z.infer<typeof ZodUserCreationDto>;
141
225
  ```
142
226
 
143
227
  - **Throttling and Rate Limiting**: The `@rateLimit` decorator is applied to safeguard the application's endpoints from abuse by limiting how frequently a particular method can be invoked.
@@ -149,37 +233,165 @@ By using a well-organized controller structure, this project makes it easier to
149
233
  Here is a quick reference to the UserController in practice:
150
234
 
151
235
  ```typescript
152
- import { Validate, ZodInput } from "ts-zod-decorators";
153
- import { createUserDto, CreateUser } from "./dto/user.dto";
154
- import { onError, rateLimit } from "utils-decorators";
236
+ import { User, ZodUserCreationDto, UserCreationDto } from "./dto/user.dto";
237
+ import { onError, rateLimit, timeout } from "utils-decorators";
238
+ import { Validate, ZodInput } from "@pkg/ts-zod-decorators";
239
+ import { ResponseError } from "@src/types";
240
+ import { tryParseId } from "@src/utilities";
241
+
242
+ // Array to store users (as a mock database)
243
+ const users = [
244
+ {
245
+ id: 1,
246
+ username: "johndoe",
247
+ email: "johndoe@gmail.com",
248
+ password: "S3cur3P@ssw0rd",
249
+ },
250
+ {
251
+ id: 2,
252
+ username: "janesmith",
253
+ email: "janesmith@yahoo.com",
254
+ password: "P@ssw0rd2024",
255
+ },
256
+ {
257
+ id: 3,
258
+ username: "michael89",
259
+ email: "michael89@hotmail.com",
260
+ password: "M1chael!2024",
261
+ },
262
+ {
263
+ id: 4,
264
+ username: "lisa.wong",
265
+ email: "lisa.wong@example.com",
266
+ password: "L1saW0ng!2024",
267
+ },
268
+ {
269
+ id: 5,
270
+ username: "alex_k",
271
+ email: "alex.k@gmail.com",
272
+ password: "A1ex#Key2024",
273
+ },
274
+ {
275
+ id: 6,
276
+ username: "emilyj",
277
+ email: "emilyj@hotmail.com",
278
+ password: "Em!ly0101",
279
+ },
280
+ {
281
+ id: 7,
282
+ username: "davidparker",
283
+ email: "david.parker@yahoo.com",
284
+ password: "D@v!d2024",
285
+ },
286
+ {
287
+ id: 8,
288
+ username: "sophia_m",
289
+ email: "sophia.m@gmail.com",
290
+ password: "Sophi@2024",
291
+ },
292
+ {
293
+ id: 9,
294
+ username: "chrisw",
295
+ email: "chrisw@outlook.com",
296
+ password: "Chri$Wong21",
297
+ },
298
+ {
299
+ id: 10,
300
+ username: "natalie_b",
301
+ email: "natalie_b@gmail.com",
302
+ password: "N@talie#B2024",
303
+ },
304
+ ];
155
305
 
156
306
  function exceedHandler() {
157
- throw new Error("Too much call in allowed window");
307
+ const message = "Too much call in allowed window";
308
+
309
+ throw new Error(message, {
310
+ cause: { status: 500, message } satisfies ResponseError,
311
+ });
158
312
  }
159
313
 
160
- function errorHandler(e: Error): void {
161
- console.error(e);
314
+ function getUserErrorHandler(e: Error) {
315
+ const message = "User not found.";
316
+
317
+ throw new Error(message, {
318
+ cause: { status: 404, message, details: e.message } satisfies ResponseError,
319
+ });
162
320
  }
163
321
 
322
+ /**
323
+ * Controller for handling user-related operations
324
+ * @class UserController
325
+ * @desc Provides methods for user management including CRUD operations
326
+ */
164
327
  export default class UserController {
165
- //constructor(private readonly userService: UserService) { }
328
+ // constructor(private readonly userService: UserService) { }
166
329
 
167
- // Throttle the createUser method to 1 request per 200 milliseconds
168
330
  @rateLimit({
169
331
  timeSpanMs: 60000,
170
332
  allowedCalls: 300,
171
333
  exceedHandler,
172
334
  })
335
+ @Validate
336
+ /**
337
+ * Create a new user
338
+ * @param {UserCreationDto} user - User creation data validated by Zod schema
339
+ * @returns {Promise<void>}
340
+ * @throws {ResponseError} 500 - When rate limit exceeded
341
+ * @throws {ResponseError} 400 - Invalid input data
342
+ */
343
+ public async create(@ZodInput(ZodUserCreationDto) user: UserCreationDto) {
344
+ users.push({ ...user, id: users.length + 1 } satisfies User);
345
+ }
346
+
173
347
  @onError({
174
- func: errorHandler,
348
+ func: getUserErrorHandler,
175
349
  })
176
- @Validate
177
- public async createUser(
178
- @ZodInput(CreateUserDto) data: CreateUser
179
- ): Promise<string> {
180
- // Here you can include logic to save user to database
181
- console.log("Creating user:", data);
182
- return "User created successfully";
350
+ @rateLimit({
351
+ timeSpanMs: 60000,
352
+ allowedCalls: 300,
353
+ exceedHandler,
354
+ })
355
+ /**
356
+ * Get user by ID
357
+ * @param {string} id - User ID as string
358
+ * @returns {Promise<User | ResponseError>} User details or error object
359
+ * @throws {ResponseError} 404 - User not found
360
+ * @throws {ResponseError} 400 - Invalid ID format
361
+ */
362
+ public async get(id: string): Promise<User | ResponseError> {
363
+ const userId = tryParseId(id);
364
+ if (typeof userId != "number") return userId satisfies ResponseError;
365
+ const user = users.find((user) => user.id === userId);
366
+
367
+ if (!user)
368
+ return {
369
+ status: 404,
370
+ message: "User dose not exist.",
371
+ } satisfies ResponseError;
372
+
373
+ return user satisfies User;
374
+ }
375
+
376
+ @timeout(20000)
377
+ @rateLimit({
378
+ timeSpanMs: 60000,
379
+ allowedCalls: 300,
380
+ exceedHandler,
381
+ })
382
+ /**
383
+ * Get all users with masked passwords
384
+ * @returns {Promise<User[]>} List of users with hidden password fields
385
+ * @throws {ResponseError} 500 - When rate limit exceeded
386
+ */
387
+ public async getAll(): Promise<User[]> {
388
+ return users.map(
389
+ (user) =>
390
+ ({
391
+ ...user,
392
+ password: "?",
393
+ } satisfies User)
394
+ );
183
395
  }
184
396
  }
185
397
  ```
package/command.js CHANGED
@@ -4,6 +4,7 @@ const fs = require("fs");
4
4
  const { exec } = require("child_process");
5
5
  const path = require("path");
6
6
  const { version } = require("os");
7
+ const { object } = require("zod");
7
8
 
8
9
  // Get the project name from command-line arguments or use a default name
9
10
  const projectName = process.argv[2] || "my-app";
@@ -29,16 +30,16 @@ exec(`git clone ${repoUrl} ${projectName}`, (error) => {
29
30
  }
30
31
 
31
32
  // Parse the package.json content and update the name
32
- const {
33
- bin,
34
- name = projectName,
35
- version = "1.0.0",
36
- description = " ",
37
- keywords = " ",
38
- author = " ",
39
- license = " ",
40
- ...packageJson
41
- } = JSON.parse(data);
33
+ const { bin, ...packageJson } = JSON.parse(data);
34
+
35
+ Object.assign(packageJson, {
36
+ name: projectName,
37
+ version: "1.0.0",
38
+ description: "",
39
+ keywords: "",
40
+ author: "",
41
+ license: "",
42
+ });
42
43
 
43
44
  // Write the updated package.json back to the file
44
45
  fs.writeFile(
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "codeweaver",
3
- "version": "1.0.14",
3
+ "version": "1.1.0",
4
4
  "main": "src/app.ts",
5
5
  "bin": {
6
6
  "create-codeweaver-app": "./command.js"
7
7
  },
8
8
  "scripts": {
9
- "start": "nodemon src/app.ts",
10
- "build": "tsc",
11
- "serve": "node dist/app.js"
9
+ "start": "nodemon -r tsconfig-paths/register src/app.ts",
10
+ "dev": "nodemon -r tsconfig-paths/register src/app.ts",
11
+ "build": "tsc && tsc-alias && copyfiles -u 1 \"src/**/*.{json,env,sqlite,db,sql,yaml,yml,xml,txt,md}\" dist",
12
+ "serve": "cross-env TSCONFIG_PATH=tsconfig.paths.json node -r tsconfig-paths/register dist/app.js"
12
13
  },
13
14
  "keywords": [
14
15
  "codeweaver",
@@ -27,23 +28,26 @@
27
28
  "swagger",
28
29
  "zod"
29
30
  ],
30
- "author": "Ehsan Afzali",
31
+ "author": "js-code-crafter",
31
32
  "license": "MIT",
32
33
  "description": "A lightweight framework built on top of Express and TypeScript",
33
34
  "dependencies": {
34
- "express": "^4.21.1",
35
+ "express": "^5.1.0",
35
36
  "express-async-handler": "^1.2.0",
36
- "ts-zod-decorators": "^1.7.1",
37
- "utils-decorators": "^2.0.9",
38
- "zod": "^3.23.8"
37
+ "utils-decorators": "^2.10.0",
38
+ "zod": "^4.0.14"
39
39
  },
40
40
  "devDependencies": {
41
- "@types/express": "^5.0.0",
42
- "@types/node": "^22.10.7",
43
- "nodemon": "^3.1.7",
41
+ "@types/express": "^5.0.3",
42
+ "@types/node": "^24.1.0",
43
+ "copyfiles": "^2.4.1",
44
+ "cross-env": "^10.0.0",
45
+ "nodemon": "^3.1.10",
44
46
  "swagger-jsdoc": "^6.2.8",
45
47
  "swagger-ui-express": "^5.0.1",
46
48
  "ts-node": "^10.9.2",
47
- "typescript": "^5.6.3"
49
+ "tsc-alias": "^1.8.16",
50
+ "tsconfig-paths": "^4.2.0",
51
+ "typescript": "^5.9.2"
48
52
  }
49
53
  }
package/src/app.ts CHANGED
@@ -1,9 +1,18 @@
1
- import express from "express";
1
+ import express, {
2
+ ErrorRequestHandler,
3
+ NextFunction,
4
+ Request,
5
+ Response,
6
+ } from "express";
2
7
  import fs from "fs";
3
8
  import path from "path";
4
9
  import config from "./config";
5
10
 
6
- // Function to load routers recursively
11
+ /**
12
+ * Recursively loads Express routers from directory
13
+ * @param {string} routerPath - Directory path to scan
14
+ * @param {string} [basePath=""] - Base route path
15
+ */
7
16
  function loadRouters(routerPath: string, basePath: string = "") {
8
17
  fs.readdirSync(routerPath).forEach((file) => {
9
18
  // Check if the filename should be excluded based on certain criteria
@@ -39,7 +48,11 @@ function loadRouters(routerPath: string, basePath: string = "") {
39
48
  // Exclude JavaScript test specification files
40
49
  file.endsWith(".spec.js") ||
41
50
  // Exclude TypeScript test specification files
42
- file.endsWith(".spec.ts")
51
+ file.endsWith(".spec.ts") ||
52
+ // Exclude JavaScript test specification files
53
+ file.endsWith(".class.js") ||
54
+ // Exclude TypeScript test specification files
55
+ file.endsWith(".class.ts")
43
56
  )
44
57
  // If any of the above conditions are true, exit the function early
45
58
  return;
@@ -85,6 +98,11 @@ if (config.devMode) {
85
98
  app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
86
99
  }
87
100
 
101
+ // General error handler
102
+ app.use((err: unknown, req: Request, res: Response, next: NextFunction) => {
103
+ res.status(500).json(err);
104
+ });
105
+
88
106
  // Start the server
89
107
  app.listen(config.port, () => {
90
108
  console.log(`Server is running on http://localhost:${config.port}`);
package/src/config.ts CHANGED
@@ -1,29 +1,62 @@
1
+ /**
2
+ * Server configuration interface
3
+ * @interface
4
+ * @property {string} url - Base server URL
5
+ */
1
6
  interface Server {
2
7
  url: string;
3
8
  }
4
9
 
10
+ /**
11
+ * API information structure
12
+ * @interface
13
+ * @property {string} title - API title
14
+ * @property {string} version - API version
15
+ * @property {string} description - API description
16
+ */
5
17
  interface Info {
6
18
  title: string;
7
19
  version: string;
8
20
  description: string;
9
21
  }
10
22
 
23
+ /**
24
+ * Swagger definition structure
25
+ * @interface
26
+ * @property {string} openApi - OpenAPI specification version
27
+ * @property {Info} info - API information
28
+ * @property {Server[]} servers - List of server configurations
29
+ */
11
30
  interface SwaggerDefinition {
12
31
  openApi: string;
13
32
  info: Info;
14
33
  servers: Server[];
15
34
  }
16
35
 
36
+ /**
37
+ * Swagger configuration options
38
+ * @interface
39
+ * @property {SwaggerDefinition} swaggerDefinition - Swagger definition object
40
+ * @property {string[]} apis - Paths to API documentation files
41
+ */
17
42
  interface SwaggerOptions {
18
43
  swaggerDefinition: SwaggerDefinition;
19
44
  apis: string[];
20
45
  }
21
46
 
47
+ /**
48
+ * Main application configuration
49
+ * @interface
50
+ * @property {boolean} devMode - Development mode flag
51
+ * @property {string} port - Server port
52
+ * @property {SwaggerOptions} swaggerOptions - Swagger configuration
53
+ */
22
54
  interface Config {
23
55
  devMode: boolean;
24
56
  port: string;
25
57
  swaggerOptions: SwaggerOptions;
26
58
  }
59
+
27
60
  const port = process.env.PORT || "3000";
28
61
  const config: Config = {
29
62
  devMode: process.env.NODE_ENV !== "production",
@@ -0,0 +1,3 @@
1
+ export * from './validate.decorator';
2
+ export * from './zod-output.decorator';
3
+ export * from './zod-input.decorator';
@@ -0,0 +1,20 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import ZodValidator from './validator.class';
3
+
4
+ export const Validate: MethodDecorator = (
5
+ target: Object,
6
+ propertyKey: string | symbol,
7
+ descriptor: PropertyDescriptor,
8
+ ) => {
9
+ const originalMethod = descriptor.value;
10
+ descriptor.value = async function (...args: unknown[]) {
11
+ ZodValidator.validateInput(target, propertyKey as string, args);
12
+ const result = originalMethod.apply(this, args);
13
+ let resultValue = result;
14
+ if (result instanceof Promise) {
15
+ resultValue = await result;
16
+ ZodValidator.validateOutput(target, propertyKey as string, resultValue);
17
+ }
18
+ return resultValue;
19
+ };
20
+ };
@@ -0,0 +1,72 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import * as z from "zod";
3
+
4
+ type Target = Object;
5
+ type MethodName = string;
6
+ type Metadata = {
7
+ paramsIndex: number[];
8
+ inputSchema?: z.ZodObject<any, any>;
9
+ outputSchema?: z.ZodObject<any, any>;
10
+ };
11
+
12
+ export default class ZodValidator {
13
+ private static methodValidatorMap: Map<Target, Map<MethodName, Metadata>> =
14
+ new Map();
15
+
16
+ static registerInputParameterValidationSchema(
17
+ target: Object,
18
+ methodName: MethodName,
19
+ paramIndex: number,
20
+ schema: z.ZodObject<any, any>
21
+ ) {
22
+ let paramMap = this.methodValidatorMap.get(target)!;
23
+ if (!paramMap) {
24
+ paramMap = new Map();
25
+ this.methodValidatorMap.set(target, paramMap);
26
+ }
27
+ let metadata = paramMap.get(methodName)!;
28
+ if (!metadata) {
29
+ metadata = { paramsIndex: [], inputSchema: schema };
30
+ paramMap.set(methodName, metadata);
31
+ }
32
+ metadata.paramsIndex.push(paramIndex);
33
+ }
34
+
35
+ static registerMethodValidationOutputSchema(
36
+ target: Object,
37
+ methodName: MethodName,
38
+ schema: z.ZodObject<any, any>
39
+ ) {
40
+ let paramMap = this.methodValidatorMap.get(target)!;
41
+ if (!paramMap) {
42
+ paramMap = new Map();
43
+ this.methodValidatorMap.set(target, paramMap);
44
+ }
45
+ let metadata = paramMap.get(methodName)!;
46
+ if (!metadata) {
47
+ metadata = { paramsIndex: [], outputSchema: schema };
48
+ paramMap.set(methodName, metadata);
49
+ }
50
+ metadata.outputSchema = schema;
51
+ }
52
+
53
+ static validateInput(
54
+ target: Object,
55
+ methodName: string,
56
+ paramValues: unknown[]
57
+ ) {
58
+ const methodMetadataMap = this.methodValidatorMap.get(target)!;
59
+ const metadata = methodMetadataMap.get(methodName)!;
60
+ for (const [index, input] of paramValues.entries()) {
61
+ if (metadata.paramsIndex.indexOf(index) != -1) {
62
+ metadata.inputSchema?.parse(input);
63
+ }
64
+ }
65
+ }
66
+
67
+ static validateOutput(target: Object, methodName: string, output: unknown) {
68
+ const methodMetadataMap = this.methodValidatorMap.get(target)!;
69
+ const metadata = methodMetadataMap.get(methodName)!;
70
+ metadata.outputSchema?.parse(output);
71
+ }
72
+ }
@@ -0,0 +1,12 @@
1
+ import { ZodObject } from "zod";
2
+ import ZodValidator from "./validator.class";
3
+
4
+ export const ZodInput =
5
+ <T extends ZodObject<any, any>>(schema: T): ParameterDecorator =>
6
+ (target, propertyKey, parameterIndex) =>
7
+ ZodValidator.registerInputParameterValidationSchema(
8
+ target,
9
+ propertyKey as string,
10
+ parameterIndex,
11
+ schema
12
+ );