create-express-kickstart 1.2.6 → 1.2.8
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 +8 -0
- package/README.md +12 -3
- package/bin/cli.js +24 -2
- package/package.json +1 -1
- package/templates/auth/auth.controller.js +30 -4
- package/templates/auth/auth.middleware.js +21 -4
package/.env.example
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# Basic Environment Variables
|
|
1
2
|
PORT=8000
|
|
2
3
|
MONGODB_URI=mongodb://localhost:27017/
|
|
3
4
|
CORS_ORIGIN=*
|
|
@@ -6,3 +7,10 @@ NODE_ENV=development
|
|
|
6
7
|
# Rate Limiting
|
|
7
8
|
RATE_LIMIT_WINDOW_MS=900000 # 15 minutes in milliseconds
|
|
8
9
|
RATE_LIMIT_MAX=100 # Maximum requests per windowMs
|
|
10
|
+
|
|
11
|
+
# Bcrypt Configuration
|
|
12
|
+
BCRYPT_SALT=10
|
|
13
|
+
|
|
14
|
+
# JWT Configuration
|
|
15
|
+
JWT_SECRET=your_jwt_secret_key
|
|
16
|
+
JWT_EXPIRES_IN=1d
|
package/README.md
CHANGED
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
A powerful CLI tool to instantly scaffold a production-ready, feature-rich backend Node.js template specifically tailored for Express API applications. It adheres to modern best practices, providing standard structures for error handling, CORS setups, routing, and middlewares right out of the box.
|
|
8
8
|
|
|
9
|
+
## Quick Start
|
|
10
|
+
```bash
|
|
11
|
+
npx create express-kickstart@latest my-app
|
|
12
|
+
```
|
|
13
|
+
|
|
9
14
|
## What is `create-express-kickstart`?
|
|
10
15
|
|
|
11
16
|
**The Purpose:**
|
|
@@ -110,10 +115,11 @@ const restrictedRoute = asyncHandler(async (req, res) => {
|
|
|
110
115
|
### `asyncHandler`
|
|
111
116
|
A wrapper for your async route handlers that eliminates the need for repetitive `try-catch` blocks.
|
|
112
117
|
|
|
113
|
-
### `hash.util.js`
|
|
114
|
-
If you choose to install the basic JWT Auth boilerplate, we automatically generate
|
|
118
|
+
### `jwt.util.js` & `hash.util.js`
|
|
119
|
+
If you choose to install the basic JWT Auth boilerplate, we automatically generate symmetric cryptography utilities wrapping `jsonwebtoken` and `bcryptjs`. This helps you map, hash, and assign JWT secrets synchronously against `.env`.
|
|
115
120
|
```javascript
|
|
116
121
|
import { hashData, compareData } from "#utils/hash.util.js";
|
|
122
|
+
import { generateToken, verifyToken } from "#utils/jwt.util.js";
|
|
117
123
|
|
|
118
124
|
const registerUser = asyncHandler(async (req, res) => {
|
|
119
125
|
const hashedPassword = await hashData("supersecret123");
|
|
@@ -122,7 +128,10 @@ const registerUser = asyncHandler(async (req, res) => {
|
|
|
122
128
|
|
|
123
129
|
const loginUser = asyncHandler(async (req, res) => {
|
|
124
130
|
const isMatch = await compareData("supersecret123", user.hashedPassword);
|
|
125
|
-
|
|
131
|
+
|
|
132
|
+
// Generate JWT natively hooked up to process.env.JWT_SECRET
|
|
133
|
+
const token = generateToken({ id: user._id, role: "user" });
|
|
134
|
+
return res.json({ token });
|
|
126
135
|
});
|
|
127
136
|
```
|
|
128
137
|
|
package/bin/cli.js
CHANGED
|
@@ -148,8 +148,16 @@ async function init() {
|
|
|
148
148
|
);
|
|
149
149
|
|
|
150
150
|
// Append JWT secret and Salt Rounds to env example
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
const authEnvConfig = `
|
|
152
|
+
# Bcrypt Configuration
|
|
153
|
+
BCRYPT_SALT=10
|
|
154
|
+
|
|
155
|
+
# JWT Configuration
|
|
156
|
+
JWT_SECRET=supersecretjwtkey123
|
|
157
|
+
JWT_EXPIRES_IN=1d
|
|
158
|
+
`;
|
|
159
|
+
fs.appendFileSync(path.join(projectPath, '.env.example'), authEnvConfig);
|
|
160
|
+
fs.appendFileSync(path.join(projectPath, '.env'), authEnvConfig);
|
|
153
161
|
|
|
154
162
|
const utilsPath = path.join(projectPath, 'src', 'utils');
|
|
155
163
|
if (!fs.existsSync(utilsPath)) {
|
|
@@ -167,6 +175,20 @@ export const hashData = async (data, saltRounds = process.env.BCRYPT_SALT) => {
|
|
|
167
175
|
export const compareData = async (data, hashedData) => {
|
|
168
176
|
return await bcrypt.compare(data, hashedData);
|
|
169
177
|
};
|
|
178
|
+
`
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
fs.writeFileSync(
|
|
182
|
+
path.join(utilsPath, 'jwt.util.js'),
|
|
183
|
+
`import jwt from "jsonwebtoken";
|
|
184
|
+
|
|
185
|
+
export const generateToken = (payload, expiresIn = process.env.JWT_EXPIRES_IN || "1d") => {
|
|
186
|
+
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn });
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export const verifyToken = (token) => {
|
|
190
|
+
return jwt.verify(token, process.env.JWT_SECRET);
|
|
191
|
+
};
|
|
170
192
|
`
|
|
171
193
|
);
|
|
172
194
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
|
+
import { asyncHandler } from "#utils/asyncHandler.js";
|
|
2
|
+
import { ApiResponse } from "#utils/ApiResponse.js";
|
|
3
|
+
import { generateToken } from "#utils/jwt.util.js";
|
|
4
|
+
import { hashData, compareData } from "#utils/hash.util.js";
|
|
5
|
+
|
|
1
6
|
export const authController = {
|
|
2
|
-
login: (req, res) =>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
login: asyncHandler(async (req, res) => {
|
|
8
|
+
// In a real app, you would fetch user from database and compare passwords here
|
|
9
|
+
// Example: const isMatch = await compareData(req.body.password, user.password);
|
|
10
|
+
|
|
11
|
+
// For now, let's just generate a mock token
|
|
12
|
+
const token = generateToken({ id: 1, role: "user" });
|
|
13
|
+
|
|
14
|
+
return res.status(200).json(
|
|
15
|
+
new ApiResponse(200, { token }, "Login successful")
|
|
16
|
+
);
|
|
17
|
+
}),
|
|
18
|
+
|
|
19
|
+
register: asyncHandler(async (req, res) => {
|
|
20
|
+
// Example: const hashedPassword = await hashData(req.body.password);
|
|
21
|
+
return res.status(201).json(
|
|
22
|
+
new ApiResponse(201, {}, "Register logic goes here")
|
|
23
|
+
);
|
|
24
|
+
}),
|
|
25
|
+
|
|
26
|
+
profile: asyncHandler(async (req, res) => {
|
|
27
|
+
return res.status(200).json(
|
|
28
|
+
new ApiResponse(200, { user: req.user }, "Protected profile data retrieved successfully.")
|
|
29
|
+
);
|
|
30
|
+
})
|
|
31
|
+
};
|
|
@@ -1,5 +1,22 @@
|
|
|
1
|
+
import { verifyToken } from "#utils/jwt.util.js";
|
|
2
|
+
import { ApiError } from "#utils/ApiError.js";
|
|
3
|
+
|
|
1
4
|
export const authMiddleware = (req, res, next) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
5
|
+
const authHeader = req.headers['authorization'];
|
|
6
|
+
if (!authHeader) {
|
|
7
|
+
return next(new ApiError(401, "Authorization header missing."));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const token = authHeader.split(' ')[1]; // Assuming "Bearer <token>"
|
|
11
|
+
if (!token) {
|
|
12
|
+
return next(new ApiError(401, "Token missing."));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const decoded = verifyToken(token);
|
|
17
|
+
req.user = decoded;
|
|
18
|
+
next();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return next(new ApiError(403, "Invalid or expired token."));
|
|
21
|
+
}
|
|
22
|
+
};
|