@imksh/create 1.0.31 → 1.0.32

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 (152) 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 +11 -1
  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 +3 -3
  112. package/templates/layers/react-native/base/src/app/doc-viewer.tsx +3 -3
  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 +144 -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/ClassicTabBar.tsx +15 -12
  118. package/templates/layers/react-native/base/src/components/ui/CustomTabBar.tsx +84 -90
  119. package/templates/layers/react-native/base/src/components/ui/Drawer.tsx +344 -0
  120. package/templates/layers/react-native/base/src/components/ui/Sidebar.tsx +4 -4
  121. package/templates/layers/react-native/base/src/components/ui/buttons/Button.tsx +29 -6
  122. package/templates/layers/react-native/base/src/components/ui/data-display/Accordion.tsx +2 -2
  123. package/templates/layers/react-native/base/src/components/ui/data-display/Badge.tsx +1 -2
  124. package/templates/layers/react-native/base/src/components/ui/data-display/Image.tsx +3 -3
  125. package/templates/layers/react-native/base/src/components/ui/data-display/SwipeableRow.tsx +28 -7
  126. package/templates/layers/react-native/base/src/components/ui/feedback/GestureWrapper.tsx +11 -4
  127. package/templates/layers/react-native/base/src/components/ui/inputs/DatePicker.tsx +3 -3
  128. package/templates/layers/react-native/base/src/components/ui/inputs/ImagePickerModal.tsx +45 -19
  129. package/templates/layers/react-native/base/src/components/ui/inputs/Input.tsx +28 -9
  130. package/templates/layers/react-native/base/src/components/ui/inputs/SearchablePicker.tsx +199 -0
  131. package/templates/layers/react-native/base/src/components/ui/inputs/Switch.tsx +7 -7
  132. package/templates/layers/react-native/base/src/components/ui/inputs/WebLocationPicker.tsx +146 -72
  133. package/templates/layers/react-native/base/src/config/api.ts +5 -5
  134. package/templates/layers/react-native/base/src/services/auth.service.ts +3 -1
  135. package/templates/layers/react-native/base/src/services/permission.service.ts +0 -2
  136. package/templates/layers/react-native/base/src/services/socket.service.ts +0 -7
  137. package/templates/layers/react-native/base/src/store/useAuthStore.ts +61 -16
  138. package/templates/layers/react-native/base/src/store/useNotificationStore.ts +36 -42
  139. package/templates/layers/react-native/base/src/types/images.d.ts +7 -5
  140. package/templates/layers/react-native/base/src/utils/fileDownload.ts +206 -0
  141. package/templates/layers/react-native/base/src/utils/storage.ts +1 -1
  142. package/templates/presets/production-fullstack/overrides/client/package.json +9 -0
  143. package/templates/presets/production-fullstack/overrides/mobile/app.json +2 -15
  144. package/templates/presets/production-fullstack/overrides/mobile/package.json +11 -1
  145. package/templates/presets/production-fullstack/overrides/mobile/src/app/_layout.tsx +3 -3
  146. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/Drawer.tsx +344 -0
  147. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/DatePicker.tsx +3 -3
  148. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/ImagePickerModal.tsx +3 -3
  149. package/templates/presets/production-fullstack/overrides/server/package.json +11 -2
  150. package/templates/layers/react-native/base/src/components/ui/BottomModal.tsx +0 -176
  151. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/BottomModal.tsx +0 -159
  152. /package/templates/layers/react-native/base/assets/images/logo/{logoWithBg.png → icon.png} +0 -0
@@ -1,155 +1,178 @@
1
+ import { OAuth2Client } from "google-auth-library";
1
2
  import bcrypt from "bcrypt";
2
3
  import { prisma } from "../config/db.js";
3
4
  import { sendOtpEmail } from "../utils/emailOtp.js";
4
5
  import { uploadSingleToCloudinary, deleteFromCloudinary } from "../utils/cloudinaryUpload.js";
5
6
  import logger from "../utils/logger.js";
