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,120 @@
1
+ import { Response } from "express";
2
+ import { ReturnInfo, ResponseError } from "./types";
3
+
4
+ /**
5
+ * Sends a standardized HTTP error response.
6
+ *
7
+ * This function sets the response status from the provided error (defaulting to 500)
8
+ * and serializes the error object as JSON.
9
+ *
10
+ * @param res - Express Response object to send the error on
11
+ * @param error - Error details to return to the client (must include status or default will be 500)
12
+ */
13
+ export function sendHttpError(res: Response, error: ResponseError): void {
14
+ res.status(error.status ?? 500).json(error);
15
+ }
16
+
17
+ /**
18
+ * Executes a function and captures a potential error as a ReturnInfo tuple.
19
+ *
20
+ * Returns a two-element tuple: [value, error]
21
+ * - value: the function result if it succeeds; null if an exception is thrown
22
+ * - error: the caught Error wrapped as a ResponseError (or the provided error) if the function throws; null if the function succeeds
23
+ *
24
+ * This utility helps avoid try/catch blocks at call sites by returning both the
25
+ * result and any error in a single value.
26
+ *
27
+ * @template T
28
+ * @param func - The function to execute
29
+ * @param error - The error object to return when an exception occurs (typically a ResponseError). If no error is provided, null is used.
30
+ * @returns ReturnInfo<T> A tuple: [value or null, error or null]
31
+ */
32
+ export function tryCatch<T>(
33
+ func: () => T,
34
+ error: ResponseError | null
35
+ ): ReturnInfo<T> {
36
+ try {
37
+ return [func(), null];
38
+ } catch {
39
+ return [null, error];
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Parses a string input into a number (ID) with basic validation.
45
+ *
46
+ * If parsing fails, this function throws a ResponseError describing the invalid input.
47
+ *
48
+ * @param input - The string to parse as an integer ID
49
+ * @returns The parsed number
50
+ * @throws {ResponseError} When the input cannot be parsed as an integer
51
+ */
52
+ export function parseId(input: string): number {
53
+ try {
54
+ // parseInt may yield NaN for non-numeric input; this example mirrors the original behavior
55
+ // If you want stricter validation, you can check isNaN and throw a more explicit error.
56
+ return parseInt(input);
57
+ } catch {
58
+ throw new ResponseError(
59
+ input,
60
+ 400,
61
+ "Wrong input",
62
+ "The id parameter must be an integer number."
63
+ );
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Creates a successful result from a ReturnInfo tuple.
69
+ *
70
+ * Given a ReturnInfo<T> of the form [value, error], this returns the value
71
+ * when the operation succeeded, or null when there was an error.
72
+ *
73
+ * @template T
74
+ * @param input - The ReturnInfo tuple
75
+ * @returns The successful value of type T, or null if there was an error
76
+ */
77
+ export function successfulResult<T>(input: ReturnInfo<T>): T | null {
78
+ return input[0];
79
+ }
80
+
81
+ /**
82
+ * Normalizes and wraps an error into the common ReturnInfo shape.
83
+ *
84
+ * The function accepts a ReturnInfo-shaped input and extracts the error portion.
85
+ * If a non-Error value is provided, you should wrap it as a ResponseError beforehand.
86
+ * If the error is already a ResponseError, it is returned as-is.
87
+ *
88
+ * @template T
89
+ * @param responseError - The error to wrap, either as a ResponseError or as a ReturnInfo<T> where the error is at index 1
90
+ * @returns The extracted or wrapped ResponseError, or null if there is no error
91
+ */
92
+ export function error<T>(responseError: ReturnInfo<T>): ResponseError | null {
93
+ return responseError[1];
94
+ }
95
+
96
+ /**
97
+ * Determines whether a ReturnInfo value represents a successful operation.
98
+ *
99
+ * A result is considered successful when there is no error (i.e., the error portion is null).
100
+ *
101
+ * @template T
102
+ * @param result - The ReturnInfo tuple [value | null, error | null]
103
+ * @returns true if there is no error; false otherwise
104
+ */
105
+ export function isSuccessful<T>(result: ReturnInfo<T>): boolean {
106
+ return result[1] === null;
107
+ }
108
+
109
+ /**
110
+ * Indicates whether a ReturnInfo value represents an error.
111
+ *
112
+ * This is the logical negation of isSuccess for a given ReturnInfo.
113
+ *
114
+ * @template T
115
+ * @param result - The ReturnInfo tuple [value | null, error | null]
116
+ * @returns true if an error is present (i.e., error is not null); false otherwise
117
+ */
118
+ export function hasError<T>(result: ReturnInfo<T>): boolean {
119
+ return result[1] !== null;
120
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Represents a standardized error response structure for API endpoints
3
+ * @class
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 class ResponseError extends Error {
11
+ public constructor(
12
+ public message: string,
13
+ public status?: number,
14
+ public details?: string,
15
+ public code?: string,
16
+ public stack?: string
17
+ ) {
18
+ super(message);
19
+ }
20
+ }
21
+
22
+ export type ReturnInfo<T> = [T | null, ResponseError | null];
23
+ export type AsyncReturnInfo<T> = Promise<[T | null, ResponseError | null]>;
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,11 @@
8
8
  "skipLibCheck": true,
9
9
  "forceConsistentCasingInFileNames": true,
10
10
  "experimentalDecorators": true,
11
- "emitDecoratorMetadata": true
11
+ "emitDecoratorMetadata": true,
12
+ "paths": {
13
+ "@/*": ["./src/*"]
14
+ }
12
15
  },
13
- "include": ["src/**/*.ts", "src/**/*.js", "command.js"],
16
+ "include": ["**/*.ts", "**/*.js"],
14
17
  "exclude": ["node_modules"]
15
18
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": {
5
+ "@/*": ["dist/*"]
6
+ }
7
+ }
8
+ }
package/src/app.ts DELETED
@@ -1,95 +0,0 @@
1
- import express from "express";
2
- import fs from "fs";
3
- import path from "path";
4
- import config from "./config";
5
-
6
- // Function to load routers recursively
7
- function loadRouters(routerPath: string, basePath: string = "") {
8
- fs.readdirSync(routerPath).forEach((file) => {
9
- // Check if the filename should be excluded based on certain criteria
10
- if (
11
- // Exclude files that start with an underscore (_)
12
- file.startsWith("_") ||
13
- // Exclude files that start with an at symbol (@)
14
- file.startsWith("@") ||
15
- // Exclude JavaScript controller files
16
- file.endsWith(".controller.js") ||
17
- // Exclude TypeScript controller files
18
- file.endsWith(".controller.ts") ||
19
- // Exclude JavaScript service files
20
- file.endsWith(".service.js") ||
21
- // Exclude TypeScript service files
22
- file.endsWith(".service.ts") ||
23
- // Exclude JavaScript middleware files
24
- file.endsWith(".middleware.js") ||
25
- // Exclude TypeScript middleware files
26
- file.endsWith(".middleware.ts") ||
27
- // Exclude JavaScript error middleware files
28
- file.endsWith(".error.js") ||
29
- // Exclude TypeScript error middleware files
30
- file.endsWith(".error.ts") ||
31
- // Exclude JavaScript service files
32
- file.endsWith(".decorator.js") ||
33
- // Exclude TypeScript service files
34
- file.endsWith(".decorator.ts") ||
35
- // Exclude JavaScript DTO files
36
- file.endsWith(".dto.js") ||
37
- // Exclude TypeScript DTO files
38
- file.endsWith(".dto.ts") ||
39
- // Exclude JavaScript test specification files
40
- file.endsWith(".spec.js") ||
41
- // Exclude TypeScript test specification files
42
- file.endsWith(".spec.ts")
43
- )
44
- // If any of the above conditions are true, exit the function early
45
- return;
46
-
47
- const fullPath = path.join(routerPath, file);
48
-
49
- // Construct a route path by combining the base path with the filename
50
- const routePath = path
51
- // Join the base path and the filename, removing the file extension (.js or .ts)
52
- .join(basePath, file.replace(/(\.js|\.ts)/g, ""))
53
- // Replace all backslashes with forward slashes for consistent file path formatting
54
- .replaceAll("\\", "/")
55
- // Remove the trailing '/index' if it exists, to clean up the route
56
- .replace(/\/?index$/g, "");
57
-
58
- if (fs.lstatSync(fullPath).isDirectory()) {
59
- // If the file is a directory, call the function again
60
- loadRouters(fullPath, routePath);
61
- } else if (file.endsWith(".ts") || file.endsWith(".js")) {
62
- // Import the router module and mount it to the app
63
- const router = require(fullPath);
64
- app.use("/" + routePath, router);
65
- console.log(`Mounted ${file} at ${"/" + routePath}`);
66
- }
67
- });
68
- }
69
-
70
- const app = express();
71
- app.use(express.json());
72
- app.use(express.urlencoded({ extended: true }));
73
-
74
- //app.use(cors());
75
-
76
- // Automatically import all routers from the /src/routers directory
77
- const routersPath = path.join(__dirname, "/routers");
78
- loadRouters(routersPath);
79
-
80
- // Swagger setup
81
- if (config.devMode) {
82
- const swaggerJsDoc = require("swagger-jsdoc");
83
- const swaggerUi = require("swagger-ui-express");
84
- const swaggerDocs = swaggerJsDoc(config.swaggerOptions);
85
- app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
86
- }
87
-
88
- // Start the server
89
- app.listen(config.port, () => {
90
- console.log(`Server is running on http://localhost:${config.port}`);
91
- if (config.devMode)
92
- console.log(
93
- `Swagger UI is available at http://localhost:${config.port}/api-docs`
94
- );
95
- });
@@ -1,40 +0,0 @@
1
- import { Router, Request, Response } from "express";
2
- import asyncHandler from "express-async-handler";
3
-
4
- const router = Router();
5
-
6
- /**
7
- * @swagger
8
- * /orders:
9
- * get:
10
- * summary: Get order home
11
- * description: Returns the order home page.
12
- * responses:
13
- * 200:
14
- * description: Order home page
15
- */
16
- router.get(
17
- "/",
18
- asyncHandler(async (req: Request, res: Response) => {
19
- res.send("Order Home");
20
- })
21
- );
22
-
23
- /**
24
- * @swagger
25
- * /orders/history:
26
- * get:
27
- * summary: Get order history
28
- * description: Returns order history.
29
- * responses:
30
- * 200:
31
- * description: Order history
32
- */
33
- router.get(
34
- "/history",
35
- asyncHandler(async (req: Request, res: Response) => {
36
- res.send("Order History");
37
- })
38
- );
39
-
40
- export = router;
@@ -1,167 +0,0 @@
1
- import { Router, Request, Response } from "express";
2
- import asyncHandler from "express-async-handler";
3
-
4
- const router = Router();
5
-
6
- // Array to store products (as a mock database)
7
- const products = [
8
- { id: 1, name: "Product1" },
9
- { id: 2, name: "Product2" },
10
- { id: 3, name: "Product3" },
11
- { id: 4, name: "Product4" },
12
- { id: 5, name: "Product5" },
13
- { id: 6, name: "Product6" },
14
- { id: 7, name: "Product7" },
15
- { id: 8, name: "Product8" },
16
- { id: 9, name: "Product9" },
17
- ];
18
-
19
- // CRUD Routes
20
-
21
- /**
22
- * @swagger
23
- * /products:
24
- * post:
25
- * summary: Create an product
26
- * description: Create a new product.
27
- * requestBody:
28
- * required: true
29
- * content:
30
- * application/json:
31
- * schema:
32
- * type: object
33
- * properties:
34
- * name:
35
- * type: string
36
- * description:
37
- * type: string
38
- * responses:
39
- * 201:
40
- * description: product created
41
- */
42
- router.post(
43
- "/",
44
- asyncHandler(async (req: Request, res: Response) => {
45
- const product = { id: products.length + 1, name: req.body.name };
46
- products.push(product);
47
- res.status(201).json(product);
48
- })
49
- );
50
-
51
- /**
52
- * @swagger
53
- * /products:
54
- * get:
55
- * summary: Get all products
56
- * responses:
57
- * 200:
58
- * description: A list of products
59
- */
60
- router.get(
61
- "/",
62
- asyncHandler(async (req: Request, res: Response) => {
63
- res.json(products);
64
- })
65
- );
66
-
67
- /**
68
- * @swagger
69
- * /products/{id}:
70
- * get:
71
- * summary: Get an product by ID
72
- * parameters:
73
- * - name: id
74
- * in: path
75
- * required: true
76
- * description: The ID of the product
77
- * schema:
78
- * type: integer
79
- * responses:
80
- * 200:
81
- * description: An product object
82
- * 404:
83
- * description: product not found
84
- */
85
- router.get(
86
- "/:id",
87
- asyncHandler(async (req: Request, res: Response) => {
88
- const product = products.find((i) => i.id === parseInt(req.params.id));
89
- if (!product) res.status(404).send("product not found");
90
- else res.json(product);
91
- })
92
- );
93
-
94
- /**
95
- * @swagger
96
- * /products/{id}:
97
- * put:
98
- * summary: Update an product
99
- * parameters:
100
- * - name: id
101
- * in: path
102
- * required: true
103
- * description: The ID of the product to update
104
- * schema:
105
- * type: integer
106
- * requestBody:
107
- * required: true
108
- * content:
109
- * application/json:
110
- * schema:
111
- * type: object
112
- * properties:
113
- * name:
114
- * type: string
115
- * description:
116
- * type: string
117
- * responses:
118
- * 200:
119
- * description: product updated
120
- * 404:
121
- * description: product not found
122
- */
123
- router.put(
124
- "/:id",
125
- asyncHandler(async (req: Request, res: Response) => {
126
- const product = products.find((i) => i.id === parseInt(req.params.id));
127
- if (!product) res.status(404).send("product not found");
128
- else {
129
- Object.assign(product, { id: req.body.id, name: req.body.name });
130
- res.json(product);
131
- }
132
- })
133
- );
134
-
135
- /**
136
- * @swagger
137
- * /products/{id}:
138
- * delete:
139
- * summary: Delete an product
140
- * parameters:
141
- * - name: id
142
- * in: path
143
- * required: true
144
- * description: The ID of the product to delete
145
- * schema:
146
- * type: integer
147
- * responses:
148
- * 204:
149
- * description: product deleted
150
- * 404:
151
- * description: product not found
152
- */
153
- router.delete(
154
- "/:id",
155
- asyncHandler(async (req: Request, res: Response) => {
156
- const productIndex = products.findIndex(
157
- (i) => i.id === parseInt(req.params.id)
158
- );
159
- if (productIndex === -1) res.status(404).send("product not found");
160
- else {
161
- products.splice(productIndex, 1);
162
- res.status(204).send();
163
- }
164
- })
165
- );
166
-
167
- export = router;
@@ -1,81 +0,0 @@
1
- import { Router, Request, Response } from "express";
2
- import asyncHandler from "express-async-handler";
3
- import UserController from "./user.controller";
4
-
5
- const router = Router();
6
- const userController = new UserController();
7
-
8
- /**
9
- * @swagger
10
- * /users:
11
- * post:
12
- * summary: Create a user
13
- * description: Create a new user.
14
- * requestBody:
15
- * required: true
16
- * content:
17
- * application/json:
18
- * schema:
19
- * type: object
20
- * required:
21
- * - username
22
- * - email
23
- * - password
24
- * properties:
25
- * username:
26
- * type: string
27
- * email:
28
- * type: string
29
- * password:
30
- * type: string
31
- * example: # Sample object
32
- * username: JessicaSmith
33
- * email: william.howard.taft@my-own-personal-domain.com
34
- * password: password123
35
- * responses:
36
- * 201:
37
- * description: product created
38
- */
39
- router.post(
40
- "/",
41
- asyncHandler(async (req: Request, res: Response) => {
42
- const result = await userController.createUser(req.body);
43
- res.status(201).json({ message: result });
44
- })
45
- );
46
-
47
- /**
48
- * @swagger
49
- * /user:
50
- * get:
51
- * summary: Get user home
52
- * description: Returns the user home page.
53
- * responses:
54
- * 200:
55
- * description: User home page
56
- */
57
- router.get(
58
- "/",
59
- asyncHandler(async (req: Request, res: Response) => {
60
- res.send("User Home");
61
- })
62
- );
63
-
64
- /**
65
- * @swagger
66
- * /user/profile:
67
- * get:
68
- * summary: Get user profile
69
- * description: Returns user profile information.
70
- * responses:
71
- * 200:
72
- * description: User profile information
73
- */
74
- router.get(
75
- "/profile",
76
- asyncHandler(async (req: Request, res: Response) => {
77
- res.send("User Profile");
78
- })
79
- );
80
-
81
- export = router;