devdad-express-utils 1.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.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # Express Utils
2
+
3
+ A collection of reusable utilities for Express.js applications, including error handling, async route wrapping, and custom error classes.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install express-utils
9
+ # or
10
+ yarn add express-utils
11
+ # or
12
+ pnpm add express-utils
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Error Handling
18
+
19
+ ```typescript
20
+ import express from "express";
21
+ import { errorHandler, AppError } from "express-utils";
22
+
23
+ const app = express();
24
+
25
+ // Your routes here
26
+
27
+ // Use the error handler as the last middleware
28
+ app.use(errorHandler);
29
+
30
+ // In your controllers, throw AppError for operational errors
31
+ throw new AppError("Something went wrong", 400);
32
+ ```
33
+
34
+ ### Async Route Wrapping
35
+
36
+ ```typescript
37
+ import { catchAsync } from "express-utils";
38
+
39
+ const getUsers = catchAsync(async (req, res, next) => {
40
+ const users = await User.find();
41
+ res.json(users);
42
+ });
43
+
44
+ app.get("/users", getUsers);
45
+ ```
46
+
47
+ ### Custom Error Class
48
+
49
+ ```typescript
50
+ import { AppError } from "express-utils";
51
+
52
+ throw new AppError("Validation failed", 400, ["Email is required"]);
53
+ ```
54
+
55
+ #### JavaScript Usage
56
+
57
+ ```javascript
58
+ const { AppError, catchAsync, errorHandler } = require("express-utils");
59
+
60
+ // Or with ES modules
61
+ import { AppError, catchAsync, errorHandler } from "express-utils";
62
+ ```
63
+
64
+ ## Error Handling Patterns
65
+
66
+ ### Using AppError
67
+
68
+ **For operational errors (expected errors like validation):**
69
+
70
+ ```typescript
71
+ // In controllers wrapped with catchAsync
72
+ const createUser = catchAsync(async (req, res, next) => {
73
+ // Validation fails
74
+ return next(new AppError("Email is required", 400));
75
+ });
76
+
77
+ // Or for unexpected errors
78
+ throw new AppError("Database connection failed", 500);
79
+ ```
80
+
81
+ **Why `next(new AppError())` over `throw`?**
82
+
83
+ - `next()` passes the error to your error handler middleware
84
+ - Allows centralized error handling and formatting
85
+ - Better for Express middleware pattern
86
+ - `throw` is more for unexpected errors that bubble up
87
+
88
+ ### Complete Example
89
+
90
+ ```javascript
91
+ const express = require("express");
92
+ const { AppError, catchAsync, errorHandler } = require("express-utils");
93
+
94
+ const app = express();
95
+
96
+ const getUser = catchAsync(async (req, res, next) => {
97
+ const user = await User.findById(req.params.id);
98
+ if (!user) {
99
+ return next(new AppError("User not found", 404));
100
+ }
101
+ res.json(user);
102
+ });
103
+
104
+ app.get("/users/:id", getUser);
105
+
106
+ // Error handler should be last
107
+ app.use(errorHandler);
108
+ ```
109
+
110
+ #### JavaScript Usage
111
+
112
+ ```javascript
113
+ const { AppError, catchAsync, errorHandler } = require("express-utils");
114
+
115
+ // Or with ES modules
116
+ import { AppError, catchAsync, errorHandler } from "express-utils";
117
+ ```
118
+
119
+ ## API
120
+
121
+ ### AppError
122
+
123
+ Custom error class for operational errors.
124
+
125
+ ```typescript
126
+ new AppError(message: string, statusCode: number, errors?: string[])
127
+ ```
128
+
129
+ ### catchAsync
130
+
131
+ Higher-order function to wrap async route handlers and catch errors.
132
+
133
+ ```typescript
134
+ catchAsync(fn: (req, res, next) => Promise<any>) => (req, res, next) => void
135
+ ```
136
+
137
+ ### errorHandler
138
+
139
+ Express error handling middleware with detailed logging in development.
140
+
141
+ ```typescript
142
+ errorHandler(err: any, req: Request, res: Response, next: NextFunction) => void
143
+ ```
144
+
145
+ ## Development
146
+
147
+ ```bash
148
+ # Install dependencies
149
+ pnpm install
150
+
151
+ # Build the package
152
+ pnpm run build
153
+
154
+ # Publish to npm
155
+ npm publish
156
+ ```
157
+
158
+ ## License
159
+
160
+ ISC
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,7 @@
1
+ export declare class AppError extends Error {
2
+ readonly statusCode: number;
3
+ readonly status: "fail" | "error";
4
+ readonly isOperational: true;
5
+ readonly errors?: string[];
6
+ constructor(message: string, statusCode: number, errors?: string[]);
7
+ }
@@ -0,0 +1,15 @@
1
+ export class AppError extends Error {
2
+ statusCode;
3
+ status;
4
+ isOperational;
5
+ errors;
6
+ constructor(message, statusCode, errors = []) {
7
+ super(message);
8
+ this.statusCode = statusCode;
9
+ this.status = statusCode.toString().startsWith("4") ? "fail" : "error";
10
+ this.isOperational = true;
11
+ this.errors = errors.length > 0 ? errors : undefined;
12
+ // Maintain proper stack trace
13
+ Error.captureStackTrace(this, this.constructor);
14
+ }
15
+ }
@@ -0,0 +1,2 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ export declare const catchAsync: (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) => (req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,5 @@
1
+ //#region Catch Async Handler
2
+ export const catchAsync = (fn) => (req, res, next) => {
3
+ fn(req, res, next).catch(next);
4
+ };
5
+ //#endregion
@@ -0,0 +1,3 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ declare const errorHandler: (err: any, req: Request, res: Response, next: NextFunction) => void;
3
+ export { errorHandler };
@@ -0,0 +1,47 @@
1
+ import { AppError } from "./AppError.js";
2
+ const sendErrorDev = (err, res) => {
3
+ res.status(err.statusCode || 500).json({
4
+ status: err.status || "error",
5
+ message: err.message,
6
+ error: err,
7
+ errors: err.errors || [],
8
+ stack: err.stack,
9
+ });
10
+ };
11
+ const sendErrorProd = (err, res) => {
12
+ // Operational, trusted error → send to client
13
+ if (err.isOperational) {
14
+ res.status(err.statusCode).json({
15
+ status: err.status,
16
+ message: err.message,
17
+ ...(err.errors && err.errors.length > 0 && { errors: err.errors }),
18
+ });
19
+ }
20
+ else {
21
+ // Unknown error → hide details
22
+ console.error("ERROR", err);
23
+ res.status(500).json({
24
+ status: "error",
25
+ message: "Something went wrong!",
26
+ });
27
+ }
28
+ };
29
+ const errorHandler = (err, req, res, next) => {
30
+ err.statusCode = err.statusCode || 500;
31
+ err.status = err.status || "error";
32
+ // Add this for Extra In-Depth Error Logging
33
+ console.error("Error details:", {
34
+ message: err.message,
35
+ statusCode: err.statusCode,
36
+ errors: err.errors,
37
+ stack: err.stack,
38
+ fullError: err,
39
+ });
40
+ if (process.env.NODE_ENV === "development") {
41
+ sendErrorDev(err, res);
42
+ }
43
+ else {
44
+ sendErrorProd(err instanceof AppError ? err : new AppError(err.message, 500), res);
45
+ }
46
+ };
47
+ export { errorHandler };
@@ -0,0 +1,3 @@
1
+ export { AppError } from "./AppError.js";
2
+ export { catchAsync } from "./catchAsync.js";
3
+ export { errorHandler } from "./errorHandler.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { AppError } from "./AppError.js";
2
+ export { catchAsync } from "./catchAsync.js";
3
+ export { errorHandler } from "./errorHandler.js";
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "devdad-express-utils",
3
+ "version": "1.0.0",
4
+ "description": "Reusable Express.js utilities for error handling, async wrapping, and more",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "prepublishOnly": "npm run build"
12
+ },
13
+ "keywords": [
14
+ "express",
15
+ "utilities",
16
+ "error-handling",
17
+ "typescript"
18
+ ],
19
+ "author": "Oliver Metz",
20
+ "license": "ISC",
21
+ "dependencies": {
22
+ "express": "^5.1.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/express": "^5.0.5",
26
+ "typescript": "^5.9.3"
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ]
31
+ }