codeweaver 1.0.15 → 2.0.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.
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Zod schema for Order entity
5
+ * @typedef {Object} ZodOrder
6
+ * @property {number} id - Unique identifier (min 1)
7
+ * @property {number} userId - Associated user ID (min 1)
8
+ * @property {{productId: number, quantity: number}[]} products - Array of ordered products
9
+ * @property {"Processing"|"Delivered"|"Canceled"} status - Order status
10
+ * @property {number} total - Total price (min 1000)
11
+ * @property {Date} createdAt - Creation timestamp
12
+ * @property {Date} [canceledAt] - Cancellation timestamp
13
+ * @property {Date} [deliveredAt] - Delivery timestamp
14
+ */
15
+ export const ZodOrder = z.object({
16
+ id: z.number().min(1).int(),
17
+ userId: z.number().min(1).int(),
18
+ products: z.array(
19
+ z.object({
20
+ productId: z.number().min(1).int(),
21
+ quantity: z.number().min(1).int(),
22
+ })
23
+ ),
24
+ status: z.enum(["Processing", "Delivered", "Canceled"]),
25
+ total: z.number().min(1000),
26
+ createdAt: z.date(),
27
+ canceledAt: z.date().optional(),
28
+ deliveredAt: z.date().optional(),
29
+ });
30
+
31
+ export const ZodOrderCreationDto = ZodOrder.omit({
32
+ id: true,
33
+ status: true,
34
+ createdAt: true,
35
+ canceledAt: true,
36
+ deliveredAt: true,
37
+ });
38
+
39
+ export type Order = z.infer<typeof ZodOrder>;
40
+ export type OrderCreationDto = z.infer<typeof ZodOrderCreationDto>;
41
+ export type OrderDto = z.infer<typeof ZodOrder>;
@@ -0,0 +1,157 @@
1
+ import { Router, Request, Response } from "express";
2
+ import asyncHandler from "express-async-handler";
3
+ import OrderController from "./order.controller";
4
+
5
+ const router = Router();
6
+ const orderController = new OrderController();
7
+
8
+ /**
9
+ * @swagger
10
+ * /orders:
11
+ * post:
12
+ * summary: Create a new order
13
+ * description: Creates an order with user details and products.
14
+ * consumes:
15
+ * - application/json
16
+ * produces:
17
+ * - application/json
18
+ * parameters:
19
+ * - in: body
20
+ * name: order
21
+ * required: true
22
+ * schema:
23
+ * type: object
24
+ * required:
25
+ * - userId
26
+ * - products
27
+ * - total
28
+ * properties:
29
+ * userId:
30
+ * type: integer
31
+ * minimum: 1
32
+ * example: 1
33
+ * products:
34
+ * type: array
35
+ * description: Array of products in the order
36
+ * items:
37
+ * type: object
38
+ * required:
39
+ * - productId
40
+ * - quantity
41
+ * properties:
42
+ * productId:
43
+ * type: integer
44
+ * minimum: 1
45
+ * example: 3
46
+ * quantity:
47
+ * type: integer
48
+ * minimum: 1
49
+ * example: 2
50
+ * total:
51
+ * type: number
52
+ * minimum: 1000
53
+ * example: 250000
54
+ * responses:
55
+ * 201:
56
+ * description: Order created
57
+ */
58
+ router.post(
59
+ "/",
60
+ asyncHandler(async (req: Request, res: Response) => {
61
+ const order = await orderController.create(req.body);
62
+ res.status(201).json(order);
63
+ })
64
+ );
65
+
66
+ /**
67
+ * @swagger
68
+ * /orders:
69
+ * get:
70
+ * summary: Get all orders
71
+ * responses:
72
+ * 200:
73
+ * description: List of orders
74
+ */
75
+ router.get(
76
+ "/",
77
+ asyncHandler(async (req: Request, res: Response) => {
78
+ const orders = await orderController.getAll();
79
+ res.json(orders);
80
+ })
81
+ );
82
+
83
+ /**
84
+ * @swagger
85
+ * /orders/{id}:
86
+ * get:
87
+ * summary: Get order details
88
+ * parameters:
89
+ * - name: id
90
+ * in: path
91
+ * required: true
92
+ * description: Numeric ID of the order to retrieve
93
+ * type: integer
94
+ * example: 101
95
+ * responses:
96
+ * 200:
97
+ * description: Order details
98
+ */
99
+ router.get(
100
+ "/:id",
101
+ asyncHandler(async (req: Request, res: Response) => {
102
+ const order = await orderController.get(req.params.id);
103
+ res.json(order);
104
+ })
105
+ );
106
+
107
+ /**
108
+ * @swagger
109
+ * /orders/{id}/cancel:
110
+ * patch:
111
+ * summary: Cancel order
112
+ * parameters:
113
+ * - name: id
114
+ * in: path
115
+ * required: true
116
+ * description: Numeric ID of the order to cancel
117
+ * type: integer
118
+ * example: 101
119
+ * responses:
120
+ * 200:
121
+ * description: Order canceled successfully
122
+ */
123
+ router.patch(
124
+ "/:id/cancel",
125
+ asyncHandler(async (req: Request, res: Response) => {
126
+ const order = await orderController.cancel(req.params.id);
127
+ res.json(order);
128
+ })
129
+ );
130
+
131
+ /**
132
+ * @swagger
133
+ * /orders/{id}/deliver:
134
+ * patch:
135
+ * summary: Mark order as delivered
136
+ * parameters:
137
+ * - name: id
138
+ * in: path
139
+ * required: true
140
+ * description: Numeric ID of the order to deliver
141
+ * type: integer
142
+ * example: 101
143
+ * responses:
144
+ * 200:
145
+ * description: Order marked as delivered
146
+ * 400:
147
+ * description: Delivery is only available when the order is in processing status.
148
+ */
149
+ router.patch(
150
+ "/:id/deliver",
151
+ asyncHandler(async (req: Request, res: Response) => {
152
+ const order = await orderController.deliver(req.params.id);
153
+ res.json(order);
154
+ })
155
+ );
156
+
157
+ export = router;
@@ -0,0 +1,178 @@
1
+ import { memoizeAsync, onError, rateLimit, timeout } from "utils-decorators";
2
+ import {
3
+ Order,
4
+ OrderDto,
5
+ OrderCreationDto,
6
+ ZodOrderCreationDto,
7
+ } from "./dto/order.dto";
8
+ import { Validate, ZodInput } from "ts-zod4-decorators";
9
+ import { ResponseError } from "@/utilities/types";
10
+ import { parseId } from "@/utilities/error-handling";
11
+ import config from "@/config";
12
+
13
+ // Array to store orders (as a mock database)
14
+ const orders: Order[] = [
15
+ {
16
+ id: 1,
17
+ userId: 1,
18
+ products: [
19
+ { productId: 2, quantity: 1 },
20
+ { productId: 6, quantity: 2 },
21
+ ],
22
+ status: "Delivered",
23
+ total: 14400,
24
+ createdAt: new Date("2024-01-15"),
25
+ deliveredAt: new Date("2024-02-10"),
26
+ },
27
+ {
28
+ id: 2,
29
+ userId: 3,
30
+ products: [
31
+ { productId: 9, quantity: 1 },
32
+ { productId: 7, quantity: 1 },
33
+ ],
34
+ status: "Processing",
35
+ total: 36500,
36
+ createdAt: new Date("2024-03-20"),
37
+ },
38
+ {
39
+ id: 3,
40
+ userId: 2,
41
+ products: [
42
+ { productId: 1, quantity: 1 },
43
+ { productId: 4, quantity: 2 },
44
+ ],
45
+ status: "Canceled",
46
+ total: 81000,
47
+ createdAt: new Date("2024-05-01"),
48
+ canceledAt: new Date("2024-05-03"),
49
+ },
50
+ ];
51
+
52
+ function exceedHandler() {
53
+ const message = "Too much call in allowed window";
54
+ throw new ResponseError(message, 429);
55
+ }
56
+
57
+ function getOrderErrorHandler(e: Error) {
58
+ const message = "Order not found.";
59
+ throw new ResponseError(message, 404, e.message);
60
+ }
61
+
62
+ /**
63
+ * Controller for handling order-related operations
64
+ * @class OrderController
65
+ * @desc Provides methods for order management including creation, status updates and retrieval
66
+ */
67
+ export default class OrderController {
68
+ @rateLimit({
69
+ timeSpanMs: config.rateLimitTimeSpan,
70
+ allowedCalls: config.rateLimitAllowedCalls,
71
+ exceedHandler,
72
+ })
73
+ @Validate
74
+ /**
75
+ * Create a new order
76
+ * @param {OrderCreationDto} order - Order creation data
77
+ * @returns {Promise<Order>} Newly created order
78
+ */
79
+ public async create(@ZodInput(ZodOrderCreationDto) order: OrderCreationDto) {
80
+ const newOrder = {
81
+ ...order,
82
+ id: orders.length + 1,
83
+ createdAt: new Date(),
84
+ status: "Processing",
85
+ } satisfies Order;
86
+
87
+ orders.push(newOrder);
88
+ return newOrder;
89
+ }
90
+
91
+ @memoizeAsync(config.memoizeTime)
92
+ @timeout(config.timeout)
93
+ @rateLimit({
94
+ timeSpanMs: config.rateLimitTimeSpan,
95
+ allowedCalls: config.rateLimitAllowedCalls,
96
+ exceedHandler,
97
+ })
98
+ /**
99
+ * Retrieves all orders
100
+ * @returns List of orders
101
+ */
102
+ public async getAll(): Promise<OrderDto[]> {
103
+ return orders;
104
+ }
105
+
106
+ @memoizeAsync(config.memoizeTime)
107
+ @rateLimit({
108
+ timeSpanMs: config.rateLimitTimeSpan,
109
+ allowedCalls: config.rateLimitAllowedCalls,
110
+ exceedHandler,
111
+ })
112
+ @onError({
113
+ func: getOrderErrorHandler,
114
+ })
115
+ /**
116
+ * Finds an order by its ID
117
+ * @param id - Order ID as string
118
+ * @returns Order details or error object if not found
119
+ */
120
+ public async get(id: string): Promise<OrderDto> {
121
+ const orderId = parseId(id);
122
+ const order = orders.find((order) => order.id === orderId);
123
+ if (order == null) throw new ResponseError("User dose not exist.", 404);
124
+ return order satisfies Order;
125
+ }
126
+
127
+ @rateLimit({
128
+ timeSpanMs: config.rateLimitTimeSpan,
129
+ allowedCalls: config.rateLimitAllowedCalls,
130
+ exceedHandler,
131
+ })
132
+ /**
133
+ * Cancel an existing order
134
+ * @param {string} id - Order ID to cancel
135
+ * @returns {Promise<Order>} Updated order or error object
136
+ * @throws {ResponseError} 404 - Order not found
137
+ * @throws {ResponseError} 400 - Invalid ID format or invalid status for cancellation
138
+ */
139
+ public async cancel(id: string): Promise<OrderDto> {
140
+ let order = await this.get(id);
141
+ if (order.status != "Processing") {
142
+ throw new ResponseError(
143
+ "Cancellation is not available unless the order is in processing status.",
144
+ 400
145
+ );
146
+ }
147
+
148
+ order.status = "Canceled";
149
+ order.deliveredAt = new Date();
150
+ return order satisfies Order;
151
+ }
152
+
153
+ @rateLimit({
154
+ timeSpanMs: config.rateLimitTimeSpan,
155
+ allowedCalls: config.rateLimitAllowedCalls,
156
+ exceedHandler,
157
+ })
158
+ /**
159
+ * Mark an order as delivered
160
+ * @param {string} id - Order ID to mark as delivered
161
+ * @returns {Promise<Order>} Updated order or error object
162
+ * @throws {ResponseError} 404 - Order not found
163
+ * @throws {ResponseError} 400 - Invalid ID format or invalid status for delivery
164
+ */
165
+ public async deliver(id: string): Promise<OrderDto> {
166
+ let order = await this.get(id);
167
+ if (order.status != "Processing") {
168
+ throw new ResponseError(
169
+ "Delivery is only available when the order is in processing status.",
170
+ 400
171
+ );
172
+ }
173
+
174
+ order.status = "Delivered";
175
+ order.deliveredAt = new Date();
176
+ return order satisfies Order;
177
+ }
178
+ }
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Zod schema for Product entity
5
+ * @typedef {Object} ZodProduct
6
+ * @property {number} id - Unique identifier (min 1)
7
+ * @property {string} name - Product name (min 2 chars)
8
+ * @property {number} price - Product price (min 1000)
9
+ * @property {string} [description] - Optional description (min 10 chars)
10
+ * @property {string} category - Product category from predefined enum
11
+ * @property {number} stock - Available stock quantity (min 0)
12
+ */
13
+ export const ZodProduct = z.object({
14
+ id: z.number().min(1).int(),
15
+ name: z.string().min(2),
16
+ price: z.number().min(1000),
17
+ description: z.string().min(10).optional(),
18
+ category: z.enum([
19
+ "Electronics",
20
+ "Appliances",
21
+ "Sports",
22
+ "Kitchen",
23
+ "Mobile Accessories",
24
+ "Computer Accessories",
25
+ "Home Appliances",
26
+ "Books",
27
+ ]),
28
+ stock: z.number().min(0).int(),
29
+ });
30
+
31
+ export const ZodProductCreationDto = ZodProduct.omit({ id: true });
32
+ export const ZodProductUpdateDto = ZodProductCreationDto.partial();
33
+
34
+ export type Product = z.infer<typeof ZodProduct>;
35
+ export type ProductCreationDto = z.infer<typeof ZodProductCreationDto>;
36
+ export type ProductUpdateDto = z.infer<typeof ZodProductUpdateDto>;
37
+ export type ProductDto = z.infer<typeof ZodProduct>;
@@ -0,0 +1,200 @@
1
+ import { Router, Request, Response } from "express";
2
+ import asyncHandler from "express-async-handler";
3
+ import ProductController from "./product.controller";
4
+
5
+ const router = Router();
6
+ const productController = new ProductController();
7
+
8
+ // CRUD Routes
9
+
10
+ /**
11
+ * @swagger
12
+ * /products:
13
+ * post:
14
+ * summary: Create a product
15
+ * description: Create a new product.
16
+ * consumes:
17
+ * - application/json
18
+ * produces:
19
+ * - application/json
20
+ * parameters:
21
+ * - in: body
22
+ * name: product
23
+ * required: true
24
+ * schema:
25
+ * type: object
26
+ * required:
27
+ * - name
28
+ * - price
29
+ * - category
30
+ * - stock
31
+ * properties:
32
+ * id:
33
+ * type: integer
34
+ * example: 1
35
+ * name:
36
+ * type: string
37
+ * example: "New Product"
38
+ * price:
39
+ * type: number
40
+ * example: 1499
41
+ * description:
42
+ * type: string
43
+ * example: "This is a detailed description."
44
+ * category:
45
+ * type: string
46
+ * enum:
47
+ * - Electronics
48
+ * - Appliances
49
+ * - Sports
50
+ * - Kitchen
51
+ * - Mobile Accessories
52
+ * - Computer Accessories
53
+ * - Home Appliances
54
+ * - Books
55
+ * example: "Electronics"
56
+ * stock:
57
+ * type: integer
58
+ * example: 50
59
+ * responses:
60
+ * 201:
61
+ * description: Product created
62
+ */
63
+ router.post(
64
+ "/",
65
+ asyncHandler(async (req: Request, res: Response) => {
66
+ const product = await productController.create(req.body);
67
+ res.status(201).json(product);
68
+ })
69
+ );
70
+
71
+ /**
72
+ * @swagger
73
+ * /products:
74
+ * get:
75
+ * summary: Get all products
76
+ * responses:
77
+ * 200:
78
+ * description: A list of products
79
+ */
80
+ router.get(
81
+ "/",
82
+ asyncHandler(async (req: Request, res: Response) => {
83
+ res.json(await productController.getAll());
84
+ })
85
+ );
86
+
87
+ /**
88
+ * @swagger
89
+ * /products/{id}:
90
+ * get:
91
+ * summary: Get a product by ID
92
+ * parameters:
93
+ * - name: id
94
+ * in: path
95
+ * required: true
96
+ * description: The ID of the product
97
+ * schema:
98
+ * type: integer
99
+ * responses:
100
+ * 200:
101
+ * description: A product object
102
+ */
103
+ router.get(
104
+ "/:id",
105
+ asyncHandler(async (req: Request, res: Response) => {
106
+ const product = await productController.get(req.params.id);
107
+ res.json(product);
108
+ })
109
+ );
110
+
111
+ /**
112
+ * @swagger
113
+ * /products/{id}:
114
+ * put:
115
+ * summary: Update a product
116
+ * description: Update an existing product.
117
+ * consumes:
118
+ * - application/json
119
+ * produces:
120
+ * - application/json
121
+ * parameters:
122
+ * - name: id
123
+ * in: path
124
+ * required: true
125
+ * description: The ID of the product to update
126
+ * schema:
127
+ * type: integer
128
+ * - in: body
129
+ * name: product
130
+ * required: true
131
+ * schema:
132
+ * type: object
133
+ * properties:
134
+ * name:
135
+ * type: string
136
+ * example: "Updated Product"
137
+ * price:
138
+ * type: number
139
+ * example: 2000
140
+ * description:
141
+ * type: string
142
+ * example: "This is a detailed description."
143
+ * category:
144
+ * type: string
145
+ * enum:
146
+ * - Electronics
147
+ * - Appliances
148
+ * - Sports
149
+ * - Kitchen
150
+ * - Mobile Accessories
151
+ * - Computer Accessories
152
+ * - Home Appliances
153
+ * - Books
154
+ * example: "Sports"
155
+ * stock:
156
+ * type: integer
157
+ * example: 70
158
+ * responses:
159
+ * 200:
160
+ * description: Product updated
161
+ * 404:
162
+ * description: Product not found
163
+ */
164
+ router.put(
165
+ "/:id",
166
+ asyncHandler(async (req: Request, res: Response) => {
167
+ const product = await productController.update(req.params.id, req.body);
168
+ res.json(product);
169
+ })
170
+ );
171
+
172
+ /**
173
+ * @swagger
174
+ * /products/{id}:
175
+ * delete:
176
+ * summary: Delete a product
177
+ * parameters:
178
+ * - name: id
179
+ * in: path
180
+ * required: true
181
+ * description: The ID of the product to delete
182
+ * schema:
183
+ * type: integer
184
+ * responses:
185
+ * 204:
186
+ * description: product deleted
187
+ * 400:
188
+ * description: invalid request
189
+ * 404:
190
+ * description: product not found
191
+ */
192
+ router.delete(
193
+ "/:id",
194
+ asyncHandler(async (req: Request, res: Response) => {
195
+ const product = await productController.delete(req.params.id);
196
+ res.json(product);
197
+ })
198
+ );
199
+
200
+ export = router;