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.
@@ -1,33 +1,161 @@
1
- import { Validate, ZodInput } from "ts-zod-decorators";
2
- import { CreateUserDto, CreateUser } from "./dto/user.dto";
3
- import { onError, rateLimit, throttle } from "utils-decorators";
1
+ import { User, ZodUserCreationDto, UserCreationDto } from "./dto/user.dto";
2
+ import { onError, rateLimit, timeout } from "utils-decorators";
3
+ import { Validate, ZodInput } from "@pkg/ts-zod-decorators";
4
+ import { ResponseError } from "@/types";
5
+ import { tryParseId } from "@/utilities";
6
+
7
+ // Array to store users (as a mock database)
8
+ const users = [
9
+ {
10
+ id: 1,
11
+ username: "johndoe",
12
+ email: "johndoe@gmail.com",
13
+ password: "S3cur3P@ssw0rd",
14
+ },
15
+ {
16
+ id: 2,
17
+ username: "janesmith",
18
+ email: "janesmith@yahoo.com",
19
+ password: "P@ssw0rd2024",
20
+ },
21
+ {
22
+ id: 3,
23
+ username: "michael89",
24
+ email: "michael89@hotmail.com",
25
+ password: "M1chael!2024",
26
+ },
27
+ {
28
+ id: 4,
29
+ username: "lisa.wong",
30
+ email: "lisa.wong@example.com",
31
+ password: "L1saW0ng!2024",
32
+ },
33
+ {
34
+ id: 5,
35
+ username: "alex_k",
36
+ email: "alex.k@gmail.com",
37
+ password: "A1ex#Key2024",
38
+ },
39
+ {
40
+ id: 6,
41
+ username: "emilyj",
42
+ email: "emilyj@hotmail.com",
43
+ password: "Em!ly0101",
44
+ },
45
+ {
46
+ id: 7,
47
+ username: "davidparker",
48
+ email: "david.parker@yahoo.com",
49
+ password: "D@v!d2024",
50
+ },
51
+ {
52
+ id: 8,
53
+ username: "sophia_m",
54
+ email: "sophia.m@gmail.com",
55
+ password: "Sophi@2024",
56
+ },
57
+ {
58
+ id: 9,
59
+ username: "chrisw",
60
+ email: "chrisw@outlook.com",
61
+ password: "Chri$Wong21",
62
+ },
63
+ {
64
+ id: 10,
65
+ username: "natalie_b",
66
+ email: "natalie_b@gmail.com",
67
+ password: "N@talie#B2024",
68
+ },
69
+ ];
4
70
 
5
71
  function exceedHandler() {
6
- throw new Error("Too much call in allowed window");
72
+ const message = "Too much call in allowed window";
73
+
74
+ throw new Error(message, {
75
+ cause: { status: 500, message } satisfies ResponseError,
76
+ });
7
77
  }
8
78
 
