devdad-express-utils 1.1.2 → 1.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Express Utils
2
2
 
3
- A collection of reusable utilities for Express.js applications, including error handling, async route wrapping, and custom error classes.
3
+ A collection of reusable utilities for Express.js applications, including error handling, async route wrapping, custom error classes, and MongoDB connection management.
4
4
 
5
5
  ## Installation
6
6
 
@@ -83,6 +83,21 @@ app.get('/profile', authMiddleware, (req, res) => {
83
83
  });
84
84
  ```
85
85
 
86
+ ### Database Connection
87
+
88
+ MongoDB connection utility with automatic reconnection and retry logic.
89
+
90
+ ```typescript
91
+ import { connectDB, getDBStatus } from "devdad-express-utils";
92
+
93
+ // Connect to MongoDB (ensure MONGO_URI is set in environment)
94
+ await connectDB();
95
+
96
+ // Check connection status
97
+ const status = getDBStatus();
98
+ console.log(status); // { isConnected: true, readyState: 1, host: '...', name: '...' }
99
+ ```
100
+
86
101
  ## Error Handling Patterns
87
102
 
88
103
  ### Using AppError
@@ -190,6 +205,22 @@ Middleware for JWT authentication.
190
205
  requireAuth(options: { secret: string, algorithms?: Algorithm[] }) => (req, res, next) => void
191
206
  ```
192
207
 
208
+ ### connectDB
209
+
210
+ Connects to MongoDB with retry logic and automatic reconnection.
211
+
212
+ ```typescript
213
+ connectDB() => Promise<void>
214
+ ```
215
+
216
+ ### getDBStatus
217
+
218
+ Gets the current MongoDB connection status.
219
+
220
+ ```typescript
221
+ getDBStatus() => { isConnected: boolean; readyState: number; host: string; name: string; }
222
+ ```
223
+
193
224
  ## Development
194
225
 
