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 +252 -40
- package/command.js +11 -10
- package/package.json +17 -13
- package/src/app.ts +21 -3
- package/src/config.ts +33 -0
- package/src/packages/ts-zod-decorators/index.ts +3 -0
- package/src/packages/ts-zod-decorators/validate.decorator.ts +20 -0
- package/src/packages/ts-zod-decorators/validator.class.ts +72 -0
- package/src/packages/ts-zod-decorators/zod-input.decorator.ts +12 -0
- package/src/packages/ts-zod-decorators/zod-output.decorator.ts +11 -0
- package/src/routers/index.ts +2 -2
- package/src/routers/orders/dto/order.dto.ts +40 -0
- package/src/routers/orders/index.ts +131 -10
- package/src/routers/orders/order.controller.ts +191 -0
- package/src/routers/products/dto/product.dto.ts +36 -0
- package/src/routers/products/index.ts +104 -64
- package/src/routers/products/product.controller.ts +237 -0
- package/src/routers/users/dto/user.dto.ts +14 -2
- package/src/routers/users/index.ts +54 -36
- package/src/routers/users/user.controller.ts +144 -16
- package/src/types.ts +16 -0
- package/src/utilities.ts +47 -0
- package/tsconfig.json +9 -3
- package/tsconfig.paths.json +10 -0
|
@@ -1,33 +1,161 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
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
|
|
10
|
-
|
|
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:
|
|
113
|
+
func: getUserErrorHandler,
|
|
24
114
|
})
|
|
25
|
-
@
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
+
}
|
package/src/utilities.ts
ADDED
|
@@ -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": "
|
|
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": ["
|
|
19
|
+
"include": ["**/*.ts", "**/*.js"],
|
|
14
20
|
"exclude": ["node_modules"]
|
|
15
21
|
}
|