codeweaver 2.2.0 → 2.3.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/.env.example ADDED
@@ -0,0 +1,20 @@
1
+ # Environment
2
+ NODE_ENV=development # or "production" depending on your deployment
3
+
4
+ # Server
5
+ HTTP=http://localhost:3000
6
+ PORT=3000
7
+
8
+ # Feature flags
9
+ SWAGGER=true
10
+
11
+ # Timeouts and limits
12
+ TIMEOUT=30
13
+
14
+ # Rate limiting (separate vars)
15
+ RATE_LIMIT_TIME_SPAN=60
16
+ RATE_LIMIT_ALLOWED_CALLS=100
17
+
18
+ # Memoization and cache
19
+ MEMOIZE_TIME=300
20
+ CACHE_SIZE=1000
package/README.md CHANGED
@@ -10,10 +10,14 @@
10
10
  - **Express**: A lightweight web framework for building server-side applications in Node.js.
11
11
  - **TypeScript**: Adds strong typing for enhanced development experience and reduced runtime errors.
12
12
  - **Modular Router Structure**: Automates importing and mounting routers, ensuring a clean separation of endpoints and logic for easier scalability.
13
+ - **Dependency resolver**: A simple dependency resolver that uses a lightweight container to manage and inject dependencies at runtime.
13
14
  - **Swagger Integration**: Automatically generates interactive API documentation, facilitating easier understanding of available endpoints for developers and consumers.
14
15
  - **Async Handlers**: Utilizes async/await syntax for cleaner, more maintainable asynchronous code without callback nesting.
15
16
  - **Zod**: Implements schema validation for input data.
16
- - **utils-decorators**: A collection of middleware utilities (throttling, caching, and error handling) designed to strengthen application resilience.
17
+ - **Utils-decorators**: A collection of middleware utilities utils-decorators (throttling, caching, and error handling) designed to strengthen application resilience.
18
+ - **Logger**: A Winston-based logger (with LogForm) that provides scalable, leveled logging, structured JSON output, and pluggable transports (console and file)
19
+
20
+ Here's a revised Installation section that explicitly supports pnpm in addition to npm. I kept the formatting and steps intact, adding clear pnpm equivalents.
17
21
 
18
22
  ## Installation
19
23
 
@@ -29,9 +33,19 @@ To get started with the project, follow these steps:
29
33
 
30
34
  2. **Install dependencies**:
31
35
 
32
- ```bash
33
- npm install
34
- ```
36
+ Choose your package manager and install:
37
+
38
+ - Using npm:
39
+
40
+ ```bash
41
+ npm install
42
+ ```
43
+
44
+ - Using pnpm:
45
+
46
+ ```bash
47
+ pnpm install
48
+ ```
35
49
 
36
50
  3. **Run the application**:
37
51
 
@@ -39,14 +53,29 @@ To get started with the project, follow these steps:
39
53
  npm start
40
54
  ```
41
55
 
56
+ Or, if you used pnpm:
57
+
58
+ ```bash
59
+ pnpm start
60
+ ```
61
+
42
62
  4. **Visit the Swagger UI**: Open your browser and go to `http://localhost:3000/api-docs` to view the automatically generated API documentation.
43
63
 
44
64
  5. **Build**: Compile the TypeScript files for the production environment:
45
65
 
46
- ```bash
47
- npm run build
48
- npm run serve
49
- ```
66
+ - Using npm:
67
+
68
+ ```bash
69
+ npm run build
70
+ npm run serve
71
+ ```
72
+
73
+ - Using pnpm:
74
+
75
+ ```bash
76
+ pnpm run build
77
+ pnpm run serve
78
+ ```
50
79
 
51
80
  ## Sample Project Structure
52
81
 
@@ -89,9 +118,10 @@ Example of a basic router:
89
118
  import { Router, Request, Response } from "express";
90
119
  import asyncHandler from "express-async-handler";
91
120
  import UserController from "./user.controller";
121
+ import { resolve } from "@/utilities/container";
92
122
 
93
123
  const router = Router();
94
- const userController = new UserController();
124
+ const userController = resolve(UserController);
95
125
 
