stackkit 0.2.8 → 0.2.9

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.
Files changed (61) hide show
  1. package/README.md +4 -0
  2. package/dist/lib/fs/files.js +1 -1
  3. package/dist/lib/generation/code-generator.d.ts +2 -7
  4. package/dist/lib/generation/code-generator.js +120 -56
  5. package/dist/lib/utils/fs-helpers.d.ts +1 -1
  6. package/modules/auth/authjs/generator.json +16 -16
  7. package/modules/auth/better-auth/files/express/middlewares/authorize.ts +121 -41
  8. package/modules/auth/better-auth/files/express/modules/auth/auth.controller.ts +257 -0
  9. package/modules/auth/better-auth/files/express/modules/auth/auth.interface.ts +23 -0
  10. package/modules/auth/better-auth/files/express/modules/auth/auth.route.ts +22 -0
  11. package/modules/auth/better-auth/files/express/modules/auth/auth.service.ts +403 -0
  12. package/modules/auth/better-auth/files/express/templates/google-redirect.ejs +91 -0
  13. package/modules/auth/better-auth/files/express/templates/otp.ejs +87 -0
  14. package/modules/auth/better-auth/files/express/types/express.d.ts +6 -8
  15. package/modules/auth/better-auth/files/express/utils/cookie.ts +19 -0
  16. package/modules/auth/better-auth/files/express/utils/jwt.ts +34 -0
  17. package/modules/auth/better-auth/files/express/utils/token.ts +66 -0
  18. package/modules/auth/better-auth/files/nextjs/api/auth/[...all]/route.ts +1 -1
  19. package/modules/auth/better-auth/files/nextjs/lib/auth/auth-guards.ts +11 -1
  20. package/modules/auth/better-auth/files/nextjs/templates/email-otp.tsx +74 -0
  21. package/modules/auth/better-auth/files/shared/config/env.ts +113 -0
  22. package/modules/auth/better-auth/files/shared/lib/auth-client.ts +1 -1
  23. package/modules/auth/better-auth/files/shared/lib/auth.ts +151 -62
  24. package/modules/auth/better-auth/files/shared/prisma/schema.prisma +22 -11
  25. package/modules/auth/better-auth/files/shared/utils/email.ts +71 -0
  26. package/modules/auth/better-auth/generator.json +159 -81
  27. package/modules/database/mongoose/generator.json +18 -18
  28. package/modules/database/prisma/generator.json +44 -44
  29. package/package.json +1 -1
  30. package/templates/express/env.example +2 -2
  31. package/templates/express/eslint.config.mjs +7 -0
  32. package/templates/express/node_modules/.bin/acorn +17 -0
  33. package/templates/express/node_modules/.bin/eslint +17 -0
  34. package/templates/express/node_modules/.bin/tsc +17 -0
  35. package/templates/express/node_modules/.bin/tsserver +17 -0
  36. package/templates/express/node_modules/.bin/tsx +17 -0
  37. package/templates/express/package.json +12 -6
  38. package/templates/express/src/app.ts +15 -7
  39. package/templates/express/src/config/cors.ts +8 -7
  40. package/templates/express/src/config/env.ts +26 -5
  41. package/templates/express/src/config/logger.ts +2 -2
  42. package/templates/express/src/config/rate-limit.ts +2 -2
  43. package/templates/express/src/modules/health/health.controller.ts +13 -11
  44. package/templates/express/src/routes/index.ts +1 -6
  45. package/templates/express/src/server.ts +12 -12
  46. package/templates/express/src/shared/errors/app-error.ts +16 -0
  47. package/templates/express/src/shared/middlewares/error.middleware.ts +154 -12
  48. package/templates/express/src/shared/middlewares/not-found.middleware.ts +2 -1
  49. package/templates/express/src/shared/utils/catch-async.ts +11 -0
  50. package/templates/express/src/shared/utils/pagination.ts +6 -1
  51. package/templates/express/src/shared/utils/send-response.ts +25 -0
  52. package/templates/nextjs/lib/env.ts +19 -8
  53. package/modules/auth/better-auth/files/shared/lib/email/email-service.ts +0 -33
  54. package/modules/auth/better-auth/files/shared/lib/email/email-templates.ts +0 -89
  55. package/templates/express/eslint.config.cjs +0 -42
  56. package/templates/express/src/config/helmet.ts +0 -5
  57. package/templates/express/src/modules/health/health.service.ts +0 -6
  58. package/templates/express/src/shared/errors/error-codes.ts +0 -9
  59. package/templates/express/src/shared/logger/logger.ts +0 -20
  60. package/templates/express/src/shared/utils/async-handler.ts +0 -9
  61. package/templates/express/src/shared/utils/response.ts +0 -9
