@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.
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/commands/create.js +2 -0
- package/src/index.js +1 -1
- package/templates/layers/next/javascript/package.json +8 -2
- package/templates/layers/next/typescript/.eslintrc.json +12 -0
- package/templates/layers/next/typescript/package.json +14 -3
- package/templates/layers/next/typescript/src/components/common/Loading.tsx +1 -1
- package/templates/layers/next/typescript/src/components/common/LottieIcon.tsx +2 -2
- package/templates/layers/next/typescript/src/components/common/Table.tsx +4 -4
- package/templates/layers/next/typescript/src/components/modals/ConfirmModal.tsx +2 -1
- package/templates/layers/next/typescript/src/components/ui/Header.tsx +2 -2
- package/templates/layers/next/typescript/src/hooks/usePwaInstall.ts +10 -4
- package/templates/layers/next/typescript/src/services/authService.ts +1 -1
- package/templates/layers/next/typescript/src/store/useAuthStore.ts +24 -9
- package/templates/layers/node/javascript/.env.example +3 -1
- package/templates/layers/node/javascript/package.json +12 -3
- package/templates/layers/node/javascript/src/app.js +2 -1
- package/templates/layers/node/javascript/src/controllers/auth.controller.js +106 -168
- package/templates/layers/node/javascript/src/controllers/push.controller.js +51 -58
- package/templates/layers/node/javascript/src/controllers/upload.controller.js +12 -19
- package/templates/layers/node/javascript/src/middleware/auth.middleware.js +5 -11
- package/templates/layers/node/javascript/src/middleware/errorHandler.js +6 -4
- package/templates/layers/node/javascript/src/routes/auth.route.js +2 -0
- package/templates/layers/node/javascript/src/services/auth.service.js +159 -164
- package/templates/layers/node/javascript/src/utils/ApiError.js +20 -0
- package/templates/layers/node/javascript/src/utils/SuccessResponse.js +15 -0
- package/templates/layers/node/javascript/src/utils/apiResponse.js +4 -0
- package/templates/layers/node/javascript/src/utils/asyncHandler.js +5 -0
- package/templates/layers/node/typescript/.env.example +3 -1
- package/templates/layers/node/typescript/.eslintrc.cjs +28 -0
- package/templates/layers/node/typescript/package.json +16 -2
- package/templates/layers/node/typescript/src/app.ts +3 -2
- package/templates/layers/node/typescript/src/config/db.ts +3 -2
- package/templates/layers/node/typescript/src/config/socket.ts +5 -4
- package/templates/layers/node/typescript/src/controllers/auth.controller.ts +104 -132
- package/templates/layers/node/typescript/src/controllers/push.controller.ts +52 -59
- package/templates/layers/node/typescript/src/controllers/upload.controller.ts +12 -19
- package/templates/layers/node/typescript/src/middleware/auth.middleware.ts +13 -7
- package/templates/layers/node/typescript/src/middleware/errorHandler.ts +18 -5
- package/templates/layers/node/typescript/src/middleware/rateLimiter.ts +2 -2
- package/templates/layers/node/typescript/src/routes/auth.route.ts +2 -0
- package/templates/layers/node/typescript/src/services/auth.service.ts +86 -43
- package/templates/layers/node/typescript/src/types/express.d.ts +5 -3
- package/templates/layers/node/typescript/src/utils/ApiError.ts +25 -0
- package/templates/layers/node/typescript/src/utils/SuccessResponse.ts +17 -0
- package/templates/layers/node/typescript/src/utils/apiResponse.ts +4 -0
- package/templates/layers/node/typescript/src/utils/asyncHandler.ts +13 -0
- package/templates/layers/node/typescript/src/utils/cloudinaryUpload.ts +18 -7
- package/templates/layers/node/typescript/src/utils/expoNotification.ts +1 -1
- package/templates/layers/node/typescript/src/utils/genOtpToken.ts +7 -1
- package/templates/layers/node/typescript/src/utils/jwt.ts +8 -2
- package/templates/layers/node/typescript/src/utils/logger.ts +2 -1
- package/templates/layers/node/typescript/src/utils/pushHelper.ts +13 -9
- package/templates/layers/node-prisma/javascript/.env.example +3 -1
- package/templates/layers/node-prisma/javascript/package.json +11 -2
- package/templates/layers/node-prisma/javascript/src/app.js +2 -1
- package/templates/layers/node-prisma/javascript/src/controllers/auth.controller.js +90 -135
- package/templates/layers/node-prisma/javascript/src/controllers/push.controller.js +64 -76
- package/templates/layers/node-prisma/javascript/src/controllers/upload.controller.js +12 -19
- package/templates/layers/node-prisma/javascript/src/middleware/auth.middleware.js +5 -4
- package/templates/layers/node-prisma/javascript/src/middleware/errorHandler.js +6 -4
- package/templates/layers/node-prisma/javascript/src/routes/auth.route.js +2 -0
- package/templates/layers/node-prisma/javascript/src/services/auth.service.js +145 -122
- package/templates/layers/node-prisma/javascript/src/utils/ApiError.js +20 -0
- package/templates/layers/node-prisma/javascript/src/utils/SuccessResponse.js +15 -0
- package/templates/layers/node-prisma/javascript/src/utils/apiResponse.js +4 -0
- package/templates/layers/node-prisma/javascript/src/utils/asyncHandler.js +5 -0
- package/templates/layers/node-prisma/typescript/.env.example +3 -1
- package/templates/layers/node-prisma/typescript/.eslintrc.cjs +28 -0
- package/templates/layers/node-prisma/typescript/package.json +19 -5
- package/templates/layers/node-prisma/typescript/src/app.ts +3 -2
- package/templates/layers/node-prisma/typescript/src/config/prisma.ts +3 -2
- package/templates/layers/node-prisma/typescript/src/config/socket.ts +5 -4
- package/templates/layers/node-prisma/typescript/src/controllers/auth.controller.ts +89 -105
- package/templates/layers/node-prisma/typescript/src/controllers/push.controller.ts +67 -83
- package/templates/layers/node-prisma/typescript/src/controllers/upload.controller.ts +12 -19
- package/templates/layers/node-prisma/typescript/src/middleware/auth.middleware.ts +9 -13
- package/templates/layers/node-prisma/typescript/src/middleware/errorHandler.ts +18 -5
- package/templates/layers/node-prisma/typescript/src/middleware/rateLimiter.ts +2 -2
- package/templates/layers/node-prisma/typescript/src/routes/auth.route.ts +2 -0
- package/templates/layers/node-prisma/typescript/src/services/auth.service.ts +83 -31
- package/templates/layers/node-prisma/typescript/src/types/express.d.ts +5 -3
- package/templates/layers/node-prisma/typescript/src/utils/ApiError.ts +25 -0
- package/templates/layers/node-prisma/typescript/src/utils/SuccessResponse.ts +17 -0
- package/templates/layers/node-prisma/typescript/src/utils/apiResponse.ts +4 -0
- package/templates/layers/node-prisma/typescript/src/utils/asyncHandler.ts +13 -0
- package/templates/layers/node-prisma/typescript/src/utils/cloudinaryUpload.ts +18 -7
- package/templates/layers/node-prisma/typescript/src/utils/genOtpToken.ts +7 -1
- package/templates/layers/node-prisma/typescript/src/utils/jwt.ts +8 -2
- package/templates/layers/node-prisma/typescript/src/utils/logger.ts +2 -1
- package/templates/layers/node-prisma/typescript/src/utils/pushHelper.ts +10 -6
- package/templates/layers/prisma/javascript/package.json +8 -0
- package/templates/layers/prisma/typescript/package.json +14 -1
- package/templates/layers/prisma/typescript/src/config/db.ts +3 -2
- package/templates/layers/react/javascript/package.json +6 -0
- package/templates/layers/react/typescript/.eslintrc.cjs +20 -0
- package/templates/layers/react/typescript/package.json +11 -2
- package/templates/layers/react/typescript/src/components/common/Table.tsx +4 -4
- package/templates/layers/react/typescript/src/components/ui/Sidebar.tsx +1 -1
- package/templates/layers/react/typescript/src/main.tsx +11 -11
- package/templates/layers/react/typescript/src/services/authService.ts +1 -1
- package/templates/layers/react/typescript/src/store/useAuthStore.ts +24 -9
- package/templates/layers/react-native/base/app.json +9 -22
- package/templates/layers/react-native/base/eslint.config.js +5 -1
- package/templates/layers/react-native/base/package.json +40 -33
- package/templates/layers/react-native/base/src/app/(auth)/edit-profile.tsx +7 -7
- package/templates/layers/react-native/base/src/app/(auth)/login.tsx +31 -7
- package/templates/layers/react-native/base/src/app/(tabs)/_layout.tsx +3 -3
- package/templates/layers/react-native/base/src/app/(tabs)/index.tsx +6 -5
- package/templates/layers/react-native/base/src/app/_layout.tsx +4 -8
- package/templates/layers/react-native/base/src/app/screens/doc-viewer.tsx +378 -0
- package/templates/layers/react-native/base/src/components/common/ConfirmationToast.tsx +58 -40
- package/templates/layers/react-native/base/src/components/common/GoogleAuthButton.tsx +123 -0
- package/templates/layers/react-native/base/src/components/common/LocationLoader.tsx +64 -9
- package/templates/layers/react-native/base/src/components/common/Typography.tsx +54 -19
- package/templates/layers/react-native/base/src/components/ui/BiometricLock.tsx +3 -3
- package/templates/layers/react-native/base/src/components/ui/ClassicTabBar.tsx +15 -12
- package/templates/layers/react-native/base/src/components/ui/CustomTabBar.tsx +90 -91
- package/templates/layers/react-native/base/src/components/ui/Drawer.tsx +344 -0
- package/templates/layers/react-native/base/src/components/ui/Sidebar.tsx +4 -4
- package/templates/layers/react-native/base/src/components/ui/buttons/Button.tsx +29 -6
- package/templates/layers/react-native/base/src/components/ui/data-display/Accordion.tsx +2 -2
- package/templates/layers/react-native/base/src/components/ui/data-display/Badge.tsx +1 -2
- package/templates/layers/react-native/base/src/components/ui/data-display/Image.tsx +3 -3
- package/templates/layers/react-native/base/src/components/ui/data-display/SwipeableRow.tsx +28 -7
- package/templates/layers/react-native/base/src/components/ui/feedback/GestureWrapper.tsx +11 -4
- package/templates/layers/react-native/base/src/components/ui/inputs/DatePicker.tsx +3 -3
- package/templates/layers/react-native/base/src/components/ui/inputs/ImagePickerModal.tsx +45 -19
- package/templates/layers/react-native/base/src/components/ui/inputs/Input.tsx +28 -9
- package/templates/layers/react-native/base/src/components/ui/inputs/SearchablePicker.tsx +199 -0
- package/templates/layers/react-native/base/src/components/ui/inputs/Switch.tsx +7 -7
- package/templates/layers/react-native/base/src/components/ui/inputs/WebLocationPicker.tsx +146 -72
- package/templates/layers/react-native/base/src/config/api.ts +5 -5
- package/templates/layers/react-native/base/src/services/auth.service.ts +3 -1
- package/templates/layers/react-native/base/src/services/permission.service.ts +168 -44
- package/templates/layers/react-native/base/src/services/socket.service.ts +0 -7
- package/templates/layers/react-native/base/src/store/useAuthStore.ts +61 -16
- package/templates/layers/react-native/base/src/store/useNotificationStore.ts +36 -42
- package/templates/layers/react-native/base/src/types/images.d.ts +7 -5
- package/templates/layers/react-native/base/src/utils/env.ts +47 -0
- package/templates/layers/react-native/base/src/utils/fileDownload.ts +206 -0
- package/templates/layers/react-native/base/src/utils/storage.ts +1 -1
- package/templates/presets/production-fullstack/overrides/client/package.json +9 -0
- package/templates/presets/production-fullstack/overrides/mobile/app.json +2 -15
- package/templates/presets/production-fullstack/overrides/mobile/package.json +39 -29
- package/templates/presets/production-fullstack/overrides/mobile/src/app/_layout.tsx +3 -3
- package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/Drawer.tsx +344 -0
- package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/DatePicker.tsx +3 -3
- package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/ImagePickerModal.tsx +3 -3
- package/templates/presets/production-fullstack/overrides/mobile/src/services/permission.service.ts +168 -44
- package/templates/presets/production-fullstack/overrides/mobile/src/store/useNotificationStore.ts +16 -0
- package/templates/presets/production-fullstack/overrides/mobile/src/utils/env.ts +47 -0
- package/templates/presets/production-fullstack/overrides/server/package.json +11 -2
- package/templates/layers/react-native/base/src/app/doc-viewer.tsx +0 -193
- package/templates/layers/react-native/base/src/components/ui/BottomModal.tsx +0 -176
- package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/BottomModal.tsx +0 -159
- /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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
await prisma.otp.delete({
|
|
67
|
-
where: { email },
|
|
68
|
-
});
|
|
69
|
-
}
|
|
68
|
+
}
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
const otp = Math.floor(100000 + Math.random() * 900000).toString();
|
|
71
|
+
const hashedOtp = await bcrypt.hash(otp, 10);
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
await prisma.otp.create({
|
|
74
|
+
data: {
|
|
75
|
+
email,
|
|
76
|
+
otp: hashedOtp,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
122
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
err
|
|
127
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
updateData.avatarUrl = uploadResult.url;
|
|
140
|
+
updateData.avatarPublicId = uploadResult.publicId;
|
|
141
|
+
}
|
|
133
142
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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,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
|
-
"@
|
|
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
|
|
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
|
|
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:
|
|
19
|
-
|
|
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:
|
|
5
|
+
let io: SocketIOServer;
|
|
5
6
|
|
|
6
7
|
const userSocketMap: { [key: string]: Set<string> } = {};
|
|
7
8
|
|
|
8
|
-
const initializeSocket = (server:
|
|
9
|
-
io = new
|
|
9
|
+
const initializeSocket = (server: HttpServer) => {
|
|
10
|
+
io = new SocketIOServer(server, {
|
|
10
11
|
cors: {
|
|
11
12
|
origin: ["http://localhost:5173"],
|
|
12
13
|
credentials: true,
|