96
126
  /**
97
127
  * @swagger
@@ -210,17 +240,13 @@ import config from "@/config";
210
240
  import { users } from "@/db";
211
241
  import { User } from "@/entities/user.entity";
212
242
  import { MapAsyncCache } from "@/utilities/cache/memory-cache";
243
+ import { Injectable } from "@/utilities/container";
213
244
 
214
245
  function exceedHandler() {
215
246
  const message = "Too much call in allowed window";
216
247
  throw new ResponseError(message, 429);
217
248
  }
218
249
 
219
- function userNotFoundHandler(e: ResponseError) {
220
- const message = "User not found.";
221
- throw new ResponseError(message, 404, e?.message);
222
- }
223
-
224
250
  function invalidInputHandler(e: ResponseError) {
225
251
  const message = "Invalid input";
226
252
  throw new ResponseError(message, 400, e?.message);
@@ -229,6 +255,7 @@ function invalidInputHandler(e: ResponseError) {
229
255
  const usersCache = new MapAsyncCache<UserDto[]>(config.cacheSize);
230
256
  const userCache = new MapAsyncCache<UserDto>(config.cacheSize);
231
257
 
258
+ @Injectable()
232
259
  /**
233
260
  * Controller for handling user-related operations
234
261
  * @class UserController
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeweaver",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "main": "src/main.ts",
5
5
  "bin": {
6
6
  "create-codeweaver-app": "./command.js"
package/src/config.ts CHANGED
@@ -4,8 +4,9 @@ import {
4
4
  rateLimitTimeSpan,
5
5
  rateLimitAllowedCalls,
6
6
  timeout,
7
- portNumber,
7
+ port,
8
8
  cacheSize,
9
+ http,
9
10
  } from "./constants";
10
11
  import { SwaggerOptions } from "./swagger-options";
11
12
  import { stringToBoolean } from "./utilities/conversion";
@@ -19,6 +20,7 @@ import { stringToBoolean } from "./utilities/conversion";
19
20
  */