@@ -0,0 +1,257 @@
1
+ import { Request, Response } from "express";
2
+ import status from "http-status";
3
+ import { envVars } from "../../config/env";
4
+ import { auth } from "../../lib/auth";
5
+ import { AppError } from "../../shared/errors/app-error";
6
+ import { catchAsync } from "../../shared/utils/catch-async";
7
+ import { cookieUtils } from "../../shared/utils/cookie";
8
+ import { sendResponse } from "../../shared/utils/send-response";
9
+ import { tokenUtils } from "../../shared/utils/token";
10
+ import { authService } from "./auth.service";
11
+
12
+ const registerUser = catchAsync(async (req: Request, res: Response) => {
13
+ const payload = req.body;
14
+
15
+ const result = await authService.registerUser(payload);
16
+
17
+ const { accessToken, refreshToken, token, ...rest } = result;
18
+
19
+ tokenUtils.setAccessTokenCookie(res, accessToken);
20
+ tokenUtils.setRefreshTokenCookie(res, refreshToken);
21
+ tokenUtils.setBetterAuthSessionCookie(res, token as string);
22
+
23
+ sendResponse(res, {
24
+ status: status.CREATED,
25
+ success: true,
26
+ message: "User registered successfully",
27
+ data: {
28
+ token,
29
+ accessToken,
30
+ refreshToken,
31
+ ...rest,
32
+ },
33
+ });
34
+ });
35
+
36
+ const loginUser = catchAsync(
37
+ async (req: Request, res: Response) => {
38
+ const payload = req.body;
39
+ const result = await authService.loginUser(payload);
40
+ const { accessToken, refreshToken, token, ...rest } = result
41
+
42
+ tokenUtils.setAccessTokenCookie(res, accessToken);
43
+ tokenUtils.setRefreshTokenCookie(res, refreshToken);
44
+ tokenUtils.setBetterAuthSessionCookie(res, token);
45
+
46
+ sendResponse(res, {
47
+ status: status.OK,
48
+ success: true,
49
+ message: "User logged in successfully",
50
+ data: {
51
+ token,
52
+ accessToken,
53
+ refreshToken,
54
+ ...rest,
55
+ },
56
+ });
57
+ }
58
+ )
59
+
60
+ const getMe = catchAsync(
61
+ async (req: Request, res: Response) => {
62
+ const user = req.user;
63
+ const result = await authService.getMe(user);
64
+ sendResponse(res, {
65
+ status: status.OK,
66
+ success: true,
67
+ message: "User profile fetched successfully",
68
+ data: result,
69
+ });
70
+ }
71
+ )
72
+
73
+ const getNewToken = catchAsync(
74
+ async (req: Request, res: Response) => {
75
+ const refreshToken = req.cookies.refreshToken;
76
+ const betterAuthSessionToken = req.cookies["better-auth.session_token"];
77
+ if (!refreshToken) {
78
+ throw new AppError(status.UNAUTHORIZED, "Refresh token is missing");
79
+ }
80
+ const result = await authService.getNewToken(refreshToken, betterAuthSessionToken);
81
+
82
+ const { accessToken, refreshToken: newRefreshToken, sessionToken } = result;
83
+
84
+ tokenUtils.setAccessTokenCookie(res, accessToken);
85
+ tokenUtils.setRefreshTokenCookie(res, newRefreshToken);
86
+ tokenUtils.setBetterAuthSessionCookie(res, sessionToken);
87
+
88
+ sendResponse(res, {
89
+ status: status.OK,
90
+ success: true,
91
+ message: "New tokens generated successfully",
92
+ data: {
93
+ accessToken,
94
+ refreshToken: newRefreshToken,
95
+ sessionToken,
96
+ },
97
+ });
98
+ }
99
+ )
100
+
101
+ const changePassword = catchAsync(
102
+ async (req: Request, res: Response) => {
103
+ const payload = req.body;
104
+ const betterAuthSessionToken = req.cookies["better-auth.session_token"];
105
+
106
+ const result = await authService.changePassword(payload, betterAuthSessionToken);
107
+
108
+ const { accessToken, refreshToken, token } = result;
109
+
110
+ tokenUtils.setAccessTokenCookie(res, accessToken);
111
+ tokenUtils.setRefreshTokenCookie(res, refreshToken);
112
+ tokenUtils.setBetterAuthSessionCookie(res, token as string);
113
+
114
+ sendResponse(res, {
115
+ status: status.OK,
116
+ success: true,
117
+ message: "Password changed successfully",
118
+ data: result,
119
+ });
120
+ }
121
+ )
122
+
123
+ const logoutUser = catchAsync(
124
+ async (req: Request, res: Response) => {
125
+ const betterAuthSessionToken = req.cookies["better-auth.session_token"];
126
+ const result = await authService.logoutUser(betterAuthSessionToken);
127
+ cookieUtils.clearCookie(res, 'accessToken', {
128
+ httpOnly: true,
129
+ secure: true,
130
+ sameSite: "none",
131
+ });
132
+ cookieUtils.clearCookie(res, 'refreshToken', {
133
+ httpOnly: true,
134
+ secure: true,
135
+ sameSite: "none",
136
+ });
137
+ cookieUtils.clearCookie(res, 'better-auth.session_token', {
138
+ httpOnly: true,
139
+ secure: true,
140
+ sameSite: "none",
141
+ });
142
+
143
+ sendResponse(res, {
144
+ status: status.OK,
145
+ success: true,
146
+ message: "User logged out successfully",
147
+ data: result,
148
+ });
149
+ }
150
+ )
151
+
152
+ const verifyEmail = catchAsync(
153
+ async (req: Request, res: Response) => {
154
+ const { email, otp } = req.body;
155
+ await authService.verifyEmail(email, otp);
156
+
157
+ sendResponse(res, {
158
+ status: status.OK,
159
+ success: true,
160
+ message: "Email verified successfully",
161
+ });
162
+ }
163
+ )
164
+
165
+ const forgetPassword = catchAsync(
166
+ async (req: Request, res: Response) => {
167
+ const { email } = req.body;
168
+ await authService.forgetPassword(email);
169
+
170
+ sendResponse(res, {
171
+ status: status.OK,
172
+ success: true,
173
+ message: "Password reset OTP sent to email successfully",
174
+ });
175
+ }
176
+ )
177
+
178
+ const resetPassword = catchAsync(
179
+ async (req: Request, res: Response) => {
180
+ const { email, otp, newPassword } = req.body;
181
+ await authService.resetPassword(email, otp, newPassword);
182
+
183
+ sendResponse(res, {
184
+ status: status.OK,
185
+ success: true,
186
+ message: "Password reset successfully",
187
+ });
188
+ }
189
+ )
190
+
191
+ const googleLogin = catchAsync((req: Request, res: Response) => {
192
+ const redirectPath = req.query.redirect || "/dashboard";
193
+
194
+ const encodedRedirectPath = encodeURIComponent(redirectPath as string);
195
+
196
+ const callbackURL = `${envVars.BETTER_AUTH_URL}/api/v1/auth/google/success?redirect=${encodedRedirectPath}`;
197
+
198
+ res.render("googleRedirect", {
199
+ callbackURL : callbackURL,
200
+ betterAuthUrl : envVars.BETTER_AUTH_URL,
201
+ })
202
+ })
203
+
204
+ const googleLoginSuccess = catchAsync(async (req: Request, res: Response) => {
205
+ const redirectPath = req.query.redirect as string || "/dashboard";
206
+
207
+ const sessionToken = req.cookies["better-auth.session_token"];
208
+
209
+ if(!sessionToken){
210
+ return res.redirect(`${envVars.FRONTEND_URL}/login?error=oauth_failed`);
211
+ }
212
+
213
+ const session = await auth.api.getSession({
214
+ headers:{
215
+ "Cookie" : `better-auth.session_token=${sessionToken}`
216
+ }
217
+ })
218
+
219
+ if (!session) {
220
+ return res.redirect(`${envVars.FRONTEND_URL}/login?error=no_session_found`);
221
+ }
222
+
223
+ if(session && !session.user){
224
+ return res.redirect(`${envVars.FRONTEND_URL}/login?error=no_user_found`);
225
+ }
226
+
227
+ const result = await authService.googleLoginSuccess(session);
228
+
229
+ const {accessToken, refreshToken} = result;
230
+
231
+ tokenUtils.setAccessTokenCookie(res, accessToken);
232
+ tokenUtils.setRefreshTokenCookie(res, refreshToken);
233
+ const isValidRedirectPath = redirectPath.startsWith("/") && !redirectPath.startsWith("//");
234
+ const finalRedirectPath = isValidRedirectPath ? redirectPath : "/dashboard";
235
+
236
+ res.redirect(`${envVars.FRONTEND_URL}${finalRedirectPath}`);
237
+ })
238
+
239
+ const handleOAuthError = catchAsync((req: Request, res: Response) => {
240
+ const error = req.query.error as string || "oauth_failed";
241
+ res.redirect(`${envVars.FRONTEND_URL}/login?error=${error}`);
242
+ })
243
+
244
+ export const authController = {
245
+ registerUser,
246
+ loginUser,
247
+ getMe,
248
+ getNewToken,
249
+ changePassword,
250
+ logoutUser,
251
+ verifyEmail,
252
+ forgetPassword,
253
+ resetPassword,
254
+ googleLogin,
255
+ googleLoginSuccess,
256
+ handleOAuthError,
257
+ };
@@ -0,0 +1,23 @@
1
+ import { Role } from "@prisma/client";
2
+
3
+ export interface ILoginUserPayload {
4
+ email: string;
5
+ password: string;
6
+ }
7
+
8
+ export interface IRegisterUserPayload {
9
+ name: string;
10
+ email: string;
11
+ password: string;
12
+ }
13
+
14
+ export interface IChangePasswordPayload {
15
+ currentPassword: string;
16
+ newPassword: string;
17
+ }
18
+
19
+ export interface IRequestUser {
20
+ id: string;
21
+ role: Role | string;
22
+ email: string;
23
+ }
@@ -0,0 +1,22 @@
1
+ import { Role } from "@prisma/client";
2
+ import { Router } from "express";
3
+ import { authorize } from "../../shared/middlewares/authorize.middleware";
4
+ import { authController } from "./auth.controller";
5
+
6
+ const router = Router()
7
+
8
+ router.post("/register", authController.registerUser)
9
+ router.post("/login", authController.loginUser)
10
+ router.get("/me", authorize(Role.ADMIN, Role.USER, Role.SUPER_ADMIN), authController.getMe)
11
+ router.post("/refresh-token", authController.getNewToken)
12
+ router.post("/change-password", authorize(Role.ADMIN, Role.USER, Role.SUPER_ADMIN), authController.changePassword)
13
+ router.post("/logout", authorize(Role.ADMIN, Role.USER, Role.SUPER_ADMIN), authController.logoutUser)
14
+ router.post("/verify-email", authController.verifyEmail)
15
+ router.post("/forget-password", authController.forgetPassword)
16
+ router.post("/reset-password", authController.resetPassword)
17
+
18
+ router.get("/login/google", authController.googleLogin);
19
+ router.get("/google/success", authController.googleLoginSuccess);
20
+ router.get("/oauth/error", authController.handleOAuthError);
21
+
22
+ export const authRoutes = router;
@@ -0,0 +1,403 @@
1
+ import status from "http-status";
2
+ import { JwtPayload } from "jsonwebtoken";
3
+ import { envVars } from "../../config/env";
4
+ import { prisma } from "../../database/prisma";
5
+ import { auth } from "../../lib/auth";
6
+ import { AppError } from "../../shared/errors/app-error";
7
+ import { jwtUtils } from "../../shared/utils/jwt";
8
+ import { tokenUtils } from "../../shared/utils/token";
9
+ import {
10
+ IChangePasswordPayload,
11
+ ILoginUserPayload,
12
+ IRegisterUserPayload,
13
+ IRequestUser,
14
+ } from "./auth.interface";
15
+
16
+ const registerUser = async (payload: IRegisterUserPayload) => {
17
+ const { name, email, password } = payload;
18
+
19
+ const data = await auth.api.signUpEmail({
20
+ body: {
21
+ name,
22
+ email,
23
+ password,
24
+ },
25
+ });
26
+
27
+ if (!data.user) {
28
+ throw new AppError(status.BAD_REQUEST, "Failed to register user");
29
+ }
30
+
31
+ try {
32
+ const accessToken = tokenUtils.getAccessToken({
33
+ userId: data.user.id,
34
+ role: data.user.role,
35
+ name: data.user.name,
36
+ email: data.user.email,
37
+ status: data.user.status,
38
+ isDeleted: data.user.isDeleted,
39
+ emailVerified: data.user.emailVerified,
40
+ });
41
+
42
+ const refreshToken = tokenUtils.getRefreshToken({
43
+ userId: data.user.id,
44
+ role: data.user.role,
45
+ name: data.user.name,
46
+ email: data.user.email,
47
+ status: data.user.status,
48
+ isDeleted: data.user.isDeleted,
49
+ emailVerified: data.user.emailVerified,
50
+ });
51
+
52
+ return {
53
+ ...data,
54
+ accessToken,
55
+ refreshToken,
56
+ user: data.user,
57
+ };
58
+ } catch (error) {
59
+ await prisma.user.delete({
60
+ where: {
61
+ id: data.user.id,
62
+ },
63
+ });
64
+ throw error;
65
+ }
66
+
67
+ }
68
+
69
+ const loginUser = async (payload: ILoginUserPayload) => {
70
+ const { email, password } = payload;
71
+
72
+ const data = await auth.api.signInEmail({
73
+ body: {
74
+ email,
75
+ password,
76
+ }
77
+ })
78
+
79
+ if (data.user.status === "BLOCKED") {
80
+ throw new AppError(status.FORBIDDEN, "User is blocked");
81
+ }
82
+
83
+ if (data.user.isDeleted || data.user.status === "DELETED") {
84
+ throw new AppError(status.NOT_FOUND, "User is deleted");
85
+ }
86
+
87
+ const accessToken = tokenUtils.getAccessToken({
88
+ userId: data.user.id,
89
+ role: data.user.role,
90
+ name: data.user.name,
91
+ email: data.user.email,
92
+ status: data.user.status,
93
+ isDeleted: data.user.isDeleted,
94
+ emailVerified: data.user.emailVerified,
95
+ });
96
+
97
+ const refreshToken = tokenUtils.getRefreshToken({
98
+ userId: data.user.id,
99
+ role: data.user.role,
100
+ name: data.user.name,
101
+ email: data.user.email,
102
+ status: data.user.status,
103
+ isDeleted: data.user.isDeleted,
104
+ emailVerified: data.user.emailVerified,
105
+ });
106
+
107
+ return {
108
+ ...data,
109
+ accessToken,
110
+ refreshToken,
111
+ };
112
+ }
113
+
114
+ const getMe = async (user : IRequestUser) => {
115
+ const isUserExists = await prisma.user.findUnique({
116
+ where: {
117
+ id: user.id,
118
+ },
119
+ // Include other related models if needed
120
+ });
121
+
122
+ if (!isUserExists) {
123
+ throw new AppError(status.NOT_FOUND, "User not found");
124
+ }
125
+
126
+ return isUserExists;
127
+ }
128
+
129
+ const getNewToken = async (refreshToken : string, sessionToken : string) => {
130
+
131
+ const isSessionTokenExists = await prisma.session.findUnique({
132
+ where : {
133
+ token : sessionToken,
134
+ },
135
+ include : {
136
+ user : true,
137
+ }
138
+ })
139
+
140
+ if(!isSessionTokenExists){
141
+ throw new AppError(status.UNAUTHORIZED, "Invalid session token");
142
+ }
143
+
144
+ const verifiedRefreshToken = jwtUtils.verifyToken(refreshToken, envVars.REFRESH_TOKEN_SECRET)
145
+
146
+ if(!verifiedRefreshToken.success && verifiedRefreshToken.error){
147
+ throw new AppError(status.UNAUTHORIZED, "Invalid refresh token");
148
+ }
149
+
150
+ const data = verifiedRefreshToken.data as JwtPayload;
151
+
152
+ const newAccessToken = tokenUtils.getAccessToken({
153
+ userId: data.userId,
154
+ role: data.role,
155
+ name: data.name,
156
+ email: data.email,
157
+ status: data.status,
158
+ isDeleted: data.isDeleted,
159
+ emailVerified: data.emailVerified,
160
+ });
161
+
162
+ const newRefreshToken = tokenUtils.getRefreshToken({
163
+ userId: data.userId,
164
+ role: data.role,
165
+ name: data.name,
166
+ email: data.email,
167
+ status: data.status,
168
+ isDeleted: data.isDeleted,
169
+ emailVerified: data.emailVerified,
170
+ });
171
+
172
+ const {token} = await prisma.session.update({
173
+ where : {
174
+ token : sessionToken
175
+ },
176
+ data : {
177
+ token : sessionToken,
178
+ expiresAt: new Date(Date.now() + 60 * 60 * 60 * 24 * 1000),
179
+ updatedAt: new Date(),
180
+ }
181
+ })
182
+
183
+ return {
184
+ accessToken : newAccessToken,
185
+ refreshToken : newRefreshToken,
186
+ sessionToken : token,
187
+ }
188
+
189
+ }
190
+
191
+ const changePassword = async (payload : IChangePasswordPayload, sessionToken : string) =>{
192
+ const session = await auth.api.getSession({
193
+ headers : new Headers({
194
+ Authorization : `Bearer ${sessionToken}`
195
+ })
196
+ })
197
+
198
+ if(!session){
199
+ throw new AppError(status.UNAUTHORIZED, "Invalid session token");
200
+ }
201
+
202
+ const {currentPassword, newPassword} = payload;
203
+
204
+ const result = await auth.api.changePassword({
205
+ body :{
206
+ currentPassword,
207
+ newPassword,
208
+ revokeOtherSessions: true,
209
+ },
210
+ headers : new Headers({
211
+ Authorization : `Bearer ${sessionToken}`
212
+ })
213
+ })
214
+
215
+ if(session.user.needPasswordChange){
216
+ await prisma.user.update({
217
+ where: {
218
+ id: session.user.id,
219
+ },
220
+ data: {
221
+ needPasswordChange: false,
222
+ }
223
+ })
224
+ }
225
+
226
+ const accessToken = tokenUtils.getAccessToken({
227
+ userId: session.user.id,
228
+ role: session.user.role,
229
+ name: session.user.name,
230
+ email: session.user.email,
231
+ status: session.user.status,
232
+ isDeleted: session.user.isDeleted,
233
+ emailVerified: session.user.emailVerified,
234
+ });
235
+
236
+ const refreshToken = tokenUtils.getRefreshToken({
237
+ userId: session.user.id,
238
+ role: session.user.role,
239
+ name: session.user.name,
240
+ email: session.user.email,
241
+ status: session.user.status,
242
+ isDeleted: session.user.isDeleted,
243
+ emailVerified: session.user.emailVerified,
244
+ });
245
+
246
+
247
+ return {
248
+ ...result,
249
+ accessToken,
250
+ refreshToken,
251
+ }
252
+ }
253
+
254
+ const logoutUser = async (sessionToken : string) => {
255
+ const result = await auth.api.signOut({
256
+ headers : new Headers({
257
+ Authorization : `Bearer ${sessionToken}`
258
+ })
259
+ })
260
+
261
+ return result;
262
+ }
263
+
264
+ const verifyEmail = async (email : string, otp : string) => {
265
+
266
+ const result = await auth.api.verifyEmailOTP({
267
+ body:{
268
+ email,
269
+ otp,
270
+ }
271
+ })
272
+
273
+ if(result.status && !result.user.emailVerified){
274
+ await prisma.user.update({
275
+ where : {
276
+ email,
277
+ },
278
+ data : {
279
+ emailVerified: true,
280
+ }
281
+ })
282
+ }
283
+ }
284
+
285
+ const forgetPassword = async (email : string) => {
286
+ const isUserExist = await prisma.user.findUnique({
287
+ where : {
288
+ email,
289
+ }
290
+ })
291
+
292
+ if(!isUserExist){
293
+ throw new AppError(status.NOT_FOUND, "User not found");
294
+ }
295
+
296
+ if(!isUserExist.emailVerified){
297
+ throw new AppError(status.BAD_REQUEST, "Email not verified");
298
+ }
299
+
300
+ if (isUserExist.isDeleted || isUserExist.status === "DELETED") {
301
+ throw new AppError(status.NOT_FOUND, "User not found");
302
+ }
303
+
304
+ await auth.api.requestPasswordResetEmailOTP({
305
+ body:{
306
+ email,
307
+ }
308
+ })
309
+ }
310
+
311
+ const resetPassword = async (email : string, otp : string, newPassword : string) => {
312
+ const isUserExist = await prisma.user.findUnique({
313
+ where: {
314
+ email,
315
+ }
316
+ })
317
+
318
+ if (!isUserExist) {
319
+ throw new AppError(status.NOT_FOUND, "User not found");
320
+ }
321
+
322
+ if (!isUserExist.emailVerified) {
323
+ throw new AppError(status.BAD_REQUEST, "Email not verified");
324
+ }
325
+
326
+ if (isUserExist.isDeleted || isUserExist.status === "DELETED") {
327
+ throw new AppError(status.NOT_FOUND, "User not found");
328
+ }
329
+
330
+ await auth.api.resetPasswordEmailOTP({
331
+ body:{
332
+ email,
333
+ otp,
334
+ password : newPassword,
335
+ }
336
+ })
337
+
338
+ if (isUserExist.needPasswordChange) {
339
+ await prisma.user.update({
340
+ where: {
341
+ id: isUserExist.id,
342
+ },
343
+ data: {
344
+ needPasswordChange: false,
345
+ }
346
+ })
347
+ }
348
+
349
+ await prisma.session.deleteMany({
350
+ where:{
351
+ userId : isUserExist.id,
352
+ }
353
+ })
354
+ }
355
+
356
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
357
+ const googleLoginSuccess = async (session : Record<string, any>) =>{
358
+ const isCustomerExists = await prisma.user.findUnique({
359
+ where: {
360
+ id: session.user.id,
361
+ },
362
+ });
363
+
364
+ if (!isCustomerExists) {
365
+ await prisma.user.create({
366
+ data: {
367
+ id: session.user.id,
368
+ name: session.user.name,
369
+ email: session.user.email,
370
+ },
371
+ });
372
+ }
373
+
374
+ const accessToken = tokenUtils.getAccessToken({
375
+ userId: session.user.id,
376
+ role: session.user.role,
377
+ name: session.user.name,
378
+ });
379
+
380
+ const refreshToken = tokenUtils.getRefreshToken({
381
+ userId: session.user.id,
382
+ role: session.user.role,
383
+ name: session.user.name,
384
+ });
385
+
386
+ return {
387
+ accessToken,
388
+ refreshToken,
389
+ }
390
+ }
391
+
392
+ export const authService = {
393
+ registerUser: registerUser,
394
+ loginUser,
395
+ getMe,
396
+ getNewToken,
397
+ changePassword,
398
+ logoutUser,
399
+ verifyEmail,
400
+ forgetPassword,
401
+ resetPassword,
402
+ googleLoginSuccess,
403
+ };