7
+ import { ApiError } from "../utils/ApiError.js";
8
+
9
+ const googleClient = new OAuth2Client(process.env.GOOGLE_CLIENT_ID || "");
10
+
6
11
  export const signup = async ({ name, email, phone, password }) => {
7
- const existingUser = await prisma.user.findUnique({
8
- where: { email },
9
- });
10
- if (existingUser) {
11
- const err = new Error("User already exists");
12
- err.status = 409;
13
- throw err;
14
- }
12
+ const existingUser = await prisma.user.findUnique({
13
+ where: { email },
14
+ });
15
+ if (existingUser) {
16
+ throw new ApiError(409, "User already exists");
17
+ }
15
18
 
16
- const salt = await bcrypt.genSalt(10);
17
- const hashedPassword = await bcrypt.hash(password, salt);
18
- const photoURL = `https://placehold.co/600x400?text=${name.charAt(0).toUpperCase()}`;
19
+ const salt = await bcrypt.genSalt(10);
20
+ const hashedPassword = await bcrypt.hash(password, salt);
21
+ const photoURL = `https://placehold.co/600x400?text=${name.charAt(0).toUpperCase()}`;
19
22
 
20
- const newUser = await prisma.user.create({
21
- data: {
22
- name,
23
- email: email.toLowerCase(),
24
- phone,
25
- password: hashedPassword,
26
- avatarUrl: photoURL,
27
- avatarPublicId: "",
28
- },
29
- });
23
+ const newUser = await prisma.user.create({
24
+ data: {
25
+ name,
26
+ email: email.toLowerCase(),
27
+ phone,
28
+ password: hashedPassword,
29
+ avatarUrl: photoURL,
30
+ avatarPublicId: "",
31
+ },
32
+ });
30
33
 
31
- return newUser;
32
- }
33
- export const login = async ({ email, password }) => {
34
- const user = await prisma.user.findUnique({
35
- where: { email },
36
- });
37
- if (!user) {
38
- const err = new Error("User not found");
39
- err.status = 404;
40
- throw err;
41
- }
34
+ return newUser;
35
+ };
42
36
 
