nodejs-structure-cli 1.0.4 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-structure-cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "description": "The ultimate nodejs quickstart structure CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
6
  "main": "bin/index.js",
@@ -10,6 +10,14 @@ class UserModel {
10
10
  return this.mockData;
11
11
  }
12
12
 
13
+ static async findOne(query) {
14
+ const { where } = query || {};
15
+ if (where && where.email) {
16
+ return this.mockData.find((u) => u.email === where.email);
17
+ }
18
+ return null;
19
+ }
20
+
13
21
  static async create(data) {
14
22
  const { id, ...rest } = data;
15
23
  const newUser = { id: String(this.mockData.length + 1), ...rest };
@@ -78,6 +86,10 @@ User.init(
78
86
  type: DataTypes.DATE,
79
87
  allowNull: true,
80
88
  },
89
+ refresh_token: {
90
+ type: DataTypes.STRING,
91
+ allowNull: true,
92
+ },
81
93
  },
82
94
  {
83
95
  sequelize,
@@ -1,4 +1,4 @@
1
- const mongoose = require('mongoose');
1
+ import mongoose from 'mongoose';
2
2
 
3
3
  const UserSchema = new mongoose.Schema({
4
4
  name: {
@@ -22,6 +22,10 @@ const UserSchema = new mongoose.Schema({
22
22
  default: null
23
23
  },
24
24
  <%_ } _%>
25
+ refresh_token: {
26
+ type: String,
27
+ default: null
28
+ },
25
29
  createdAt: {
26
30
  type: Date,
27
31
  default: Date.now
@@ -32,4 +36,4 @@ const UserSchema = new mongoose.Schema({
32
36
  }
33
37
  });
34
38
 
35
- module.exports = mongoose.model('User', UserSchema);
39
+ export default mongoose.model('User', UserSchema);
@@ -4,6 +4,7 @@ export interface User {
4
4
  email: string;
5
5
  <% if (auth && auth !== 'None') { %>password?: string;<% } %>
6
6
  <% if (includeMulter) { %>imageUrl?: string;<% } %>
7
+ refresh_token?: string;
7
8
  }
8
9
 
9
10
  export default class UserModel {
@@ -17,6 +18,14 @@ export default class UserModel {
17
18
  return this.mockData;
18
19
  }
19
20
 
21
+ static async findOne(query: any) {
22
+ const { where } = query || {};
23
+ if (where && where.email) {
24
+ return this.mockData.find((u) => u.email === where.email);
25
+ }
26
+ return null;
27
+ }
28
+
20
29
  static async create(data: Omit<User, 'id'> & { id?: string | number | null }) {
21
30
  const { id: _, ...rest } = data;
22
31
  const newUser: User = { id: String(this.mockData.length + 1), ...rest };
@@ -89,6 +98,10 @@ User.init(
89
98
  type: DataTypes.DATE,
90
99
  allowNull: true,
91
100
  },
101
+ refresh_token: {
102
+ type: DataTypes.STRING,
103
+ allowNull: true,
104
+ },
92
105
  },
93
106
  {
94
107
  sequelize,
@@ -5,6 +5,7 @@ export interface IUser extends Document {
5
5
  email: string;
6
6
  <% if (auth && auth !== 'None') { %>password?: string;<% } %>
7
7
  <% if (includeMulter) { %>imageUrl?: string;<% } %>
8
+ refresh_token?: string;
8
9
  createdAt: Date;
9
10
  deletedAt?: Date | null;
10
11
  }
@@ -21,6 +22,7 @@ const UserSchema: Schema = new Schema({
21
22
  },
22
23
  <% if (auth && auth !== 'None') { %>password: { type: String },<% } %>
23
24
  <% if (includeMulter) { %>imageUrl: { type: String },<% } %>
25
+ refresh_token: { type: String, default: null },
24
26
  createdAt: {
25
27
  type: Date,
26
28
  default: Date.now
@@ -35,26 +35,51 @@ export const login = async (req, res, next) => {
35
35
  import jwt from 'jsonwebtoken';
36
36
  import bcrypt from 'bcryptjs';
37
37
  import { ApiError } from '../errors/ApiError<% if (language === 'TypeScript') { %>.ts<% } else { %>.js<% } %>';
38
+ import User from '<% if (architecture === 'MVC') { %>../models/User.js<% } else { %>../../infrastructure/database/models/User.js<% } %>';
38
39
 
39
- // Mock User database (In production, use your database models)
40
- const users = [];
40
+ const generateTokens = (user) => {
41
+ const accessToken = jwt.sign(
42
+ { id: user.id || user._id, email: user.email },
43
+ process.env.JWT_SECRET || 'secret',
44
+ { expiresIn: process.env.JWT_EXPIRES_IN || '15m' }
45
+ );
46
+
47
+ const refreshToken = jwt.sign(
48
+ { id: user.id || user._id },
49
+ process.env.JWT_REFRESH_SECRET || 'refresh_secret',
50
+ { expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d' }
51
+ );
52
+
53
+ return { accessToken, refreshToken };
54
+ };
41
55
 
42
56
  export const register = async (req, res, next) => {
43
57
  try {
44
58
  const { email, password, name } = req.body;
45
59
 
46
- const existingUser = users.find(u => u.email === email);
60
+ const existingUser = await User.findOne(<% if (database === 'MongoDB') { %>{ email }<% } else { %>{ where: { email } }<% } %>);
47
61
  if (existingUser) {
48
62
  throw new ApiError(400, 'User already exists');
49
63
  }
50
64
 
51
65
  const hashedPassword = await bcrypt.hash(password, 10);
52
- const newUser = { id: Date.now(), email, password: hashedPassword, name };
53
- users.push(newUser);
66
+ const user = await User.create({ email, password: hashedPassword, name });
67
+
68
+ const { accessToken, refreshToken } = generateTokens(user);
69
+
70
+ // Store refresh token in DB
71
+ <% if (database === 'MongoDB') { %>
72
+ user.refresh_token = refreshToken;
73
+ await user.save();
74
+ <% } else { %>
75
+ await User.update({ refresh_token: refreshToken }, { where: { id: user.id } });
76
+ <% } %>
54
77
 
55
78
  res.status(201).json({
56
79
  message: 'User registered successfully',
57
- user: { id: newUser.id, email: newUser.email, name: newUser.name }
80
+ accessToken,
81
+ refreshToken,
82
+ user: { id: user.id || user._id, email: user.email, name: user.name }
58
83
  });
59
84
  } catch (error) {
60
85
  next(error);
@@ -65,7 +90,7 @@ export const login = async (req, res, next) => {
65
90
  try {
66
91
  const { email, password } = req.body;
67
92
 
68
- const user = users.find(u => u.email === email);
93
+ const user = await User.findOne(<% if (database === 'MongoDB') { %>{ email }<% } else { %>{ where: { email } }<% } %>);
69
94
  if (!user) {
70
95
  throw new ApiError(401, 'Invalid credentials');
71
96
  }
@@ -75,21 +100,59 @@ export const login = async (req, res, next) => {
75
100
  throw new ApiError(401, 'Invalid credentials');
76
101
  }
77
102
 
78
- const token = jwt.sign(
79
- { id: user.id, email: user.email },
80
- process.env.JWT_SECRET || 'secret',
81
- { expiresIn: process.env.JWT_EXPIRES_IN || '1d' }
82
- );
103
+ const { accessToken, refreshToken } = generateTokens(user);
104
+
105
+ // Update refresh token in DB
106
+ <% if (database === 'MongoDB') { %>
107
+ user.refresh_token = refreshToken;
108
+ await user.save();
109
+ <% } else { %>
110
+ await User.update({ refresh_token: refreshToken }, { where: { id: user.id } });
111
+ <% } %>
83
112
 
84
113
  res.status(200).json({
85
114
  message: 'Login successful',
86
- token,
87
- user: { id: user.id, email: user.email, name: user.name }
115
+ accessToken,
116
+ refreshToken,
117
+ user: { id: user.id || user._id, email: user.email, name: user.name }
88
118
  });
89
119
  } catch (error) {
90
120
  next(error);
91
121
  }
92
122
  };
123
+
124
+ export const refreshToken = async (req, res, next) => {
125
+ try {
126
+ const { token } = req.body;
127
+ if (!token) {
128
+ throw new ApiError(400, 'Refresh token is required');
129
+ }
130
+
131
+ const decoded = jwt.verify(token, process.env.JWT_REFRESH_SECRET || 'refresh_secret');
132
+ const user = await User.findOne(<% if (database === 'MongoDB') { %>{ _id: decoded.id, refresh_token: token }<% } else { %>{ where: { id: decoded.id, refresh_token: token } }<% } %>);
133
+
134
+ if (!user) {
135
+ throw new ApiError(401, 'Invalid refresh token');
136
+ }
137
+
138
+ const tokens = generateTokens(user);
139
+
140
+ // Update refresh token in DB (Rotation)
141
+ <% if (database === 'MongoDB') { %>
142
+ user.refresh_token = tokens.refreshToken;
143
+ await user.save();
144
+ <% } else { %>
145
+ await User.update({ refresh_token: tokens.refreshToken }, { where: { id: user.id } });
146
+ <% } %>
147
+
148
+ res.status(200).json({
149
+ message: 'Token refreshed successfully',
150
+ ...tokens
151
+ });
152
+ } catch (error) {
153
+ next(new ApiError(401, 'Invalid or expired refresh token'));
154
+ }
155
+ };
93
156
  <% } else if (auth === 'OAuth' || googleLogin === 'Google Login') { %>
94
157
  export const googleCallback = (req, res) => {
95
158
  // Passport handles the authentication, we just redirect or respond
@@ -36,26 +36,51 @@ export const login = async (req: Request, res: Response, next: NextFunction) =>
36
36
  import jwt from 'jsonwebtoken';
37
37
  import bcrypt from 'bcryptjs';
38
38
  import { ApiError } from '../errors/ApiError';
39
+ import User from '<% if (architecture === 'MVC') { %>../models/User<% if (language === 'TypeScript') { %><% } else { %>.js<% } %><% } else { %>../../infrastructure/database/models/User<% if (language === 'TypeScript') { %><% } else { %>.js<% } %><% } %>';
39
40
 
40
- // Mock User database (In production, use your database models)
41
- const users: any[] = [];
41
+ const generateTokens = (user: any) => {
42
+ const accessToken = jwt.sign(
43
+ { id: user.id || user._id, email: user.email },
44
+ process.env.JWT_SECRET || 'secret',
45
+ { expiresIn: process.env.JWT_EXPIRES_IN || '15m' }
46
+ );
47
+
48
+ const refreshToken = jwt.sign(
49
+ { id: user.id || user._id },
50
+ process.env.JWT_REFRESH_SECRET || 'refresh_secret',
51
+ { expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d' }
52
+ );
53
+
54
+ return { accessToken, refreshToken };
55
+ };
42
56
 
43
57
  export const register = async (req: Request, res: Response, next: NextFunction) => {
44
58
  try {
45
59
  const { email, password, name } = req.body;
46
60
 
47
- const existingUser = users.find(u => u.email === email);
61
+ const existingUser = await (User as any).findOne(<% if (database === 'MongoDB') { %>{ email }<% } else { %>{ where: { email } }<% } %>);
48
62
  if (existingUser) {
49
63
  throw new ApiError(400, 'User already exists');
50
64
  }
51
65
 
52
66
  const hashedPassword = await bcrypt.hash(password, 10);
53
- const newUser = { id: Date.now(), email, password: hashedPassword, name };
54
- users.push(newUser);
67
+ const user = await (User as any).create({ email, password: hashedPassword, name });
68
+
69
+ const { accessToken, refreshToken } = generateTokens(user);
70
+
71
+ // Store refresh token in DB
72
+ <% if (database === 'MongoDB') { %>
73
+ user.refresh_token = refreshToken;
74
+ await user.save();
75
+ <% } else { %>
76
+ await (User as any).update({ refresh_token: refreshToken }, { where: { id: user.id } });
77
+ <% } %>
55
78
 
56
79
  res.status(201).json({
57
80
  message: 'User registered successfully',
58
- user: { id: newUser.id, email: newUser.email, name: newUser.name }
81
+ accessToken,
82
+ refreshToken,
83
+ user: { id: user.id || user._id, email: user.email, name: user.name }
59
84
  });
60
85
  } catch (error: any) {
61
86
  next(error);
@@ -66,7 +91,7 @@ export const login = async (req: Request, res: Response, next: NextFunction) =>
66
91
  try {
67
92
  const { email, password } = req.body;
68
93
 
69
- const user = users.find(u => u.email === email);
94
+ const user = await (User as any).findOne(<% if (database === 'MongoDB') { %>{ email }<% } else { %>{ where: { email } }<% } %>);
70
95
  if (!user) {
71
96
  throw new ApiError(401, 'Invalid credentials');
72
97
  }
@@ -76,21 +101,59 @@ export const login = async (req: Request, res: Response, next: NextFunction) =>
76
101
  throw new ApiError(401, 'Invalid credentials');
77
102
  }
78
103
 
79
- const token = jwt.sign(
80
- { id: user.id, email: user.email },
81
- process.env.JWT_SECRET || 'secret',
82
- { expiresIn: process.env.JWT_EXPIRES_IN || '1d' }
83
- );
104
+ const { accessToken, refreshToken } = generateTokens(user);
105
+
106
+ // Update refresh token in DB
107
+ <% if (database === 'MongoDB') { %>
108
+ user.refresh_token = refreshToken;
109
+ await user.save();
110
+ <% } else { %>
111
+ await (User as any).update({ refresh_token: refreshToken }, { where: { id: user.id } });
112
+ <% } %>
84
113
 
85
114
  res.status(200).json({
86
115
  message: 'Login successful',
87
- token,
88
- user: { id: user.id, email: user.email, name: user.name }
116
+ accessToken,
117
+ refreshToken,
118
+ user: { id: user.id || user._id, email: user.email, name: user.name }
89
119
  });
90
120
  } catch (error: any) {
91
121
  next(error);
92
122
  }
93
123
  };
124
+
125
+ export const refreshToken = async (req: Request, res: Response, next: NextFunction) => {
126
+ try {
127
+ const { token } = req.body;
128
+ if (!token) {
129
+ throw new ApiError(400, 'Refresh token is required');
130
+ }
131
+
132
+ const decoded = jwt.verify(token, process.env.JWT_REFRESH_SECRET || 'refresh_secret') as any;
133
+ const user = await (User as any).findOne(<% if (database === 'MongoDB') { %>{ _id: decoded.id, refresh_token: token }<% } else { %>{ where: { id: decoded.id, refresh_token: token } }<% } %>);
134
+
135
+ if (!user) {
136
+ throw new ApiError(401, 'Invalid refresh token');
137
+ }
138
+
139
+ const tokens = generateTokens(user);
140
+
141
+ // Update refresh token in DB (Rotation)
142
+ <% if (database === 'MongoDB') { %>
143
+ user.refresh_token = tokens.refreshToken;
144
+ await user.save();
145
+ <% } else { %>
146
+ await (User as any).update({ refresh_token: tokens.refreshToken }, { where: { id: user.id } });
147
+ <% } %>
148
+
149
+ res.status(200).json({
150
+ message: 'Token refreshed successfully',
151
+ ...tokens
152
+ });
153
+ } catch (error: any) {
154
+ next(new ApiError(401, 'Invalid or expired refresh token'));
155
+ }
156
+ };
94
157
  <% } else if (auth === 'OAuth' || googleLogin === 'Google Login') { %>
95
158
  export const googleCallback = (req: Request, res: Response) => {
96
159
  res.status(200).json({
@@ -7,6 +7,9 @@ const router = express.Router();
7
7
  <% if (auth === 'Better-Auth' || auth === 'JWT') { %>
8
8
  router.post('/register', authController.register);
9
9
  router.post('/login', authController.login);
10
+ <% if (auth === 'JWT') { %>
11
+ router.post('/refresh-token', authController.refreshToken);
12
+ <% } %>
10
13
  <% } %>
11
14
 
12
15
  <% if (auth === 'OAuth' || googleLogin === 'Google Login') { %>
@@ -7,6 +7,9 @@ const router: Router = express.Router();
7
7
  <% if (auth === 'Better-Auth' || auth === 'JWT') { %>
8
8
  router.post('/register', authController.register);
9
9
  router.post('/login', authController.login);
10
+ <% if (auth === 'JWT') { %>
11
+ router.post('/refresh-token', authController.refreshToken);
12
+ <% } %>
10
13
  <% } %>
11
14
 
12
15
  <% if (auth === 'OAuth' || googleLogin === 'Google Login') { %>
@@ -1,5 +1,5 @@
1
1
  import express from 'express';
2
- import userController from '../controllers/userController.js';
2
+ import * as userController from '../controllers/userController.js';
3
3
  <% if (auth && auth !== 'None') { %>import { authMiddleware } from '../middleware/auth.js';<% } %>
4
4
  <% if (includeMulter) { %>import { upload } from '../middleware/upload.js';<% } %>
5
5
  <% if (auth && auth !== 'None') { %>import authRoutes from './authRoutes.js';<% } %>