@imksh/create 1.0.31 → 1.0.33

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 (158) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/src/commands/create.js +2 -0
  4. package/src/index.js +1 -1
  5. package/templates/layers/next/javascript/package.json +8 -2
  6. package/templates/layers/next/typescript/.eslintrc.json +12 -0
  7. package/templates/layers/next/typescript/package.json +14 -3
  8. package/templates/layers/next/typescript/src/components/common/Loading.tsx +1 -1
  9. package/templates/layers/next/typescript/src/components/common/LottieIcon.tsx +2 -2
  10. package/templates/layers/next/typescript/src/components/common/Table.tsx +4 -4
  11. package/templates/layers/next/typescript/src/components/modals/ConfirmModal.tsx +2 -1
  12. package/templates/layers/next/typescript/src/components/ui/Header.tsx +2 -2
  13. package/templates/layers/next/typescript/src/hooks/usePwaInstall.ts +10 -4
  14. package/templates/layers/next/typescript/src/services/authService.ts +1 -1
  15. package/templates/layers/next/typescript/src/store/useAuthStore.ts +24 -9
  16. package/templates/layers/node/javascript/.env.example +3 -1
  17. package/templates/layers/node/javascript/package.json +12 -3
  18. package/templates/layers/node/javascript/src/app.js +2 -1
  19. package/templates/layers/node/javascript/src/controllers/auth.controller.js +106 -168
  20. package/templates/layers/node/javascript/src/controllers/push.controller.js +51 -58
  21. package/templates/layers/node/javascript/src/controllers/upload.controller.js +12 -19
  22. package/templates/layers/node/javascript/src/middleware/auth.middleware.js +5 -11
  23. package/templates/layers/node/javascript/src/middleware/errorHandler.js +6 -4
  24. package/templates/layers/node/javascript/src/routes/auth.route.js +2 -0
  25. package/templates/layers/node/javascript/src/services/auth.service.js +159 -164
  26. package/templates/layers/node/javascript/src/utils/ApiError.js +20 -0
  27. package/templates/layers/node/javascript/src/utils/SuccessResponse.js +15 -0
  28. package/templates/layers/node/javascript/src/utils/apiResponse.js +4 -0
  29. package/templates/layers/node/javascript/src/utils/asyncHandler.js +5 -0
  30. package/templates/layers/node/typescript/.env.example +3 -1
  31. package/templates/layers/node/typescript/.eslintrc.cjs +28 -0
  32. package/templates/layers/node/typescript/package.json +16 -2
  33. package/templates/layers/node/typescript/src/app.ts +3 -2
  34. package/templates/layers/node/typescript/src/config/db.ts +3 -2
  35. package/templates/layers/node/typescript/src/config/socket.ts +5 -4
  36. package/templates/layers/node/typescript/src/controllers/auth.controller.ts +104 -132
  37. package/templates/layers/node/typescript/src/controllers/push.controller.ts +52 -59
  38. package/templates/layers/node/typescript/src/controllers/upload.controller.ts +12 -19
  39. package/templates/layers/node/typescript/src/middleware/auth.middleware.ts +13 -7
  40. package/templates/layers/node/typescript/src/middleware/errorHandler.ts +18 -5
  41. package/templates/layers/node/typescript/src/middleware/rateLimiter.ts +2 -2
  42. package/templates/layers/node/typescript/src/routes/auth.route.ts +2 -0
  43. package/templates/layers/node/typescript/src/services/auth.service.ts +86 -43
  44. package/templates/layers/node/typescript/src/types/express.d.ts +5 -3
  45. package/templates/layers/node/typescript/src/utils/ApiError.ts +25 -0
  46. package/templates/layers/node/typescript/src/utils/SuccessResponse.ts +17 -0
  47. package/templates/layers/node/typescript/src/utils/apiResponse.ts +4 -0
  48. package/templates/layers/node/typescript/src/utils/asyncHandler.ts +13 -0
  49. package/templates/layers/node/typescript/src/utils/cloudinaryUpload.ts +18 -7
  50. package/templates/layers/node/typescript/src/utils/expoNotification.ts +1 -1
  51. package/templates/layers/node/typescript/src/utils/genOtpToken.ts +7 -1
  52. package/templates/layers/node/typescript/src/utils/jwt.ts +8 -2
  53. package/templates/layers/node/typescript/src/utils/logger.ts +2 -1
  54. package/templates/layers/node/typescript/src/utils/pushHelper.ts +13 -9
  55. package/templates/layers/node-prisma/javascript/.env.example +3 -1
  56. package/templates/layers/node-prisma/javascript/package.json +11 -2
  57. package/templates/layers/node-prisma/javascript/src/app.js +2 -1
  58. package/templates/layers/node-prisma/javascript/src/controllers/auth.controller.js +90 -135
  59. package/templates/layers/node-prisma/javascript/src/controllers/push.controller.js +64 -76
  60. package/templates/layers/node-prisma/javascript/src/controllers/upload.controller.js +12 -19
  61. package/templates/layers/node-prisma/javascript/src/middleware/auth.middleware.js +5 -4
  62. package/templates/layers/node-prisma/javascript/src/middleware/errorHandler.js +6 -4
  63. package/templates/layers/node-prisma/javascript/src/routes/auth.route.js +2 -0
  64. package/templates/layers/node-prisma/javascript/src/services/auth.service.js +145 -122
  65. package/templates/layers/node-prisma/javascript/src/utils/ApiError.js +20 -0
  66. package/templates/layers/node-prisma/javascript/src/utils/SuccessResponse.js +15 -0
  67. package/templates/layers/node-prisma/javascript/src/utils/apiResponse.js +4 -0
  68. package/templates/layers/node-prisma/javascript/src/utils/asyncHandler.js +5 -0
  69. package/templates/layers/node-prisma/typescript/.env.example +3 -1
  70. package/templates/layers/node-prisma/typescript/.eslintrc.cjs +28 -0
  71. package/templates/layers/node-prisma/typescript/package.json +19 -5
  72. package/templates/layers/node-prisma/typescript/src/app.ts +3 -2
  73. package/templates/layers/node-prisma/typescript/src/config/prisma.ts +3 -2
  74. package/templates/layers/node-prisma/typescript/src/config/socket.ts +5 -4
  75. package/templates/layers/node-prisma/typescript/src/controllers/auth.controller.ts +89 -105
  76. package/templates/layers/node-prisma/typescript/src/controllers/push.controller.ts +67 -83
  77. package/templates/layers/node-prisma/typescript/src/controllers/upload.controller.ts +12 -19
  78. package/templates/layers/node-prisma/typescript/src/middleware/auth.middleware.ts +9 -13
  79. package/templates/layers/node-prisma/typescript/src/middleware/errorHandler.ts +18 -5
  80. package/templates/layers/node-prisma/typescript/src/middleware/rateLimiter.ts +2 -2
  81. package/templates/layers/node-prisma/typescript/src/routes/auth.route.ts +2 -0
  82. package/templates/layers/node-prisma/typescript/src/services/auth.service.ts +83 -31
  83. package/templates/layers/node-prisma/typescript/src/types/express.d.ts +5 -3
  84. package/templates/layers/node-prisma/typescript/src/utils/ApiError.ts +25 -0
  85. package/templates/layers/node-prisma/typescript/src/utils/SuccessResponse.ts +17 -0
  86. package/templates/layers/node-prisma/typescript/src/utils/apiResponse.ts +4 -0
  87. package/templates/layers/node-prisma/typescript/src/utils/asyncHandler.ts +13 -0
  88. package/templates/layers/node-prisma/typescript/src/utils/cloudinaryUpload.ts +18 -7
  89. package/templates/layers/node-prisma/typescript/src/utils/genOtpToken.ts +7 -1
  90. package/templates/layers/node-prisma/typescript/src/utils/jwt.ts +8 -2
  91. package/templates/layers/node-prisma/typescript/src/utils/logger.ts +2 -1
  92. package/templates/layers/node-prisma/typescript/src/utils/pushHelper.ts +10 -6
  93. package/templates/layers/prisma/javascript/package.json +8 -0
  94. package/templates/layers/prisma/typescript/package.json +14 -1
  95. package/templates/layers/prisma/typescript/src/config/db.ts +3 -2
  96. package/templates/layers/react/javascript/package.json +6 -0
  97. package/templates/layers/react/typescript/.eslintrc.cjs +20 -0
  98. package/templates/layers/react/typescript/package.json +11 -2
  99. package/templates/layers/react/typescript/src/components/common/Table.tsx +4 -4
  100. package/templates/layers/react/typescript/src/components/ui/Sidebar.tsx +1 -1
  101. package/templates/layers/react/typescript/src/main.tsx +11 -11
  102. package/templates/layers/react/typescript/src/services/authService.ts +1 -1
  103. package/templates/layers/react/typescript/src/store/useAuthStore.ts +24 -9
  104. package/templates/layers/react-native/base/app.json +9 -22
  105. package/templates/layers/react-native/base/eslint.config.js +5 -1
  106. package/templates/layers/react-native/base/package.json +40 -33
  107. package/templates/layers/react-native/base/src/app/(auth)/edit-profile.tsx +7 -7
  108. package/templates/layers/react-native/base/src/app/(auth)/login.tsx +31 -7
  109. package/templates/layers/react-native/base/src/app/(tabs)/_layout.tsx +3 -3
  110. package/templates/layers/react-native/base/src/app/(tabs)/index.tsx +6 -5
  111. package/templates/layers/react-native/base/src/app/_layout.tsx +4 -8
  112. package/templates/layers/react-native/base/src/app/screens/doc-viewer.tsx +378 -0
  113. package/templates/layers/react-native/base/src/components/common/ConfirmationToast.tsx +58 -40
  114. package/templates/layers/react-native/base/src/components/common/GoogleAuthButton.tsx +123 -0
  115. package/templates/layers/react-native/base/src/components/common/LocationLoader.tsx +64 -9
  116. package/templates/layers/react-native/base/src/components/common/Typography.tsx +54 -19
  117. package/templates/layers/react-native/base/src/components/ui/BiometricLock.tsx +3 -3
  118. package/templates/layers/react-native/base/src/components/ui/ClassicTabBar.tsx +15 -12
  119. package/templates/layers/react-native/base/src/components/ui/CustomTabBar.tsx +90 -91
  120. package/templates/layers/react-native/base/src/components/ui/Drawer.tsx +344 -0
  121. package/templates/layers/react-native/base/src/components/ui/Sidebar.tsx +4 -4
  122. package/templates/layers/react-native/base/src/components/ui/buttons/Button.tsx +29 -6
  123. package/templates/layers/react-native/base/src/components/ui/data-display/Accordion.tsx +2 -2
  124. package/templates/layers/react-native/base/src/components/ui/data-display/Badge.tsx +1 -2
  125. package/templates/layers/react-native/base/src/components/ui/data-display/Image.tsx +3 -3
  126. package/templates/layers/react-native/base/src/components/ui/data-display/SwipeableRow.tsx +28 -7
  127. package/templates/layers/react-native/base/src/components/ui/feedback/GestureWrapper.tsx +11 -4
  128. package/templates/layers/react-native/base/src/components/ui/inputs/DatePicker.tsx +3 -3
  129. package/templates/layers/react-native/base/src/components/ui/inputs/ImagePickerModal.tsx +45 -19
  130. package/templates/layers/react-native/base/src/components/ui/inputs/Input.tsx +28 -9
  131. package/templates/layers/react-native/base/src/components/ui/inputs/SearchablePicker.tsx +199 -0
  132. package/templates/layers/react-native/base/src/components/ui/inputs/Switch.tsx +7 -7
  133. package/templates/layers/react-native/base/src/components/ui/inputs/WebLocationPicker.tsx +146 -72
  134. package/templates/layers/react-native/base/src/config/api.ts +5 -5
  135. package/templates/layers/react-native/base/src/services/auth.service.ts +3 -1
  136. package/templates/layers/react-native/base/src/services/permission.service.ts +168 -44
  137. package/templates/layers/react-native/base/src/services/socket.service.ts +0 -7
  138. package/templates/layers/react-native/base/src/store/useAuthStore.ts +61 -16
  139. package/templates/layers/react-native/base/src/store/useNotificationStore.ts +36 -42
  140. package/templates/layers/react-native/base/src/types/images.d.ts +7 -5
  141. package/templates/layers/react-native/base/src/utils/env.ts +47 -0
  142. package/templates/layers/react-native/base/src/utils/fileDownload.ts +206 -0
  143. package/templates/layers/react-native/base/src/utils/storage.ts +1 -1
  144. package/templates/presets/production-fullstack/overrides/client/package.json +9 -0
  145. package/templates/presets/production-fullstack/overrides/mobile/app.json +2 -15
  146. package/templates/presets/production-fullstack/overrides/mobile/package.json +39 -29
  147. package/templates/presets/production-fullstack/overrides/mobile/src/app/_layout.tsx +3 -3
  148. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/Drawer.tsx +344 -0
  149. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/DatePicker.tsx +3 -3
  150. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/ImagePickerModal.tsx +3 -3
  151. package/templates/presets/production-fullstack/overrides/mobile/src/services/permission.service.ts +168 -44
  152. package/templates/presets/production-fullstack/overrides/mobile/src/store/useNotificationStore.ts +16 -0
  153. package/templates/presets/production-fullstack/overrides/mobile/src/utils/env.ts +47 -0
  154. package/templates/presets/production-fullstack/overrides/server/package.json +11 -2
  155. package/templates/layers/react-native/base/src/app/doc-viewer.tsx +0 -193
  156. package/templates/layers/react-native/base/src/components/ui/BottomModal.tsx +0 -176
  157. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/BottomModal.tsx +0 -159
  158. /package/templates/layers/react-native/base/assets/images/logo/{logoWithBg.png → icon.png} +0 -0