20
21
  interface Config {
21
22
  devMode: boolean;
23
+ http: string;
22
24
  port: number;
23
25
  swagger: boolean;
24
26
  swaggerOptions: SwaggerOptions;
@@ -29,11 +31,10 @@ interface Config {
29
31
  cacheSize: number;
30
32
  }
31
33
 
32
- const port = Number(process.env.PORT) || portNumber;
33
-
34
34
  let config: Config = {
35
35
  devMode: process.env.NODE_ENV !== productionEnvironment,
36
- port,
36
+ http: process.env.HTTP || http,
37
+ port: Number(process.env.PORT) || port,
37
38
  swagger: stringToBoolean(process.env.SWAGGER || "true"),
38
39
  swaggerOptions: {
39
40
  swaggerDefinition: {
@@ -57,9 +58,10 @@ let config: Config = {
57
58
  ], // Path to the API docs
58
59
  },
59
60
  timeout: Number(process.env.TIMEOUT) || timeout,
60
- rateLimitTimeSpan: Number(process.env.RATE_LIMIT) || rateLimitTimeSpan,
61
+ rateLimitTimeSpan:
62
+ Number(process.env.RATE_LIMIT_TIME_SPAN) || rateLimitTimeSpan,
61
63
  rateLimitAllowedCalls:
62
- Number(process.env.RATE_LIMIT) || rateLimitAllowedCalls,
64
+ Number(process.env.RATE_LIMIT_ALLOWED_CALLS) || rateLimitAllowedCalls,
63
65
  memoizeTime: Number(process.env.MEMOIZE_TIME) || memoizeTime,
64
66
  cacheSize: Number(process.env.CACHE_SIZE) || cacheSize,
65
67
  };
package/src/constants.ts CHANGED
@@ -1,7 +1,12 @@
1
+ export const http = "http://localhost";
2
+ export const port = 3000;
1
3
  export const timeout = 20000;
2
4
  export const rateLimitTimeSpan = 60000;
3
5
  export const rateLimitAllowedCalls = 300;
4
6
  export const memoizeTime = 1000 * 60 * 60;
5
7
  export const cacheSize = 1000;
6
8
  export const productionEnvironment = "production";
7
- export const portNumber = 3000;
9
+ export const swaggerPath = "/api-docs";
10
+ export const routerDir = "/routers";
11
+ export const routerExtension = ".router";
12
+ export const defaultRouter = "index";
package/src/main.ts CHANGED
@@ -5,6 +5,14 @@ import config from "./config";
5
5
  import { ResponseError } from "./utilities/error-handling";
6
6
  import { resolve } from "./utilities/container";
7
7
  import { WinstonLoggerService } from "./utilities/logger/winston-logger.service";
8
+ import "dotenv/config";
9
+ import {
10
+ defaultRouter,
11
+ routerDir,
12
+ routerExtension,
13
+ swaggerPath,
14
+ } from "./constants";
15
+ //import cors from "cors";
8
16
 
9
17
  /**
10
18
  * Recursively loads Express routers from directory
@@ -30,17 +38,20 @@ function loadRouters(routerPath: string, basePath: string = "") {
30
38
 
31
39
  // Only handle router files
32
40
  if (
33
- !entry.name.endsWith(".router.ts") &&
34
- !entry.name.endsWith(".router.js")
41
+ !entry.name.endsWith(`${routerExtension}.ts`) &&
42
+ !entry.name.endsWith(`${routerExtension}.js`)
35
43
  ) {
36
44
  continue;
37
45
  }
38
46
 
39
47
  // Build route path safely
40
48
  const routePath = path
41
- .join(basePath, entry.name.replace(/\.router\.[tj]s$/, ""))
49
+ .join(
50
+ basePath,
51
+ entry.name.replace(new RegExp(`\\${routerExtension}\\.([tj]s)$`), "")
52
+ )
42
53
  .replace(/\\/g, "/")
43
- .replace(/\/?index$/g, "");
54
+ .replace(new RegExp(`\\/?${defaultRouter}$`), "");
44
55
 
45
56
  // Optional: skip if the target path would be empty (maps to /)
46
57
  const mountPath = "/" + (routePath || "");
@@ -53,11 +64,12 @@ function loadRouters(routerPath: string, basePath: string = "") {
53
64
  }
54
65
 
55
66
  const app = express();
67
+ //app.use(cors());
56
68
  app.use(express.json());
57
69
  app.use(express.urlencoded({ extended: true }));
58
70
 
59
71
  // Automatically import all routers from the /src/routers directory
60
- const routersPath = path.join(__dirname, "/routers");
72
+ const routersPath = path.join(__dirname, routerDir);
61
73
  loadRouters(routersPath);
62
74
 
63
75
  // Swagger setup
@@ -65,7 +77,7 @@ if (config.swagger) {
65
77
  const swaggerJsDoc = require("swagger-jsdoc");
66
78
  const swaggerUi = require("swagger-ui-express");
67
79
  const swaggerDocs = swaggerJsDoc(config.swaggerOptions);
68
- app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
80
+ app.use(swaggerPath, swaggerUi.serve, swaggerUi.setup(swaggerDocs));
69
81
  }
70
82
 
71
83
  const logger = resolve(WinstonLoggerService);
@@ -74,21 +86,33 @@ const logger = resolve(WinstonLoggerService);
74
86
  app.use(
75
87
  (error: ResponseError, req: Request, res: Response, next: NextFunction) => {
76
88
  const status = error.status ?? 500;
89
+ const errorObject = {
90
+ status,
91
+ code: error.code,
92
+ input: error.input,
93
+ stack: error.stack,
94
+ cause: error.cause,
95
+ };
96
+
77
97
  res.status(status).json(error);
78
98
  if (status < 500) {
79
- logger.warn(error.message, "Invalid request", error.details);
99
+ logger.warn(error.message, "Invalid request", error.details, errorObject);
80
100
  } else {
81
- logger.error(error.message, "Server error", error.details);
101
+ if (status == 401 || status == 403) {
102
+ logger.fatal(error.message, "Forbidden", error.details, errorObject);
103
+ } else {
104
+ logger.error(error.message, "Server error", error.details, errorObject);
105
+ }
82
106
  }
83
107
  }
84
108
  );
85
109
 
86
110
  // Start the server
87
111
  app.listen(config.port, () => {
88
- console.log(`Server is running on http://localhost:${config.port}`);
112
+ console.log(`Server is running on ${config.http}:${config.port}`);
89
113
  if (config.devMode) {
90
114
  console.log(
91
- `Swagger UI is available at http://localhost:${config.port}/api-docs`
115
+ `Swagger UI is available at ${config.http}:${config.port}${swaggerPath}`
92
116
  );
93
117
  }
94
118
  });
@@ -1,3 +0,0 @@
1
- {
2
- "cSpell.words": ["microframework"]
3
- }