195
226
  ```bash
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Database connection class for MongoDB using Mongoose.
3
+ * Provides automatic reconnection, retry logic, and connection status monitoring.
4
+ */
5
+ declare class DatabaseConnection {
6
+ private retryCount;
7
+ private isConnected;
8
+ /**
9
+ * Creates a new DatabaseConnection instance.
10
+ * Sets up event listeners for connection events and application termination signals.
11
+ */
12
+ constructor();
13
+ /**
14
+ * Establishes a connection to MongoDB.
15
+ * @throws {Error} If MONGO_URI is not defined in environment variables.
16
+ */
17
+ connect(): Promise<void>;
18
+ /**
19
+ * Handles connection errors by retrying the connection up to MAX_RETRIES times.
20
+ * Exits the process if all retries fail.
21
+ */
22
+ private handleConnectionError;
23
+ /**
24
+ * Handles disconnection events by attempting to reconnect if not already connected.
25
+ */
26
+ private handleDisconnection;
27
+ /**
28
+ * Handles application termination by closing the database connection gracefully.
29
+ */
30
+ private handleAppTermination;
31
+ /**
32
+ * Gets the current connection status.
33
+ * @returns An object containing connection status information.
34
+ */
35
+ getConnectionStatus(): {
36
+ isConnected: boolean;
37
+ readyState: number;
38
+ host: string;
39
+ name: string;
40
+ };
41
+ }
42
+ declare const _default: () => Promise<void>;
43
+ export default _default;
44
+ export declare const getDBStatus: () => {
45
+ isConnected: boolean;
46
+ readyState: number;
47
+ host: string;
48
+ name: string;
49
+ };
50
+ export { DatabaseConnection };
@@ -0,0 +1,127 @@
1
+ import mongoose from "mongoose";
2
+ /**
3
+ * Maximum number of connection retry attempts
4
+ */
5
+ const MAX_RETRIES = 3;
6
+ /**
7
+ * Interval between retry attempts in milliseconds
8
+ */
9
+ const RETRY_INTERVAL = 5000; // 5 seconds
10
+ /**
11
+ * Database connection class for MongoDB using Mongoose.
12
+ * Provides automatic reconnection, retry logic, and connection status monitoring.
13
+ */
14
+ class DatabaseConnection {
15
+ retryCount;
16
+ isConnected;
17
+ /**
18
+ * Creates a new DatabaseConnection instance.
19
+ * Sets up event listeners for connection events and application termination signals.
20
+ */
21
+ constructor() {
22
+ this.retryCount = 0;
23
+ this.isConnected = false;
24
+ // Configure mongoose settings
25
+ mongoose.set("strictQuery", true);
26
+ // Handle connection events
27
+ mongoose.connection.on("connected", () => {
28
+ console.log("✅ MongoDB connected successfully");
29
+ this.isConnected = true;
30
+ });
31
+ mongoose.connection.on("error", (err) => {
32
+ console.error("❌ MongoDB connection error:", err);
33
+ this.isConnected = false;
34
+ });
35
+ mongoose.connection.on("disconnected", () => {
36
+ console.log("⚠️ MongoDB disconnected");
37
+ this.isConnected = false;
38
+ this.handleDisconnection();
39
+ });
40
+ // Handle application termination
41
+ process.on("SIGINT", this.handleAppTermination.bind(this));
42
+ process.on("SIGTERM", this.handleAppTermination.bind(this));
43
+ }
44
+ /**
45
+ * Establishes a connection to MongoDB.
46
+ * @throws {Error} If MONGO_URI is not defined in environment variables.
47
+ */
48
+ async connect() {
49
+ try {
50
+ if (!process.env.MONGO_URI) {
51
+ throw new Error("MongoDB URI is not defined in environment variables");
52
+ }
53
+ const connectionOptions = {
54
+ maxPoolSize: 10,
55
+ serverSelectionTimeoutMS: 5000,
56
+ socketTimeoutMS: 45000,
57
+ family: 4, // Use IPv4
58
+ };
59
+ if (process.env.NODE_ENV === "development") {
60
+ mongoose.set("debug", true);
61
+ }
62
+ await mongoose.connect(process.env.MONGO_URI, connectionOptions);
63
+ this.retryCount = 0; // Reset retry count on successful connection
64
+ }
65
+ catch (error) {
66
+ console.error("Failed to connect to MongoDB:", error.message);
67
+ await this.handleConnectionError();
68
+ }
69
+ }
70
+ /**
71
+ * Handles connection errors by retrying the connection up to MAX_RETRIES times.
72
+ * Exits the process if all retries fail.
73
+ */
74
+ async handleConnectionError() {
75
+ if (this.retryCount < MAX_RETRIES) {
76
+ this.retryCount++;
77
+ console.log(`Retrying connection... Attempt ${this.retryCount} of ${MAX_RETRIES}`);
78
+ await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL));
79
+ return this.connect();
80
+ }
81
+ else {
82
+ console.error(`Failed to connect to MongoDB after ${MAX_RETRIES} attempts`);
83
+ process.exit(1);
84
+ }
85
+ }
86
+ /**
87
+ * Handles disconnection events by attempting to reconnect if not already connected.
88
+ */
89
+ handleDisconnection() {
90
+ if (!this.isConnected) {
91
+ console.log("Attempting to reconnect to MongoDB...");
92
+ this.connect();
93
+ }
94
+ }
95
+ /**
96
+ * Handles application termination by closing the database connection gracefully.
97
+ */
98
+ async handleAppTermination() {
99
+ try {
100
+ await mongoose.connection.close();
101
+ console.log("MongoDB connection closed through app termination");
102
+ process.exit(0);
103
+ }
104
+ catch (err) {
105
+ console.error("Error during database disconnection:", err);
106
+ process.exit(1);
107
+ }
108
+ }
109
+ /**
110
+ * Gets the current connection status.
111
+ * @returns An object containing connection status information.
112
+ */
113
+ getConnectionStatus() {
114
+ return {
115
+ isConnected: this.isConnected,
116
+ readyState: mongoose.connection.readyState,
117
+ host: mongoose.connection.host,
118
+ name: mongoose.connection.name,
119
+ };
120
+ }
121
+ }
122
+ // Create a singleton instance
123
+ const dbConnection = new DatabaseConnection();
124
+ // Export the connect function and the instance
125
+ export default dbConnection.connect.bind(dbConnection);
126
+ export const getDBStatus = dbConnection.getConnectionStatus.bind(dbConnection);
127
+ export { DatabaseConnection };
package/dist/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export { catchAsync } from "./catchAsync.js";
3
3
  export { errorHandler } from "./errorHandler.js";
4
4
  export { sendSuccess, sendError } from "./responseFormatter.js";
5
5
  export { requireAuth } from "./authWrapper.js";
6
+ export { default as connectDB, getDBStatus, DatabaseConnection } from "./DatabaseConnection.js";
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export { catchAsync } from "./catchAsync.js";
3
3
  export { errorHandler } from "./errorHandler.js";
4
4
  export { sendSuccess, sendError } from "./responseFormatter.js";
5
5
  export { requireAuth } from "./authWrapper.js";
6
+ export { default as connectDB, getDBStatus, DatabaseConnection } from "./DatabaseConnection.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devdad-express-utils",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Reusable Express.js utilities for error handling, async wrapping, and more",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,14 +26,18 @@
26
26
  },
27
27
  "license": "ISC",
28
28
  "dependencies": {
29
+ "@types/mongoose": "^5.11.96",
29
30
  "express": "^5.1.0",
30
- "jsonwebtoken": "^9.0.2"
31
+ "jsonwebtoken": "^9.0.2",
32
+ "mongoose": "^9.0.0"
31
33
  },
32
34
  "devDependencies": {
33
35
  "@types/express": "^5.0.5",
34
36
  "@types/jsonwebtoken": "^9.0.10",
37
+ "@types/mongodb-memory-server": "^1.8.0",
35
38
  "@types/supertest": "^6.0.3",
36
39
  "@vitest/ui": "^4.0.14",
40
+ "mongodb-memory-server": "^10.3.0",
37
41
  "supertest": "^7.1.4",
38
42
  "typescript": "^5.9.3",
39
43
  "vitest": "^4.0.14"