@@ -1,146 +1,101 @@
1
1
  import * as authService from "../services/auth.service.js";
2
2
  import { generateToken } from "../utils/jwt.js";
3
3
  import genOtpToken from "../utils/genOtpToken.js";
4
- import logger from "../utils/logger.js";
5
-
6
- export const signup = async (req, res, next) => {
7
- try {
8
- const { name, email, phone, password } = req.body;
9
- if (!email || !password || !name) {
10
- return next({
11
- status: 400,
12
- message: "All fields are required.",
13
- });
14
- }
15
-
16
- const newUser = await authService.signup({ name, email, phone, password });
17
- const token = await generateToken(newUser, res);
18
- const safeUser = { ...newUser };
19
- delete safeUser.password;
20
-
21
- res.status(201).json({ message: "Registration Successful", data: safeUser, token });
22
- } catch (error) {
23
- logger.error("Error in signup controller", error);
24
- next(error);
4
+ import { asyncHandler } from "../utils/asyncHandler.js";
5
+ import { SuccessResponse } from "../utils/SuccessResponse.js";
6
+ import { ApiError } from "../utils/ApiError.js";
7
+
8
+ export const signup = asyncHandler(async (req, res) => {
9
+ const { name, email, phone, password } = req.body;
10
+ if (!email || !password || !name) {
11
+ throw new ApiError(400, "All fields are required.");
25
12
  }
26
- };
27
-
28
- export const login = async (req, res, next) => {
29
- try {
30
- const { email, password } = req.body;
31
- if (!email || !password) {
32
- return next({
33
- status: 400,
34
- message: "All fields are required.",
35
- });
36
- }
37
-
38
- const user = await authService.login({ email, password });
39
- const token = await generateToken(user, res);
40
- const safeUser = { ...user };
41
- delete safeUser.password;
42
-
43
- res.status(200).json({ message: "Login successfully", data: safeUser, token });
44
- } catch (error) {
45
- logger.error("Error in login controller", error);
46
- next(error);
13
+ const newUser = await authService.signup({ name, email, phone, password });
14
+ const token = await generateToken(newUser, res);
15
+ const safeUser = { ...newUser };
16
+ delete safeUser.password;
17
+ SuccessResponse(res, 201, "Registration Successful", { user: safeUser, token });
18
+ });
19
+
20
+ export const login = asyncHandler(async (req, res) => {
21
+ const { email, password } = req.body;
22
+ if (!email || !password) {
23
+ throw new ApiError(400, "All fields are required.");
47
24
  }
48
- };
49
-
50
- export const logout = async (_req, res, next) => {
51
- try {
52
- res.clearCookie("token", {
53
- httpOnly: true,
54
- secure: process.env.NODE_ENV === "production",
55
- sameSite: "strict",
56
- path: "/",
57
- });
58
- res.status(200).json({ message: "Logout Successfully" });
59
- } catch (error) {
60
- logger.error("Error in logout controller", error);
61
- next(error);
25
+ const user = await authService.login({ email, password });
26
+ const token = await generateToken(user, res);
27
+ const safeUser = { ...user };
28
+ delete safeUser.password;
29
+ SuccessResponse(res, 200, "Login successfully", { user: safeUser, token });
30
+ });
31
+
32
+ export const logout = asyncHandler(async (_req, res) => {
33
+ res.clearCookie("token", {
34
+ httpOnly: true,
35
+ secure: process.env.NODE_ENV === "production",
36
+ sameSite: "strict",
37
+ path: "/",
38
+ });
39
+ SuccessResponse(res, 200, "Logout Successfully");
40
+ });
41
+
42
+ export const getMe = asyncHandler(async (req, res) => {
43
+ const safeUser = { ...req.user };
44
+ delete safeUser.password;
45
+ SuccessResponse(res, 200, "User Authenticated", safeUser);
46
+ });
47
+
48
+ export const genOtp = asyncHandler(async (req, res) => {
49
+ const { email } = req.body;
50
+ if (!email) {
51
+ throw new ApiError(400, "Email is required.");
62
52
  }
63
- };
64
-
65
- export const getMe = async (req, res, next) => {
66
- try {
67
- res.status(200).json({ message: "User Authenticated", data: req.user });
68
- } catch (error) {
69
- logger.error("Error in getMe controller", error);
70
- next(error);
53
+ await authService.generateOtp(email);
54
+ SuccessResponse(res, 200, "Otp sent successfully");
55
+ });
56
+
57
+ export const verifyOtp = asyncHandler(async (req, res) => {
58
+ const { email, otp } = req.body;
59
+ if (!email || !otp) {
60
+ throw new ApiError(400, "All fields are required.");
71
61
  }
72
- };
73
-
74
- export const genOtp = async (req, res, next) => {
75
- try {
76
- const { email } = req.body;
77
- if (!email) {
78
- return next({
79
- status: 400,
80
- message: "Email is required.",
81
- });
82
- }
83
-
84
- await authService.generateOtp(email);
85
- res.status(200).json({ message: "Otp sent successfully" });
86
- } catch (error) {
87
- logger.error("Error in genOtp", error);
88
- next(error);
62
+ const user = await authService.verifyOtp({ email, otp });
63
+ await genOtpToken(user, res);
64
+ SuccessResponse(res, 200, "Otp verified successfully");
65
+ });
66
+
67
+ export const resetPassword = asyncHandler(async (req, res) => {
68
+ const { newPassword } = req.body;
69
+ const currentUser = req.user;
70
+ if (!newPassword) {
71
+ throw new ApiError(400, "All fields are required.");
89
72
  }
90
- };
91
-
92
- export const verifyOtp = async (req, res, next) => {
93
- try {
94
- const { email, otp } = req.body;
95
- if (!email || !otp) {
96
- return next({
97
- status: 400,
98
- message: "All fields are required.",
99
- });
100
- }
101
-
102
- const user = await authService.verifyOtp({ email, otp });
103
- await genOtpToken(user, res);
104
-
105
- res.status(200).json({ message: "Otp verified successfully" });
106
- } catch (error) {
107
- logger.error("Error in verifyOtp", error);
108
- next(error);
73
+ await authService.resetPassword(currentUser, newPassword);
74
+ SuccessResponse(res, 200, "Password updated successfully");
75
+ });
76
+
77
+ export const updateMe = asyncHandler(async (req, res) => {
78
+ const { name, phone } = req.body;
79
+ const user = await authService.updateProfile(req.user.id, {
80
+ name,
81
+ phone,
82
+ file: req.file,
83
+ });
84
+ const safeUser = { ...user };
85
+ delete safeUser.password;
86
+ SuccessResponse(res, 200, "Profile updated successfully", safeUser);
87
+ });
88
+
89
+ export const googleLogin = asyncHandler(async (req, res) => {
90
+ const { idToken } = req.body;
91
+ if (!idToken) {
92
+ throw new ApiError(400, "idToken is required.");
109
93
  }
110
- };
111
-
112
- export const resetPassword = async (req, res, next) => {
113
- try {
114
- const { newPassword } = req.body;
115
- const currentUser = req.user;
116
- if (!newPassword) {
117
- return next({
118
- status: 400,
119
- message: "All fields are required.",
120
- });
121
- }
122
-
123
- await authService.resetPassword(currentUser, newPassword);
124
- res.status(200).json({ message: "Password updated successfully" });
125
- } catch (error) {
126
- logger.error("Error in resetPassword", error);
127
- next(error);
128
- }
129
- };
130
-
131
- export const updateMe = async (req, res, next) => {
132
- try {
133
- const { name, phone } = req.body;
134
- const user = await authService.updateProfile(req.user.id, {
135
- name,
136
- phone,
137
- file: req.file,
138
- });
139
- const safeUser = { ...user };
94
+ const user = await authService.googleLogin(idToken);
95
+ const token = await generateToken(user, res);
96
+ const safeUser = user;
97
+ if (safeUser.password !== undefined) {
140
98
  delete safeUser.password;
141
- res.status(200).json({ success: true, data: safeUser });
142
- } catch (error) {
143
- logger.error("Error updating profile", error);
144
- next(error);
145
99
  }
146
- };
100
+ SuccessResponse(res, 200, "Google Login successfully", { user: safeUser, token });
101
+ });
@@ -1,93 +1,81 @@
1
1
  import { prisma } from "../config/db.js";
2
- import logger from "../utils/logger.js";
2
+ import { asyncHandler } from "../utils/asyncHandler.js";
3
+ import { SuccessResponse } from "../utils/SuccessResponse.js";
4
+ import { ApiError } from "../utils/ApiError.js";
3
5
 
4
- export const subscribe = async (
5
- req,
6
- res,
7
- next,
8
- ) => {
9
- try {
10
- const subscription = req.body;
11
- const userId = req.user?._id || req.user?.id;
6
+ export const subscribe = asyncHandler(async (req, res) => {
7
+ const subscription = req.body;
8
+ const userId = req.user?._id || req.user?.id;
12
9
 
13
- if (!subscription) {
14
- return next({ status: 400, message: "Invalid subscription payload" });
15
- }
10
+ if (!subscription) {
11
+ throw new ApiError(400, "Invalid subscription payload");
12
+ }
16
13
 
17
- // Determine type: EXPO if token is present, else WEB
18
- const isExpo = !!subscription.token;
19
- const isWeb = !!(subscription.endpoint && subscription.keys);
14
+ // Determine type: EXPO if token is present, else WEB
15
+ const isExpo = !!subscription.token;
16
+ const isWeb = !!(subscription.endpoint && subscription.keys);
20
17
 
21
- if (!isExpo && !isWeb) {
22
- return next({ status: 400, message: "Missing token (EXPO) or endpoint/keys (WEB)" });
23
- }
18
+ if (!isExpo && !isWeb) {
19
+ throw new ApiError(400, "Missing token (EXPO) or endpoint/keys (WEB)");
20
+ }
24
21
 
25
- if (isExpo) {
26
- const existingSub = await prisma.pushSubscription.findUnique({
27
- where: { token: subscription.token },
28
- });
22
+ if (isExpo) {
23
+ const existingSub = await prisma.pushSubscription.findUnique({
24
+ where: { token: subscription.token },
25
+ });
29
26
 
30
- if (existingSub) {
31
- if (userId && existingSub.userId !== userId) {
32
- await prisma.pushSubscription.update({
33
- where: { token: subscription.token },
34
- data: { userId },
35
- });
36
- }
37
- return res.status(200).json({ success: true, message: "Already subscribed." });
27
+ if (existingSub) {
28
+ if (userId && existingSub.userId !== userId) {
29
+ await prisma.pushSubscription.update({
30
+ where: { token: subscription.token },
31
+ data: { userId },
32
+ });
38
33
  }
34
+ return SuccessResponse(res, 200, "Already subscribed.");
35
+ }
39
36
 
40
- await prisma.pushSubscription.create({
41
- data: {
42
- type: "EXPO",
43
- token: subscription.token,
44
- userId: userId || null,
45
- },
46
- });
47
- } else {
48
- const existingSub = await prisma.pushSubscription.findUnique({
49
- where: { endpoint: subscription.endpoint },
50
- });
37
+ await prisma.pushSubscription.create({
38
+ data: {
39
+ type: "EXPO",
40
+ token: subscription.token,
41
+ userId: userId || null,
42
+ },
43
+ });
44
+ } else {
45
+ const existingSub = await prisma.pushSubscription.findUnique({
46
+ where: { endpoint: subscription.endpoint },
47
+ });
51
48
 
52
- if (existingSub) {
53
- if (userId && existingSub.userId !== userId) {
54
- await prisma.pushSubscription.update({
55
- where: { endpoint: subscription.endpoint },
56
- data: { userId },
57
- });
58
- }
59
- return res.status(200).json({ success: true, message: "Already subscribed." });
49
+ if (existingSub) {
50
+ if (userId && existingSub.userId !== userId) {
51
+ await prisma.pushSubscription.update({
52
+ where: { endpoint: subscription.endpoint },
53
+ data: { userId },
54
+ });
60
55
  }
61
-
62
- await prisma.pushSubscription.create({
63
- data: {
64
- type: "WEB",
65
- endpoint: subscription.endpoint,
66
- keys: subscription.keys,
67
- userId: userId || null,
68
- },
69
- });
56
+ return SuccessResponse(res, 200, "Already subscribed.");
70
57
  }
71
58
 
72
- res.status(201).json({ success: true, message: "Subscription created." });
73
- } catch (error) {
74
- logger.error("Error in push subscribe controller", error);
75
- next(error);
59
+ await prisma.pushSubscription.create({
60
+ data: {
61
+ type: "WEB",
62
+ endpoint: subscription.endpoint,
63
+ keys: subscription.keys,
64
+ userId: userId || null,
65
+ },
66
+ });
76
67
  }
77
- };
78
-
79
- export const unsubscribe = async (req, res, next) => {
80
- try {
81
- const { endpoint } = req.body;
82
- if (!endpoint) {
83
- return next({ status: 400, message: "Endpoint required" });
84
- }
85
68
 
86
- await prisma.pushSubscription.delete({ where: { endpoint } }).catch(() => {})
69
+ SuccessResponse(res, 201, "Subscription created.");
70
+ });
87
71
 
88
- res.status(200).json({ success: true, message: "Unsubscribed." });
89
- } catch (error) {
90
- logger.error("Error in push unsubscribe controller", error);
91
- next(error);
72
+ export const unsubscribe = asyncHandler(async (req, res) => {
73
+ const { endpoint } = req.body;
74
+ if (!endpoint) {
75
+ throw new ApiError(400, "Endpoint required");
92
76
  }
93
- };
77
+
78
+ await prisma.pushSubscription.delete({ where: { endpoint } }).catch(() => {});
79
+
80
+ SuccessResponse(res, 200, "Unsubscribed.");
81
+ });
@@ -1,26 +1,19 @@
1
1
  import { uploadSingleToCloudinary } from "../utils/cloudinaryUpload.js";
2
- import logger from "../utils/logger.js";
2
+ import { asyncHandler } from "../utils/asyncHandler.js";
3
+ import { SuccessResponse } from "../utils/SuccessResponse.js";
4
+ import { ApiError } from "../utils/ApiError.js";
3
5
 
4
6
  /**
5
7
  * Handle single file uploads to Cloudinary
6
8
  */
7
- export const uploadFile = async (req, res, next) => {
8
- try {
9
- if (!req.file) {
10
- return res.status(400).json({ success: false, message: "No file uploaded" });
11
- }
9
+ export const uploadFile = asyncHandler(async (req, res) => {
10
+ if (!req.file) {
11
+ throw new ApiError(400, "No file uploaded");
12
+ }
12
13
 
13
- const result = await uploadSingleToCloudinary(req.file, {
14
- folder: req.body.folder || "general_uploads",
15
- });
14
+ const result = await uploadSingleToCloudinary(req.file, {
15
+ folder: req.body.folder || "general_uploads",
16
+ });
16
17
 
17
- res.status(200).json({
18
- success: true,
19
- message: "File uploaded successfully",
20
- data: result,
21
- });
22
- } catch (error) {
23
- logger.error("Upload controller error", error);
24
- next(error);
25
- }
26
- };
18
+ SuccessResponse(res, 200, "File uploaded successfully", result);
19
+ });
@@ -1,6 +1,7 @@
1
1
  import { verifyToken } from "../utils/jwt.js";
2
2
  import logger from "../utils/logger.js";
3
3
  import { prisma } from "../config/db.js";
4
+ import { ApiError } from "../utils/ApiError.js";
4
5
 
5
6
  export const protect = async (req, res, next) => {
6
7
  let token;
@@ -14,13 +15,13 @@ export const protect = async (req, res, next) => {
14
15
  }
15
16
 
16
17
  if (!token) {
17
- return res.status(401).json({ message: "Not authorized, no token provided" });
18
+ return next(new ApiError(401, "Not authorized, no token provided"));
18
19
  }
19
20
 
20
21
  try {
21
22
  const decoded = verifyToken(token);
22
23
  if (!decoded) {
23
- return res.status(401).json({ message: "Not authorized, invalid token" });
24
+ return next(new ApiError(401, "Not authorized, invalid token"));
24
25
  }
25
26
 
26
27
  const user = await prisma.user.findUnique({
@@ -28,7 +29,7 @@ export const protect = async (req, res, next) => {
28
29
  });
29
30
 
30
31
  if (!user) {
31
- return res.status(401).json({ message: "Not authorized, user not found" });
32
+ return next(new ApiError(401, "Not authorized, user not found"));
32
33
  }
33
34
 
34
35
  // Exclude password
@@ -39,6 +40,6 @@ export const protect = async (req, res, next) => {
39
40
  return next();
40
41
  } catch (error) {
41
42
  logger.error("Auth middleware error", error);
42
- return res.status(401).json({ message: "Not authorized, token verification failed" });
43
+ return next(new ApiError(401, "Not authorized, token verification failed"));
43
44
  }
44
45
  };
@@ -1,11 +1,11 @@
1
+ import { ApiError } from "../utils/ApiError.js";
2
+
1
3
  /**
2
4
  * Not Found Middleware
3
5
  * Catches all unmatched requests and forwards a 404 error
4
6
  */
5
7
  export const notFound = (req, res, next) => {
6
- const error = new Error(`Not Found - ${req.originalUrl}`);
7
- res.status(404);
8
- next(error);
8
+ next(new ApiError(404, `Not Found - ${req.originalUrl}`));
9
9
  };
10
10
 
11
11
  /**
@@ -13,10 +13,12 @@ export const notFound = (req, res, next) => {
13
13
  * Formats error responses nicely in JSON
14
14
  */
15
15
  export const errorHandler = (err, req, res, next) => {
16
- const statusCode = err.status || err.statusCode || (res.statusCode === 200 ? 500 : res.statusCode);
16
+ const statusCode = err.statusCode || err.status || (res.statusCode === 200 ? 500 : res.statusCode);
17
17
  res.status(statusCode).json({
18
18
  success: false,
19
+ statusCode,
19
20
  message: err.message || "An unexpected error occurred",
21
+ errors: err.errors || [],
20
22
  stack: process.env.NODE_ENV === "production" ? undefined : err.stack,
21
23
  });
22
24
  };
@@ -5,6 +5,7 @@ import {
5
5
  getMe,
6
6
  logout,
7
7
  updateMe,
8
+ googleLogin,
8
9
  } from "../controllers/auth.controller.js";
9
10
  import { protect } from "../middleware/auth.middleware.js";
10
11
  import { apiLimiter } from "../middleware/rateLimiter.js";
@@ -15,6 +16,7 @@ router.use(apiLimiter);
15
16
 
16
17
  router.post("/signup", signup);
17
18
  router.post("/login", login);
19
+ router.post("/google", googleLogin);
18
20
  router.post("/logout", logout);
19
21
  router.get("/me", protect, getMe);
20
22
  router.put("/me", protect, updateMe);