9
- function errorHandler(e: Error): void {
10
- console.error(e);
79
+ function getUserErrorHandler(e: Error) {
80
+ const message = "User not found.";
81
+
82
+ throw new Error(message, {
83
+ cause: { status: 404, message, details: e.message } satisfies ResponseError,
84
+ });
11
85
  }
12
86
 
87
+ /**
88
+ * Controller for handling user-related operations
89
+ * @class UserController
90
+ * @desc Provides methods for user management including CRUD operations
91
+ */
13
92
  export default class UserController {
14
- //constructor(private readonly userService: UserService) { }
93
+ // constructor(private readonly userService: UserService) { }
15
94
 
16
- // Throttle the createUser method to 1 request per 200 milliseconds
17
95
  @rateLimit({
18
96
  timeSpanMs: 60000,
19
97
  allowedCalls: 300,
20
98
  exceedHandler,
21
99
  })
100
+ @Validate
101
+ /**
102
+ * Create a new user
103
+ * @param {UserCreationDto} user - User creation data validated by Zod schema
104
+ * @returns {Promise<void>}
105
+ * @throws {ResponseError} 500 - When rate limit exceeded
106
+ * @throws {ResponseError} 400 - Invalid input data
107
+ */
108
+ public async create(@ZodInput(ZodUserCreationDto) user: UserCreationDto) {
109
+ users.push({ ...user, id: users.length + 1 } satisfies User);
110
+ }
111
+
22
112
  @onError({
23
- func: errorHandler,
113
+ func: getUserErrorHandler,
24
114
  })
25
- @Validate
26
- public async createUser(
27
- @ZodInput(CreateUserDto) data: CreateUser
28
- ): Promise<string> {
29
- // Here you can include logic to save user to database
30
- console.log("Creating user:", data);
31
- return "User created successfully";
115
+ @rateLimit({
116
+ timeSpanMs: 60000,
117
+ allowedCalls: 300,
118
+ exceedHandler,
119
+ })
120
+ /**
121
+ * Get user by ID
122
+ * @param {string} id - User ID as string
123
+ * @returns {Promise<User | ResponseError>} User details or error object
124
+ * @throws {ResponseError} 404 - User not found
125
+ * @throws {ResponseError} 400 - Invalid ID format
126
+ */
127
+ public async get(id: string): Promise<User | ResponseError> {
128
+ const userId = tryParseId(id);
129
+ if (typeof userId != "number") return userId satisfies ResponseError;
130
+ const user = users.find((user) => user.id === userId);
131
+
132
+ if (!user)
133
+ return {
134
+ status: 404,
135
+ message: "User dose not exist.",
136
+ } satisfies ResponseError;
137
+
138
+ return user satisfies User;
139
+ }
140
+
141
+ @timeout(20000)
142
+ @rateLimit({
143
+ timeSpanMs: 60000,
144
+ allowedCalls: 300,
145
+ exceedHandler,
146
+ })
147
+ /**
148
+ * Get all users with masked passwords
149
+ * @returns {Promise<User[]>} List of users with hidden password fields
150
+ * @throws {ResponseError} 500 - When rate limit exceeded
151
+ */
152
+ public async getAll(): Promise<User[]> {
153
+ return users.map(
154
+ (user) =>
155
+ ({
156
+ ...user,
157
+ password: "?",
158
+ } satisfies User)
159
+ );
32
160
  }
33
161
  }
package/src/types.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Represents a standardized error response structure for API endpoints
3
+ * @interface
4
+ * @property {number} status - HTTP status code
5
+ * @property {string} [name] - Error name/type
6
+ * @property {string} message - Human-readable error message
7
+ * @property {string} [stack] - Error stack trace (development only)
8
+ * @property {string} [details] - Additional error details
9
+ */
10
+ export interface ResponseError {
11
+ status: number;
12
+ name?: string;
13
+ message: string;
14
+ stack?: string;
15
+ details?: string;
16
+ }
@@ -0,0 +1,47 @@
1
+ import { Response } from "express";
2
+ import { ResponseError } from "./types";
3
+
4
+ /**
5
+ * Sends a standardized error response
6
+ * @param {Response} res - Express response object
7
+ * @param {ResponseError} error - Error details object
8
+ */
9
+ export function sendError(res: Response, error: ResponseError): void {
10
+ res.status(error.status).json(error);
11
+ }
12
+
13
+ /**
14
+ * Parses and validates ID parameter from string to number
15
+ * @param {string} input - Input string to parse
16
+ * @returns {number|ResponseError} Parsed number or error object
17
+ */
18
+ export function tryParseId(input: string): number | ResponseError {
19
+ try {
20
+ return parseInt(input) satisfies number;
21
+ } catch {
22
+ return {
23
+ status: 400,
24
+ message: "wrong input",
25
+ details: "The id parameter must be an integer number.",
26
+ } satisfies ResponseError;
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Checks if the provided object is a ResponseError.
32
+ *
33
+ * A ResponseError is an object that contains at least the properties:
34
+ * - message: string
35
+ * - status: number
36
+ *
37
+ * @param obj - The object to check.
38
+ * @returns true if the object is a ResponseError, false otherwise.
39
+ */
40
+ export function isResponseError(obj: unknown): boolean {
41
+ return (
42
+ obj != null &&
43
+ typeof obj === "object" &&
44
+ "message" in obj &&
45
+ "status" in obj
46
+ );
47
+ }
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ESNext",
3
+ "target": "ES2023",
4
4
  "module": "commonjs",
5
5
  "outDir": "./dist",
6
6
  "strict": true,
@@ -8,8 +8,14 @@
8
8
  "skipLibCheck": true,
9
9
  "forceConsistentCasingInFileNames": true,
10
10
  "experimentalDecorators": true,
11
- "emitDecoratorMetadata": true
11
+ "emitDecoratorMetadata": true,
12
+ "baseUrl": ".",
13
+ "paths": {
14
+ "@pkg/*": ["src/packages/*"],
15
+ "@r/*": ["src/routers/*"],
16
+ "@/*": ["src/*"]
17
+ }
12
18
  },
13
- "include": ["src/**/*.ts", "src/**/*.js", "command.js"],
19
+ "include": ["**/*.ts", "**/*.js"],
14
20
  "exclude": ["node_modules"]
15
21
  }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": {
5
+ "@pkg/*": ["dist/packages/*"],
6
+ "@r/*": ["dist/routers/*"],
7
+ "@/*": ["dist/*"]
8
+ }
9
+ }
10
+ }