43
- const isValid = await bcrypt.compare(password, user.password);
44
- if (!isValid) {
45
- const err = new Error("Invalid Credentials");
46
- err.status = 401;
47
- throw err;
48
- }
37
+ export const login = async ({ email, password }) => {
38
+ const user = await prisma.user.findUnique({
39
+ where: { email },
40
+ });
41
+ if (!user) {
42
+ throw new ApiError(404, "User not found");
43
+ }
49
44
 
50
- return user;
45
+ const isValid = await bcrypt.compare(password, user.password);
46
+ if (!isValid) {
47
+ throw new ApiError(401, "Invalid Credentials");
51
48
  }
49
+
50
+ return user;
51
+ };
52
+
52
53
  export const generateOtp = async (email) => {
53
- const user = await prisma.user.findUnique({
54
- where: { email },
55
- });
56
- if (!user) {
57
- const err = new Error("User not found");
58
- err.status = 404;
59
- throw err;
60
- }
54
+ const user = await prisma.user.findUnique({
55
+ where: { email },
56
+ });
57
+ if (!user) {
58
+ throw new ApiError(404, "User not found");
59
+ }
61
60
 
62
- const existingOtp = await prisma.otp.findUnique({
61
+ const existingOtp = await prisma.otp.findUnique({
62
+ where: { email },
63
+ });
64
+ if (existingOtp) {
65
+ await prisma.otp.delete({
63
66
  where: { email },
64
67
  });
65
- if (existingOtp) {
66
- await prisma.otp.delete({
67
- where: { email },
68
- });
69
- }
68
+ }
70
69
 
71
- const otp = Math.floor(100000 + Math.random() * 900000).toString();
72
- const hashedOtp = await bcrypt.hash(otp, 10);
70
+ const otp = Math.floor(100000 + Math.random() * 900000).toString();
71
+ const hashedOtp = await bcrypt.hash(otp, 10);
73
72
 
74
- await prisma.otp.create({
75
- data: {
76
- email,
77
- otp: hashedOtp,
78
- },
79
- });
73
+ await prisma.otp.create({
74
+ data: {
75
+ email,
76
+ otp: hashedOtp,
77
+ },
78
+ });
80
79
 
81
- await sendOtpEmail(email, otp);
82
- return true;
83
- }
84
- export const verifyOtp = async ({ email, otp }) => {
85
- const user = await prisma.user.findUnique({
86
- where: { email },
87
- });
88
- if (!user) {
89
- const err = new Error("User not found");
90
- err.status = 404;
91
- throw err;
92
- }
80
+ await sendOtpEmail(email, otp);
81
+ return true;
82
+ };
93
83
 
94
- const existingOtp = await prisma.otp.findUnique({
95
- where: { email },
96
- });
97
- if (!existingOtp) {
98
- const err = new Error("OTP match failed");
99
- err.status = 400;
100
- throw err;
101
- }
84
+ export const verifyOtp = async ({ email, otp }) => {
85
+ const user = await prisma.user.findUnique({
86
+ where: { email },
87
+ });
88
+ if (!user) {
89
+ throw new ApiError(404, "User not found");
90
+ }
102
91
 
103
- const isMatched = await bcrypt.compare(otp, existingOtp.otp);
104
- if (!isMatched) {
105
- const err = new Error("OTP match failed");
106
- err.status = 400;
107
- throw err;
108
- }
92
+ const existingOtp = await prisma.otp.findUnique({
93
+ where: { email },
94
+ });
95
+ if (!existingOtp) {
96
+ throw new ApiError(400, "OTP match failed");
97
+ }
109
98
 
110
- return user;
99
+ const isMatched = await bcrypt.compare(otp, existingOtp.otp);
100
+ if (!isMatched) {
101
+ throw new ApiError(400, "OTP match failed");
111
102
  }
103
+
104
+ return user;
105
+ };
106
+
112
107
  export const resetPassword = async (user, newPassword) => {
113
- const hashedPassword = await bcrypt.hash(newPassword, 10);
114
- await prisma.user.update({
115
- where: { id: user.id },
116
- data: { password: hashedPassword },
117
- });
118
- return true;
119
- }
108
+ const hashedPassword = await bcrypt.hash(newPassword, 10);
109
+ await prisma.user.update({
110
+ where: { id: user.id },
111
+ data: { password: hashedPassword },
112
+ });
113
+ return true;
114
+ };
115
+
120
116
  export const updateProfile = async (userId, { name, phone, file }) => {
121
- const user = await prisma.user.findUnique({
122
- where: { id: userId },
117
+ const user = await prisma.user.findUnique({
118
+ where: { id: userId },
119
+ });
120
+ if (!user) {
121
+ throw new ApiError(404, "User not found");
122
+ }
123
+
124
+ const updateData = {};
125
+ if (name) updateData.name = name;
126
+ if (phone) updateData.phone = phone;
127
+
128
+ if (file) {
129
+ const uploadResult = await uploadSingleToCloudinary(file, {
130
+ folder: "codelab/avatars",
123
131
  });
124
- if (!user) {
125
- const err = new Error("User not found");
126
- err.status = 404;
127
- throw err;
132
+
133
+ if (user.avatarPublicId) {
134
+ await deleteFromCloudinary(user.avatarPublicId).catch((err) =>
135
+ logger.error("Old avatar delete error", err)
136
+ );
128
137
  }
129
138
 
130
- const updateData = {};
131
- if (name) updateData.name = name;
132
- if (phone) updateData.phone = phone;
139
+ updateData.avatarUrl = uploadResult.url;
140
+ updateData.avatarPublicId = uploadResult.publicId;
141
+ }
133
142
 
134
- if (file) {
135
- const uploadResult = await uploadSingleToCloudinary(file, {
136
- folder: "codelab/avatars",
137
- });
143
+ const updatedUser = await prisma.user.update({
144
+ where: { id: userId },
145
+ data: updateData,
146
+ });
147
+
148
+ return updatedUser;
149
+ };
150
+
151
+ export const googleLogin = async (idToken) => {
152
+ const ticket = await googleClient.verifyIdToken({
153
+ idToken,
154
+ audience: process.env.GOOGLE_CLIENT_ID,
155
+ });
156
+ const payload = ticket.getPayload();
157
+ if (!payload) {
158
+ throw new ApiError(401, "Invalid Google Token");
159
+ }
160
+ const { email, name, picture } = payload;
161
+ if (!email) {
162
+ throw new ApiError(400, "Email not found in Google Token");
163
+ }
138
164
 
139
- if (user.avatarPublicId) {
140
- await deleteFromCloudinary(user.avatarPublicId).catch((err) =>
141
- logger.error("Old avatar delete error", err)
142
- );
165
+ let user = await prisma.user.findUnique({ where: { email } });
166
+ if (!user) {
167
+ user = await prisma.user.create({
168
+ data: {
169
+ name: name || "User",
170
+ email: email.toLowerCase(),
171
+ password: "",
172
+ avatarUrl: picture || `https://placehold.co/600x400?text=${name?.charAt(0).toUpperCase() || 'U'}`,
173
+ avatarPublicId: "",
143
174
  }
144
-
145
- updateData.avatarUrl = uploadResult.url;
146
- updateData.avatarPublicId = uploadResult.publicId;
147
- }
148
-
149
- const updatedUser = await prisma.user.update({
150
- where: { id: userId },
151
- data: updateData,
152
175
  });
153
-
154
- return updatedUser;
155
176
  }
177
+ return user;
178
+ };
@@ -0,0 +1,20 @@
1
+ export class ApiError extends Error {
2
+ constructor(
3
+ statusCode,
4
+ message = "Something went wrong",
5
+ errors = [],
6
+ stack = "",
7
+ ) {
8
+ super(message);
9
+ this.statusCode = statusCode;
10
+ this.data = null;
11
+ this.success = false;
12
+ this.errors = errors;
13
+
14
+ if (stack) {
15
+ this.stack = stack;
16
+ } else {
17
+ Error.captureStackTrace(this, this.constructor);
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,15 @@
1
+ export const SuccessResponse = (
2
+ res,
3
+ statusCode,
4
+ message = "Success",
5
+ data = null,
6
+ pagination = undefined,
7
+ ) => {
8
+ return res.status(statusCode).json({
9
+ success: statusCode < 400,
10
+ statusCode,
11
+ message,
12
+ data,
13
+ ...(pagination && { pagination }),
14
+ });
15
+ };
@@ -0,0 +1,4 @@
1
+ import { SuccessResponse } from "./SuccessResponse.js";
2
+
3
+ export { SuccessResponse };
4
+ export const ApiResponse = SuccessResponse;
@@ -0,0 +1,5 @@
1
+ export const asyncHandler = (requestHandler) => {
2
+ return (req, res, next) => {
3
+ Promise.resolve(requestHandler(req, res, next)).catch((err) => next(err));
4
+ };
5
+ };
@@ -60,4 +60,6 @@ RATE_LIMIT_MAX=100
60
60
  # ==========================
61
61
  VAPID_PRIVATE_KEY=
62
62
  VAPID_PUBLIC_KEY=
63
- VAPID_SUBJECT=mailto:noreply@example.com
63
+ VAPID_SUBJECT=mailto:noreply@example.com
64
+ # Google Auth
65
+ GOOGLE_CLIENT_ID=your-google-client-id
@@ -0,0 +1,28 @@
1
+ module.exports = {
2
+ env: {
3
+ node: true,
4
+ es2022: true,
5
+ },
6
+ parser: "@typescript-eslint/parser",
7
+ parserOptions: {
8
+ ecmaVersion: "latest",
9
+ sourceType: "module",
10
+ },
11
+ plugins: ["@typescript-eslint"],
12
+ extends: [
13
+ "eslint:recommended",
14
+ "plugin:@typescript-eslint/recommended",
15
+ ],
16
+ rules: {
17
+ "@typescript-eslint/no-explicit-any": "error",
18
+ "no-console": "error",
19
+ },
20
+ overrides: [
21
+ {
22
+ files: ["src/utils/logger.ts"],
23
+ rules: {
24
+ "no-console": "off",
25
+ },
26
+ },
27
+ ],
28
+ };
@@ -7,6 +7,13 @@
7
7
  "start": "tsx src/index.ts",
8
8
  "dev": "tsx watch src/index.ts",
9
9
  "build": "tsc",
10
+ "lint": "eslint . --ext .ts --max-warnings 0",
11
+ "lint:fix": "eslint . --ext .ts --fix",
12
+ "format": "prettier --write \"src/**/*.{ts,json}\"",
13
+ "format:check": "prettier --check \"src/**/*.{ts,json}\"",
14
+ "circular-check": "dpdm --circular --no-warning --no-tree --exit-code circular:1 \"src/**/*.ts\"",
15
+ "ts-prune": "ts-prune",
16
+ "ts-purns": "ts-prune",
10
17
  "db:push": "prisma db push",
11
18
  "db:generate": "prisma generate",
12
19
  "generate:vapid": "node ./src/utils/generateVapidKeys.js"
@@ -30,7 +37,8 @@
30
37
  "web-push": "^3.6.6",
31
38
  "pg": "^8.11.3",
32
39
  "@prisma/adapter-pg": "^7.0.0",
33
- "expo-server-sdk": "^3.10.0"
40
+ "expo-server-sdk": "^3.10.0",
41
+ "google-auth-library": "^9.14.2"
34
42
  },
35
43
  "devDependencies": {
36
44
  "@types/bcrypt": "^5.0.2",
@@ -41,12 +49,18 @@
41
49
  "@types/jsonwebtoken": "^9.0.5",
42
50
  "@types/morgan": "^1.9.9",
43
51
  "@types/multer": "^1.4.11",
52
+ "@types/node": "^20.9.0",
44
53
  "@types/nodemailer": "^6.4.14",
54
+ "@types/pg": "^8.11.0",
45
55
  "@types/web-push": "^3.6.3",
46
- "@types/node": "^20.9.0",
56
+ "@typescript-eslint/eslint-plugin": "^6.10.0",
57
+ "@typescript-eslint/parser": "^6.10.0",
58
+ "dpdm": "^3.14.0",
59
+ "eslint": "^8.53.0",
60
+ "prettier": "^3.4.2",
47
61
  "prisma": "^7.0.0",
62
+ "ts-prune": "^0.10.3",
48
63
  "tsx": "^4.23.1",
49
- "typescript": "^5.2.2",
50
- "@types/pg": "^8.11.0"
64
+ "typescript": "^5.2.2"
51
65
  }
52
- }
66
+ }
@@ -1,4 +1,4 @@
1
- import express, { Request, Response, NextFunction } from "express";
1
+ import express, { Request, Response } from "express";
2
2
  import helmet from "helmet";
3
3
  import cors from "cors";
4
4
  import compression from "compression";
@@ -7,6 +7,7 @@ import morgan from "morgan";
7
7
  import apiRoutes from "./routes/index.js";
8
8
  import { notFound, errorHandler } from "./middleware/errorHandler.js";
9
9
  import { apiLimiter } from "./middleware/rateLimiter.js";
10
+ import { SuccessResponse } from "./utils/SuccessResponse.js";
10
11
 
11
12
  const app = express();
12
13
 
@@ -27,7 +28,7 @@ app.use(apiLimiter);
27
28
  app.use("/api", apiRoutes);
28
29
 
29
30
  app.get("/api/health", (req: Request, res: Response) => {
30
- res.status(200).json({ success: true, message: "API is running" });
31
+ SuccessResponse(res, 200, "API is running");
31
32
  });
32
33
 
33
34
  app.use(notFound);
@@ -15,8 +15,9 @@ const connectDB = async () => {
15
15
  try {
16
16
  await prisma.$connect();
17
17
  logger.success("Prisma Database connected successfully");
18
- } catch (error: any) {
19
- logger.error(`Prisma Database connection failed: ${error.message}`, error);
18
+ } catch (error: unknown) {
19
+ const err = error as Error;
20
+ logger.error(`Prisma Database connection failed: ${err.message}`, error);
20
21
  process.exit(1);
21
22
  }
22
23
  };
@@ -1,12 +1,13 @@
1
- import { Server } from "socket.io";
1
+ import { Server as SocketIOServer } from "socket.io";
2
+ import type { Server as HttpServer } from "http";
2
3
  import logger from "../utils/logger.js";
3
4
 
4
- let io: Server;
5
+ let io: SocketIOServer;
5
6
 
6
7
  const userSocketMap: { [key: string]: Set<string> } = {};
7
8
 
8
- const initializeSocket = (server: any) => {
9
- io = new Server(server, {
9
+ const initializeSocket = (server: HttpServer) => {
10
+ io = new SocketIOServer(server, {
10
11
  cors: {
11
12
  origin: ["http://localhost:5173"],
12
13
  credentials: true,