create-charcole 2.2.0 → 2.2.2
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/.github/workflows/release.yml +26 -26
- package/CHANGELOG.md +301 -301
- package/LICENSE +21 -21
- package/README.md +357 -354
- package/bin/index.js +494 -444
- package/bin/lib/pkgManager.js +49 -49
- package/bin/lib/templateHandler.js +33 -33
- package/package.json +42 -27
- package/packages/swagger/BACKWARD_COMPATIBILITY.md +1 -1
- package/packages/swagger/CHANGELOG.md +1 -1
- package/packages/swagger/README.md +3 -3
- package/packages/swagger/package.json +57 -44
- package/packages/swagger/src/index.d.ts +126 -126
- package/packages/swagger/src/index.js +12 -12
- package/packages/swagger/src/setup.js +100 -100
- package/template/js/.env.example +16 -15
- package/template/js/README.md +982 -978
- package/template/js/basePackage.json +26 -26
- package/template/js/src/app.js +81 -81
- package/template/js/src/config/constants.js +20 -20
- package/template/js/src/config/env.js +26 -26
- package/template/js/src/config/swagger.config.js +15 -15
- package/template/js/src/lib/swagger/SWAGGER_GUIDE.md +3 -3
- package/template/js/src/middlewares/errorHandler.js +180 -180
- package/template/js/src/middlewares/requestLogger.js +33 -33
- package/template/js/src/middlewares/validateRequest.js +42 -42
- package/template/js/src/modules/auth/auth.constants.js +3 -3
- package/template/js/src/modules/auth/auth.controller.js +29 -29
- package/template/js/src/modules/auth/auth.middlewares.js +19 -19
- package/template/js/src/modules/auth/auth.routes.js +131 -131
- package/template/js/src/modules/auth/auth.schemas.js +60 -60
- package/template/js/src/modules/auth/auth.service.js +67 -67
- package/template/js/src/modules/auth/package.json +6 -6
- package/template/js/src/modules/health/controller.js +151 -151
- package/template/js/src/modules/swagger/package.json +5 -5
- package/template/js/src/repositories/user.repo.js +19 -19
- package/template/js/src/routes/index.js +25 -25
- package/template/js/src/routes/protected.js +57 -57
- package/template/js/src/server.js +38 -38
- package/template/js/src/utils/AppError.js +182 -182
- package/template/js/src/utils/logger.js +73 -73
- package/template/js/src/utils/response.js +51 -51
- package/template/ts/.env.example +16 -15
- package/template/ts/README.md +982 -978
- package/template/ts/basePackage.json +36 -36
- package/template/ts/build.js +46 -46
- package/template/ts/src/app.ts +71 -71
- package/template/ts/src/config/constants.ts +27 -27
- package/template/ts/src/config/env.ts +40 -40
- package/template/ts/src/config/swagger.config.ts +30 -30
- package/template/ts/src/lib/swagger/SWAGGER_GUIDE.md +2 -2
- package/template/ts/src/middlewares/errorHandler.ts +201 -201
- package/template/ts/src/middlewares/requestLogger.ts +38 -38
- package/template/ts/src/middlewares/validateRequest.ts +46 -46
- package/template/ts/src/modules/auth/auth.constants.ts +6 -6
- package/template/ts/src/modules/auth/auth.controller.ts +32 -32
- package/template/ts/src/modules/auth/auth.middlewares.ts +46 -46
- package/template/ts/src/modules/auth/auth.routes.ts +52 -52
- package/template/ts/src/modules/auth/auth.schemas.ts +73 -73
- package/template/ts/src/modules/auth/auth.service.ts +106 -106
- package/template/ts/src/modules/auth/package.json +10 -10
- package/template/ts/src/modules/health/controller.ts +80 -80
- package/template/ts/src/modules/swagger/package.json +5 -5
- package/template/ts/src/repositories/user.repo.ts +33 -33
- package/template/ts/src/routes/index.ts +24 -24
- package/template/ts/src/routes/protected.ts +46 -46
- package/template/ts/src/server.ts +41 -41
- package/template/ts/src/types/express.d.ts +9 -9
- package/template/ts/src/utils/AppError.ts +220 -220
- package/template/ts/src/utils/logger.ts +55 -55
- package/template/ts/src/utils/response.ts +100 -100
- package/template/ts/tsconfig.json +26 -26
- package/packages/swagger/package-lock.json +0 -1715
- package/tmpclaude-1049-cwd +0 -1
- package/tmpclaude-3e37-cwd +0 -1
- package/tmpclaude-4d73-cwd +0 -1
- package/tmpclaude-8a8e-cwd +0 -1
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
import { Router } from "express";
|
|
2
|
-
import { AuthController } from "./auth.controller.js";
|
|
3
|
-
|
|
4
|
-
const router = Router();
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @swagger
|
|
8
|
-
* /api/auth/register:
|
|
9
|
-
* post:
|
|
10
|
-
* summary: Register a new user
|
|
11
|
-
* description: Create a new user account with email and password
|
|
12
|
-
* tags:
|
|
13
|
-
* - Authentication
|
|
14
|
-
* requestBody:
|
|
15
|
-
* required: true
|
|
16
|
-
* content:
|
|
17
|
-
* application/json:
|
|
18
|
-
* schema:
|
|
19
|
-
* type: object
|
|
20
|
-
* required:
|
|
21
|
-
* - email
|
|
22
|
-
* - password
|
|
23
|
-
* - name
|
|
24
|
-
* properties:
|
|
25
|
-
* email:
|
|
26
|
-
* type: string
|
|
27
|
-
* format: email
|
|
28
|
-
* example: user@example.com
|
|
29
|
-
* password:
|
|
30
|
-
* type: string
|
|
31
|
-
* format: password
|
|
32
|
-
* minLength: 8
|
|
33
|
-
* example: SecurePassword123
|
|
34
|
-
* name:
|
|
35
|
-
* type: string
|
|
36
|
-
* example: John Doe
|
|
37
|
-
* responses:
|
|
38
|
-
* 201:
|
|
39
|
-
* description: User registered successfully
|
|
40
|
-
* content:
|
|
41
|
-
* application/json:
|
|
42
|
-
* schema:
|
|
43
|
-
* type: object
|
|
44
|
-
* properties:
|
|
45
|
-
* success:
|
|
46
|
-
* type: boolean
|
|
47
|
-
* example: true
|
|
48
|
-
* message:
|
|
49
|
-
* type: string
|
|
50
|
-
* example: User registered successfully
|
|
51
|
-
* data:
|
|
52
|
-
* type: object
|
|
53
|
-
* properties:
|
|
54
|
-
* id:
|
|
55
|
-
* type: string
|
|
56
|
-
* example: user_123abc
|
|
57
|
-
* email:
|
|
58
|
-
* type: string
|
|
59
|
-
* example: user@example.com
|
|
60
|
-
* token:
|
|
61
|
-
* type: string
|
|
62
|
-
* example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
63
|
-
* 400:
|
|
64
|
-
* description: Validation error or user already exists
|
|
65
|
-
* 500:
|
|
66
|
-
* description: Internal server error
|
|
67
|
-
*/
|
|
68
|
-
router.post("/register", AuthController.register);
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @swagger
|
|
72
|
-
* /api/auth/login:
|
|
73
|
-
* post:
|
|
74
|
-
* summary: Login user
|
|
75
|
-
* description: Authenticate user with email and password
|
|
76
|
-
* tags:
|
|
77
|
-
* - Authentication
|
|
78
|
-
* requestBody:
|
|
79
|
-
* required: true
|
|
80
|
-
* content:
|
|
81
|
-
* application/json:
|
|
82
|
-
* schema:
|
|
83
|
-
* type: object
|
|
84
|
-
* required:
|
|
85
|
-
* - email
|
|
86
|
-
* - password
|
|
87
|
-
* properties:
|
|
88
|
-
* email:
|
|
89
|
-
* type: string
|
|
90
|
-
* format: email
|
|
91
|
-
* example: user@example.com
|
|
92
|
-
* password:
|
|
93
|
-
* type: string
|
|
94
|
-
* format: password
|
|
95
|
-
* example: SecurePassword123
|
|
96
|
-
* responses:
|
|
97
|
-
* 200:
|
|
98
|
-
* description: Login successful
|
|
99
|
-
* content:
|
|
100
|
-
* application/json:
|
|
101
|
-
* schema:
|
|
102
|
-
* type: object
|
|
103
|
-
* properties:
|
|
104
|
-
* success:
|
|
105
|
-
* type: boolean
|
|
106
|
-
* example: true
|
|
107
|
-
* message:
|
|
108
|
-
* type: string
|
|
109
|
-
* example: Login successful
|
|
110
|
-
* data:
|
|
111
|
-
* type: object
|
|
112
|
-
* properties:
|
|
113
|
-
* id:
|
|
114
|
-
* type: string
|
|
115
|
-
* example: user_123abc
|
|
116
|
-
* email:
|
|
117
|
-
* type: string
|
|
118
|
-
* example: user@example.com
|
|
119
|
-
* token:
|
|
120
|
-
* type: string
|
|
121
|
-
* example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
122
|
-
* 401:
|
|
123
|
-
* description: Invalid credentials
|
|
124
|
-
* 400:
|
|
125
|
-
* description: Validation error
|
|
126
|
-
* 500:
|
|
127
|
-
* description: Internal server error
|
|
128
|
-
*/
|
|
129
|
-
router.post("/login", AuthController.login);
|
|
130
|
-
|
|
131
|
-
export default router;
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { AuthController } from "./auth.controller.js";
|
|
3
|
+
|
|
4
|
+
const router = Router();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @swagger
|
|
8
|
+
* /api/auth/register:
|
|
9
|
+
* post:
|
|
10
|
+
* summary: Register a new user
|
|
11
|
+
* description: Create a new user account with email and password
|
|
12
|
+
* tags:
|
|
13
|
+
* - Authentication
|
|
14
|
+
* requestBody:
|
|
15
|
+
* required: true
|
|
16
|
+
* content:
|
|
17
|
+
* application/json:
|
|
18
|
+
* schema:
|
|
19
|
+
* type: object
|
|
20
|
+
* required:
|
|
21
|
+
* - email
|
|
22
|
+
* - password
|
|
23
|
+
* - name
|
|
24
|
+
* properties:
|
|
25
|
+
* email:
|
|
26
|
+
* type: string
|
|
27
|
+
* format: email
|
|
28
|
+
* example: user@example.com
|
|
29
|
+
* password:
|
|
30
|
+
* type: string
|
|
31
|
+
* format: password
|
|
32
|
+
* minLength: 8
|
|
33
|
+
* example: SecurePassword123
|
|
34
|
+
* name:
|
|
35
|
+
* type: string
|
|
36
|
+
* example: John Doe
|
|
37
|
+
* responses:
|
|
38
|
+
* 201:
|
|
39
|
+
* description: User registered successfully
|
|
40
|
+
* content:
|
|
41
|
+
* application/json:
|
|
42
|
+
* schema:
|
|
43
|
+
* type: object
|
|
44
|
+
* properties:
|
|
45
|
+
* success:
|
|
46
|
+
* type: boolean
|
|
47
|
+
* example: true
|
|
48
|
+
* message:
|
|
49
|
+
* type: string
|
|
50
|
+
* example: User registered successfully
|
|
51
|
+
* data:
|
|
52
|
+
* type: object
|
|
53
|
+
* properties:
|
|
54
|
+
* id:
|
|
55
|
+
* type: string
|
|
56
|
+
* example: user_123abc
|
|
57
|
+
* email:
|
|
58
|
+
* type: string
|
|
59
|
+
* example: user@example.com
|
|
60
|
+
* token:
|
|
61
|
+
* type: string
|
|
62
|
+
* example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
63
|
+
* 400:
|
|
64
|
+
* description: Validation error or user already exists
|
|
65
|
+
* 500:
|
|
66
|
+
* description: Internal server error
|
|
67
|
+
*/
|
|
68
|
+
router.post("/register", AuthController.register);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @swagger
|
|
72
|
+
* /api/auth/login:
|
|
73
|
+
* post:
|
|
74
|
+
* summary: Login user
|
|
75
|
+
* description: Authenticate user with email and password
|
|
76
|
+
* tags:
|
|
77
|
+
* - Authentication
|
|
78
|
+
* requestBody:
|
|
79
|
+
* required: true
|
|
80
|
+
* content:
|
|
81
|
+
* application/json:
|
|
82
|
+
* schema:
|
|
83
|
+
* type: object
|
|
84
|
+
* required:
|
|
85
|
+
* - email
|
|
86
|
+
* - password
|
|
87
|
+
* properties:
|
|
88
|
+
* email:
|
|
89
|
+
* type: string
|
|
90
|
+
* format: email
|
|
91
|
+
* example: user@example.com
|
|
92
|
+
* password:
|
|
93
|
+
* type: string
|
|
94
|
+
* format: password
|
|
95
|
+
* example: SecurePassword123
|
|
96
|
+
* responses:
|
|
97
|
+
* 200:
|
|
98
|
+
* description: Login successful
|
|
99
|
+
* content:
|
|
100
|
+
* application/json:
|
|
101
|
+
* schema:
|
|
102
|
+
* type: object
|
|
103
|
+
* properties:
|
|
104
|
+
* success:
|
|
105
|
+
* type: boolean
|
|
106
|
+
* example: true
|
|
107
|
+
* message:
|
|
108
|
+
* type: string
|
|
109
|
+
* example: Login successful
|
|
110
|
+
* data:
|
|
111
|
+
* type: object
|
|
112
|
+
* properties:
|
|
113
|
+
* id:
|
|
114
|
+
* type: string
|
|
115
|
+
* example: user_123abc
|
|
116
|
+
* email:
|
|
117
|
+
* type: string
|
|
118
|
+
* example: user@example.com
|
|
119
|
+
* token:
|
|
120
|
+
* type: string
|
|
121
|
+
* example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
122
|
+
* 401:
|
|
123
|
+
* description: Invalid credentials
|
|
124
|
+
* 400:
|
|
125
|
+
* description: Validation error
|
|
126
|
+
* 500:
|
|
127
|
+
* description: Internal server error
|
|
128
|
+
*/
|
|
129
|
+
router.post("/login", AuthController.login);
|
|
130
|
+
|
|
131
|
+
export default router;
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { USER_ROLES, AUTH_PROVIDERS } from "./auth.constants.js";
|
|
3
|
-
|
|
4
|
-
export const emailSchema = z
|
|
5
|
-
.string()
|
|
6
|
-
.email("Invalid email address")
|
|
7
|
-
.toLowerCase();
|
|
8
|
-
|
|
9
|
-
export const passwordSchema = z
|
|
10
|
-
.string()
|
|
11
|
-
.min(8, "Password must be at least 8 characters")
|
|
12
|
-
.max(72, "Password too long");
|
|
13
|
-
|
|
14
|
-
export const userSchema = z.object({
|
|
15
|
-
id: z.string().uuid(),
|
|
16
|
-
email: emailSchema,
|
|
17
|
-
name: z.string().min(1).max(100),
|
|
18
|
-
role: z.enum(USER_ROLES).default("user"),
|
|
19
|
-
provider: z.enum(AUTH_PROVIDERS).default("credentials"),
|
|
20
|
-
|
|
21
|
-
passwordHash: z.string().optional(), // credentials only
|
|
22
|
-
isEmailVerified: z.boolean().default(false),
|
|
23
|
-
|
|
24
|
-
createdAt: z.date(),
|
|
25
|
-
updatedAt: z.date(),
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
export const registerSchema = z.object({
|
|
29
|
-
name: z.string().min(1, "Name is required"),
|
|
30
|
-
email: emailSchema,
|
|
31
|
-
password: passwordSchema,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
export const loginSchema = z.object({
|
|
35
|
-
email: emailSchema,
|
|
36
|
-
password: z.string().min(1, "Password is required"),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
export const jwtPayloadSchema = z.object({
|
|
40
|
-
sub: z.string().uuid(), // user id
|
|
41
|
-
email: emailSchema,
|
|
42
|
-
role: z.enum(USER_ROLES),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
export const forgotPasswordSchema = z.object({
|
|
46
|
-
email: emailSchema,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
export const resetPasswordSchema = z.object({
|
|
50
|
-
token: z.string().min(1),
|
|
51
|
-
newPassword: passwordSchema,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
export const publicUserSchema = userSchema.omit({
|
|
55
|
-
passwordHash: true,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
export const validate = (schema, data) => {
|
|
59
|
-
return schema.parse(data);
|
|
60
|
-
};
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { USER_ROLES, AUTH_PROVIDERS } from "./auth.constants.js";
|
|
3
|
+
|
|
4
|
+
export const emailSchema = z
|
|
5
|
+
.string()
|
|
6
|
+
.email("Invalid email address")
|
|
7
|
+
.toLowerCase();
|
|
8
|
+
|
|
9
|
+
export const passwordSchema = z
|
|
10
|
+
.string()
|
|
11
|
+
.min(8, "Password must be at least 8 characters")
|
|
12
|
+
.max(72, "Password too long");
|
|
13
|
+
|
|
14
|
+
export const userSchema = z.object({
|
|
15
|
+
id: z.string().uuid(),
|
|
16
|
+
email: emailSchema,
|
|
17
|
+
name: z.string().min(1).max(100),
|
|
18
|
+
role: z.enum(USER_ROLES).default("user"),
|
|
19
|
+
provider: z.enum(AUTH_PROVIDERS).default("credentials"),
|
|
20
|
+
|
|
21
|
+
passwordHash: z.string().optional(), // credentials only
|
|
22
|
+
isEmailVerified: z.boolean().default(false),
|
|
23
|
+
|
|
24
|
+
createdAt: z.date(),
|
|
25
|
+
updatedAt: z.date(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const registerSchema = z.object({
|
|
29
|
+
name: z.string().min(1, "Name is required"),
|
|
30
|
+
email: emailSchema,
|
|
31
|
+
password: passwordSchema,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const loginSchema = z.object({
|
|
35
|
+
email: emailSchema,
|
|
36
|
+
password: z.string().min(1, "Password is required"),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const jwtPayloadSchema = z.object({
|
|
40
|
+
sub: z.string().uuid(), // user id
|
|
41
|
+
email: emailSchema,
|
|
42
|
+
role: z.enum(USER_ROLES),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const forgotPasswordSchema = z.object({
|
|
46
|
+
email: emailSchema,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export const resetPasswordSchema = z.object({
|
|
50
|
+
token: z.string().min(1),
|
|
51
|
+
newPassword: passwordSchema,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const publicUserSchema = userSchema.omit({
|
|
55
|
+
passwordHash: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const validate = (schema, data) => {
|
|
59
|
+
return schema.parse(data);
|
|
60
|
+
};
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
import bcrypt from "bcryptjs";
|
|
2
|
-
import jwt from "jsonwebtoken";
|
|
3
|
-
import { registerSchema, loginSchema } from "./auth.schemas.js";
|
|
4
|
-
|
|
5
|
-
const SALT_ROUNDS = 10;
|
|
6
|
-
const JWT_EXPIRES_IN = "7d";
|
|
7
|
-
|
|
8
|
-
export const AuthService = {
|
|
9
|
-
async hashPassword(password) {
|
|
10
|
-
return bcrypt.hash(password, SALT_ROUNDS);
|
|
11
|
-
},
|
|
12
|
-
|
|
13
|
-
async comparePassword(password, hash) {
|
|
14
|
-
return bcrypt.compare(password, hash);
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
signToken(payload) {
|
|
18
|
-
return jwt.sign(payload, process.env.JWT_SECRET, {
|
|
19
|
-
expiresIn: JWT_EXPIRES_IN,
|
|
20
|
-
});
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
async register(data, userRepo) {
|
|
24
|
-
const input = registerSchema.parse(data);
|
|
25
|
-
|
|
26
|
-
const existingUser = await userRepo.findByEmail(input.email);
|
|
27
|
-
if (existingUser) {
|
|
28
|
-
throw new Error("Email already in use");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const passwordHash = await this.hashPassword(input.password);
|
|
32
|
-
|
|
33
|
-
const user = await userRepo.create({
|
|
34
|
-
email: input.email,
|
|
35
|
-
name: input.name,
|
|
36
|
-
passwordHash,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
return user;
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
async login(data, userRepo) {
|
|
43
|
-
const input = loginSchema.parse(data);
|
|
44
|
-
|
|
45
|
-
const user = await userRepo.findByEmail(input.email);
|
|
46
|
-
if (!user || !user.passwordHash) {
|
|
47
|
-
throw new Error("Invalid credentials");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const isValid = await this.comparePassword(
|
|
51
|
-
input.password,
|
|
52
|
-
user.passwordHash,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
if (!isValid) {
|
|
56
|
-
throw new Error("Invalid credentials");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const token = this.signToken({
|
|
60
|
-
sub: user.id,
|
|
61
|
-
email: user.email,
|
|
62
|
-
role: user.role,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return { user, token };
|
|
66
|
-
},
|
|
67
|
-
};
|
|
1
|
+
import bcrypt from "bcryptjs";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
import { registerSchema, loginSchema } from "./auth.schemas.js";
|
|
4
|
+
|
|
5
|
+
const SALT_ROUNDS = 10;
|
|
6
|
+
const JWT_EXPIRES_IN = "7d";
|
|
7
|
+
|
|
8
|
+
export const AuthService = {
|
|
9
|
+
async hashPassword(password) {
|
|
10
|
+
return bcrypt.hash(password, SALT_ROUNDS);
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
async comparePassword(password, hash) {
|
|
14
|
+
return bcrypt.compare(password, hash);
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
signToken(payload) {
|
|
18
|
+
return jwt.sign(payload, process.env.JWT_SECRET, {
|
|
19
|
+
expiresIn: JWT_EXPIRES_IN,
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
async register(data, userRepo) {
|
|
24
|
+
const input = registerSchema.parse(data);
|
|
25
|
+
|
|
26
|
+
const existingUser = await userRepo.findByEmail(input.email);
|
|
27
|
+
if (existingUser) {
|
|
28
|
+
throw new Error("Email already in use");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const passwordHash = await this.hashPassword(input.password);
|
|
32
|
+
|
|
33
|
+
const user = await userRepo.create({
|
|
34
|
+
email: input.email,
|
|
35
|
+
name: input.name,
|
|
36
|
+
passwordHash,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return user;
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
async login(data, userRepo) {
|
|
43
|
+
const input = loginSchema.parse(data);
|
|
44
|
+
|
|
45
|
+
const user = await userRepo.findByEmail(input.email);
|
|
46
|
+
if (!user || !user.passwordHash) {
|
|
47
|
+
throw new Error("Invalid credentials");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const isValid = await this.comparePassword(
|
|
51
|
+
input.password,
|
|
52
|
+
user.passwordHash,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (!isValid) {
|
|
56
|
+
throw new Error("Invalid credentials");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const token = this.signToken({
|
|
60
|
+
sub: user.id,
|
|
61
|
+
email: user.email,
|
|
62
|
+
role: user.role,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return { user, token };
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"dependencies": {
|
|
3
|
-
"bcryptjs": "^3.0.3",
|
|
4
|
-
"jsonwebtoken": "^9.0.3"
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"bcryptjs": "^3.0.3",
|
|
4
|
+
"jsonwebtoken": "^9.0.3"
|
|
5
|
+
}
|
|
6
|
+
}
|