@imksh/create 1.0.30 → 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.
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/commands/create.js +2 -0
- package/src/index.js +1 -1
- package/src/utils/askTemplate.js +2 -1
- package/templates/layers/electron/base/electron/main.js +262 -0
- package/templates/layers/electron/base/electron/preload.js +37 -0
- package/templates/layers/electron/base/electron-builder.json5 +68 -0
- package/templates/layers/electron/javascript/_gitignore +38 -0
- package/templates/layers/electron/javascript/package.json +49 -0
- package/templates/layers/electron/javascript/src/components/layout/SidebarLayout.jsx +43 -0
- package/templates/layers/electron/javascript/src/components/ui/TitleBar.jsx +130 -0
- package/templates/layers/electron/javascript/src/config/appConfig.js +51 -0
- package/templates/layers/electron/javascript/src/hooks/useElectron.js +68 -0
- package/templates/layers/electron/javascript/src/main.jsx +17 -0
- package/templates/layers/electron/javascript/src/store/useUiStore.js +59 -0
- package/templates/layers/electron/javascript/vite.config.js +29 -0
- package/templates/layers/electron/typescript/_gitignore +38 -0
- package/templates/layers/electron/typescript/electron/main.ts +213 -0
- package/templates/layers/electron/typescript/electron/preload.ts +52 -0
- package/templates/layers/electron/typescript/package.json +52 -0
- package/templates/layers/electron/typescript/src/components/layout/SidebarLayout.tsx +42 -0
- package/templates/layers/electron/typescript/src/components/ui/TitleBar.tsx +120 -0
- package/templates/layers/electron/typescript/src/config/appConfig.ts +52 -0
- package/templates/layers/electron/typescript/src/hooks/useElectron.ts +68 -0
- package/templates/layers/electron/typescript/src/main.tsx +17 -0
- package/templates/layers/electron/typescript/src/store/useUiStore.ts +97 -0
- package/templates/layers/electron/typescript/src/vite-env.d.ts +13 -0
- package/templates/layers/electron/typescript/tsconfig.json +25 -0
- package/templates/layers/electron/typescript/tsconfig.node.json +11 -0
- package/templates/layers/electron/typescript/vite.config.ts +29 -0
- package/templates/layers/next/javascript/package.json +8 -2
- package/templates/layers/next/javascript/src/components/common/Breadcrumbs.jsx +44 -6
- package/templates/layers/next/javascript/src/components/common/Loading.jsx +1 -0
- package/templates/layers/next/javascript/src/components/common/LottieIcon.jsx +1 -0
- package/templates/layers/next/javascript/src/components/common/Pagination.jsx +170 -0
- package/templates/layers/next/javascript/src/components/common/SidebarModal.jsx +180 -0
- package/templates/layers/next/javascript/src/components/common/StatsCard.jsx +168 -0
- package/templates/layers/next/javascript/src/components/common/Table.jsx +191 -41
- package/templates/layers/next/javascript/src/components/common/Tabs.jsx +187 -0
- package/templates/layers/next/javascript/src/components/common/ToggleSwitch.jsx +4 -3
- package/templates/layers/next/javascript/src/components/layout/ProtectedRoute.jsx +2 -1
- package/templates/layers/next/javascript/src/components/layout/PublicLayout.jsx +3 -6
- package/templates/layers/next/javascript/src/components/layout/SidebarLayout.jsx +4 -17
- package/templates/layers/next/javascript/src/components/modals/ConfirmModal.jsx +4 -12
- package/templates/layers/next/javascript/src/components/modals/Modal.jsx +50 -19
- package/templates/layers/next/javascript/src/components/ui/Input.jsx +50 -0
- package/templates/layers/next/{typescript/src/components/ui/sidebar.tsx → javascript/src/components/ui/Sidebar.jsx} +65 -53
- package/templates/layers/next/javascript/src/components/ui/SidebarHeader.jsx +11 -6
- package/templates/layers/next/javascript/src/config/appConfig.js +4 -4
- package/templates/layers/next/javascript/src/hooks/useWindowSize.js +2 -3
- package/templates/layers/next/javascript/src/store/useUiStore.js +9 -4
- 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/Breadcrumbs.tsx +57 -8
- package/templates/layers/next/typescript/src/components/common/Loading.tsx +2 -1
- package/templates/layers/next/typescript/src/components/common/LottieIcon.tsx +2 -2
- package/templates/layers/next/typescript/src/components/common/Pagination.tsx +186 -0
- package/templates/layers/next/typescript/src/components/common/SidebarModal.tsx +200 -0
- package/templates/layers/next/typescript/src/components/common/StatsCard.tsx +232 -0
- package/templates/layers/next/typescript/src/components/common/Table.tsx +205 -39
- package/templates/layers/next/typescript/src/components/common/Tabs.tsx +190 -0
- package/templates/layers/next/typescript/src/components/common/ToggleSwitch.tsx +12 -8
- package/templates/layers/next/typescript/src/components/layout/PublicLayout.tsx +8 -6
- package/templates/layers/next/typescript/src/components/layout/SidebarLayout.tsx +8 -17
- package/templates/layers/next/typescript/src/components/modals/ConfirmModal.tsx +3 -1
- package/templates/layers/next/typescript/src/components/modals/Modal.tsx +67 -21
- package/templates/layers/next/typescript/src/components/ui/Button.tsx +1 -0
- package/templates/layers/next/typescript/src/components/ui/Header.tsx +2 -2
- package/templates/layers/next/typescript/src/components/ui/Input.tsx +40 -60
- package/templates/layers/next/{javascript/src/components/ui/sidebar.jsx → typescript/src/components/ui/Sidebar.tsx} +77 -44
- package/templates/layers/next/typescript/src/components/ui/SidebarHeader.tsx +16 -10
- package/templates/layers/next/typescript/src/config/appConfig.ts +4 -4
- package/templates/layers/next/typescript/src/hooks/usePwaInstall.ts +10 -4
- package/templates/layers/next/typescript/src/hooks/useWindowSize.ts +2 -3
- 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/next/typescript/src/store/useUiStore.ts +14 -4
- 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-lock.json +2 -2
- package/templates/layers/node/typescript/package.json +17 -3
- 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/prisma/schema.prisma +35 -10
- package/templates/layers/prisma/typescript/src/config/db.ts +3 -2
- package/templates/layers/react/javascript/package.json +6 -0
- package/templates/layers/react/javascript/src/components/common/Breadcrumbs.jsx +62 -58
- package/templates/layers/react/javascript/src/components/common/Pagination.jsx +164 -76
- package/templates/layers/react/javascript/src/components/common/SidebarModal.jsx +179 -0
- package/templates/layers/react/javascript/src/components/common/StatsCard.jsx +167 -0
- package/templates/layers/react/javascript/src/components/common/Table.jsx +248 -132
- package/templates/layers/react/javascript/src/components/common/Tabs.jsx +164 -112
- package/templates/layers/react/javascript/src/components/common/ToggleSwitch.jsx +3 -3
- package/templates/layers/react/javascript/src/components/layout/SidebarLayout.jsx +4 -12
- package/templates/layers/react/javascript/src/components/modals/Modal.jsx +53 -18
- package/templates/layers/react/javascript/src/components/ui/Input.jsx +49 -0
- package/templates/layers/react/javascript/src/components/ui/Sidebar.jsx +215 -0
- package/templates/layers/react/javascript/src/components/ui/SidebarHeader.jsx +25 -30
- package/templates/layers/react/javascript/src/config/appConfig.js +3 -3
- package/templates/layers/react/javascript/src/hooks/useWindowSize.js +2 -2
- 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/Breadcrumbs.tsx +32 -6
- package/templates/layers/react/typescript/src/components/common/Pagination.tsx +151 -57
- package/templates/layers/react/typescript/src/components/common/SidebarModal.tsx +199 -0
- package/templates/layers/react/typescript/src/components/common/StatsCard.tsx +231 -0
- package/templates/layers/react/typescript/src/components/common/Table.tsx +201 -38
- package/templates/layers/react/typescript/src/components/common/Tabs.tsx +56 -12
- package/templates/layers/react/typescript/src/components/common/ToggleSwitch.tsx +15 -3
- package/templates/layers/react/typescript/src/components/layout/SidebarLayout.tsx +3 -6
- package/templates/layers/react/typescript/src/components/modals/Modal.tsx +151 -0
- package/templates/layers/react/typescript/src/components/ui/Input.tsx +58 -0
- package/templates/layers/react/typescript/src/components/ui/Sidebar.tsx +116 -53
- package/templates/layers/react/typescript/src/components/ui/SidebarHeader.tsx +5 -4
- package/templates/layers/react/typescript/src/config/appConfig.ts +3 -3
- package/templates/layers/react/typescript/src/hooks/useWindowSize.ts +2 -3
- 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 +11 -1
- 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 +3 -3
- package/templates/layers/react-native/base/src/app/doc-viewer.tsx +3 -3
- package/templates/layers/react-native/base/src/components/common/ConfirmationToast.tsx +58 -40
- package/templates/layers/react-native/base/src/components/common/GoogleAuthButton.tsx +144 -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/ClassicTabBar.tsx +15 -12
- package/templates/layers/react-native/base/src/components/ui/CustomTabBar.tsx +84 -90
- 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/config/appConfig.ts +1 -1
- package/templates/layers/react-native/base/src/services/auth.service.ts +3 -1
- package/templates/layers/react-native/base/src/services/permission.service.ts +0 -2
- 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/fileDownload.ts +206 -0
- package/templates/layers/react-native/base/src/utils/storage.ts +1 -1
- package/templates/presets/electron/preset.json +9 -0
- package/templates/presets/electron-ts/preset.json +9 -0
- 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 +11 -1
- 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/server/package.json +11 -2
- package/templates/layers/react/javascript/src/components/ui/sidebar.jsx +0 -169
- 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,154 +1,126 @@
|
|
|
1
|
-
import { Request, Response
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
2
|
import * as authService from "../services/auth.service.js";
|
|
3
3
|
import { generateToken } from "../utils/jwt.js";
|
|
4
4
|
import genOtpToken from "../utils/genOtpToken.js";
|
|
5
|
-
import
|
|
5
|
+
import { asyncHandler } from "../utils/asyncHandler.js";
|
|
6
|
+
import { SuccessResponse } from "../utils/SuccessResponse.js";
|
|
7
|
+
import { ApiError } from "../utils/ApiError.js";
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const token = await generateToken(newUser, res);
|
|
15
|
-
const safeUser: any = newUser.toObject();
|
|
16
|
-
delete safeUser.password;
|
|
17
|
-
res.status(201).json({ message: "Registration Successful", data: safeUser, token });
|
|
18
|
-
} catch (error) {
|
|
19
|
-
logger.error("Error in signup controller", error);
|
|
20
|
-
next(error);
|
|
21
|
-
}
|
|
9
|
+
const toSafeUser = (user: unknown): Record<string, unknown> => {
|
|
10
|
+
const obj: Record<string, unknown> =
|
|
11
|
+
user && typeof user === "object" && "toObject" in user && typeof (user as { toObject: () => unknown }).toObject === "function"
|
|
12
|
+
? { ...((user as { toObject: () => Record<string, unknown> }).toObject()) }
|
|
13
|
+
: { ...((user as Record<string, unknown>) || {}) };
|
|
14
|
+
delete obj.password;
|
|
15
|
+
return obj;
|
|
22
16
|
};
|
|
23
17
|
|
|
24
|
-
export const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return next({ status: 400, message: "All fields are required." });
|
|
29
|
-
}
|
|
30
|
-
const user = await authService.login({ email, password });
|
|
31
|
-
const token = await generateToken(user, res);
|
|
32
|
-
const safeUser: any = user.toObject();
|
|
33
|
-
delete safeUser.password;
|
|
34
|
-
res.status(200).json({ message: "Login successfully", data: safeUser, token });
|
|
35
|
-
} catch (error) {
|
|
36
|
-
logger.error("Error in login controller", error);
|
|
37
|
-
next(error);
|
|
18
|
+
export const signup = asyncHandler(async (req: Request, res: Response) => {
|
|
19
|
+
const { name, email, phone, password, otp } = req.body;
|
|
20
|
+
if (!email || !password || !name || !otp) {
|
|
21
|
+
throw new ApiError(400, "All fields are required.");
|
|
38
22
|
}
|
|
39
|
-
};
|
|
23
|
+
const newUser = await authService.signup({ name, email, phone, password, otp });
|
|
24
|
+
const token = await generateToken(newUser, res);
|
|
25
|
+
const safeUser = toSafeUser(newUser);
|
|
26
|
+
SuccessResponse(res, 201, "Registration Successful", { user: safeUser, token });
|
|
27
|
+
});
|
|
40
28
|
|
|
41
|
-
export const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
secure: process.env.NODE_ENV === "production",
|
|
46
|
-
sameSite: "strict",
|
|
47
|
-
path: "/",
|
|
48
|
-
});
|
|
49
|
-
res.status(200).json({ message: "Logout Successfully" });
|
|
50
|
-
} catch (error) {
|
|
51
|
-
logger.error("Error in logout controller", error);
|
|
52
|
-
next(error);
|
|
29
|
+
export const login = asyncHandler(async (req: Request, res: Response) => {
|
|
30
|
+
const { email, password } = req.body;
|
|
31
|
+
if (!email || !password) {
|
|
32
|
+
throw new ApiError(400, "All fields are required.");
|
|
53
33
|
}
|
|
54
|
-
};
|
|
34
|
+
const user = await authService.login({ email, password });
|
|
35
|
+
const token = await generateToken(user, res);
|
|
36
|
+
const safeUser = toSafeUser(user);
|
|
37
|
+
SuccessResponse(res, 200, "Login successfully", { user: safeUser, token });
|
|
38
|
+
});
|
|
55
39
|
|
|
56
|
-
export const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
40
|
+
export const logout = asyncHandler(async (req: Request, res: Response) => {
|
|
41
|
+
res.clearCookie("token", {
|
|
42
|
+
httpOnly: true,
|
|
43
|
+
secure: process.env.NODE_ENV === "production",
|
|
44
|
+
sameSite: "strict",
|
|
45
|
+
path: "/",
|
|
46
|
+
});
|
|
47
|
+
SuccessResponse(res, 200, "Logout Successfully");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const getMe = asyncHandler(async (req: Request, res: Response) => {
|
|
51
|
+
const safeUser = toSafeUser(req.user);
|
|
52
|
+
SuccessResponse(res, 200, "User Authenticated", safeUser);
|
|
53
|
+
});
|
|
66
54
|
|
|
67
|
-
export const genSignupOtp = async (req: Request, res: Response
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return next({ status: 400, message: "Email is required." });
|
|
72
|
-
}
|
|
73
|
-
await authService.generateSignupOtp(email);
|
|
74
|
-
res.status(200).json({ message: "Signup Otp sent successfully" });
|
|
75
|
-
} catch (error) {
|
|
76
|
-
logger.error("Error in genSignupOtp", error);
|
|
77
|
-
next(error);
|
|
55
|
+
export const genSignupOtp = asyncHandler(async (req: Request, res: Response) => {
|
|
56
|
+
const { email } = req.body;
|
|
57
|
+
if (!email) {
|
|
58
|
+
throw new ApiError(400, "Email is required.");
|
|
78
59
|
}
|
|
79
|
-
|
|
60
|
+
await authService.generateSignupOtp(email);
|
|
61
|
+
SuccessResponse(res, 200, "Signup Otp sent successfully");
|
|
62
|
+
});
|
|
80
63
|
|
|
81
|
-
export const genOtp = async (req: Request, res: Response
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return next({ status: 400, message: "Email is required." });
|
|
86
|
-
}
|
|
87
|
-
await authService.generateOtp(email);
|
|
88
|
-
res.status(200).json({ message: "Otp sent successfully" });
|
|
89
|
-
} catch (error) {
|
|
90
|
-
logger.error("Error in genOtp", error);
|
|
91
|
-
next(error);
|
|
64
|
+
export const genOtp = asyncHandler(async (req: Request, res: Response) => {
|
|
65
|
+
const { email } = req.body;
|
|
66
|
+
if (!email) {
|
|
67
|
+
throw new ApiError(400, "Email is required.");
|
|
92
68
|
}
|
|
93
|
-
|
|
69
|
+
await authService.generateOtp(email);
|
|
70
|
+
SuccessResponse(res, 200, "Otp sent successfully");
|
|
71
|
+
});
|
|
94
72
|
|
|
95
|
-
export const verifyOtp = async (req: Request, res: Response
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return next({ status: 400, message: "All fields are required." });
|
|
100
|
-
}
|
|
101
|
-
const user = await authService.verifyOtp({ email, otp });
|
|
102
|
-
await genOtpToken(user, res);
|
|
103
|
-
res.status(200).json({ message: "Otp verified successfully" });
|
|
104
|
-
} catch (error) {
|
|
105
|
-
logger.error("Error in verifyOtp", error);
|
|
106
|
-
next(error);
|
|
73
|
+
export const verifyOtp = asyncHandler(async (req: Request, res: Response) => {
|
|
74
|
+
const { email, otp } = req.body;
|
|
75
|
+
if (!email || !otp) {
|
|
76
|
+
throw new ApiError(400, "All fields are required.");
|
|
107
77
|
}
|
|
108
|
-
};
|
|
78
|
+
const user = await authService.verifyOtp({ email, otp });
|
|
79
|
+
await genOtpToken(user, res);
|
|
80
|
+
SuccessResponse(res, 200, "Otp verified successfully");
|
|
81
|
+
});
|
|
109
82
|
|
|
110
|
-
export const resetPassword = async (req: Request, res: Response
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!newPassword) {
|
|
115
|
-
return next({ status: 400, message: "All fields are required." });
|
|
116
|
-
}
|
|
117
|
-
await authService.resetPassword(currentUser, newPassword);
|
|
118
|
-
res.status(200).json({ message: "Password updated successfully" });
|
|
119
|
-
} catch (error) {
|
|
120
|
-
logger.error("Error in resetPassword", error);
|
|
121
|
-
next(error);
|
|
83
|
+
export const resetPassword = asyncHandler(async (req: Request, res: Response) => {
|
|
84
|
+
const { newPassword } = req.body;
|
|
85
|
+
if (!newPassword) {
|
|
86
|
+
throw new ApiError(400, "All fields are required.");
|
|
122
87
|
}
|
|
123
|
-
}
|
|
88
|
+
if (!req.user || typeof (req.user as unknown as { save?: unknown }).save !== "function") {
|
|
89
|
+
throw new ApiError(401, "Not authorized");
|
|
90
|
+
}
|
|
91
|
+
await authService.resetPassword(req.user as unknown as authService.UserWithSave, newPassword);
|
|
92
|
+
SuccessResponse(res, 200, "Password updated successfully");
|
|
93
|
+
});
|
|
124
94
|
|
|
125
|
-
export const updateMe = async (req: Request, res: Response
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
95
|
+
export const updateMe = asyncHandler(async (req: Request, res: Response) => {
|
|
96
|
+
const { name, phone } = req.body;
|
|
97
|
+
const userId = String(req.user?._id || req.user?.id || "");
|
|
98
|
+
const user = await authService.updateProfile(userId, {
|
|
99
|
+
name,
|
|
100
|
+
phone,
|
|
101
|
+
file: req.file,
|
|
102
|
+
});
|
|
103
|
+
const safeUser = toSafeUser(user);
|
|
104
|
+
SuccessResponse(res, 200, "Profile updated successfully", safeUser);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export const savePushToken = asyncHandler(async (req: Request, res: Response) => {
|
|
108
|
+
const { token } = req.body;
|
|
109
|
+
if (!token) {
|
|
110
|
+
throw new ApiError(400, "Token is required.");
|
|
139
111
|
}
|
|
140
|
-
|
|
112
|
+
const userId = String(req.user?._id || req.user?.id || "");
|
|
113
|
+
await authService.savePushToken(userId, token);
|
|
114
|
+
SuccessResponse(res, 200, "Push token saved successfully");
|
|
115
|
+
});
|
|
141
116
|
|
|
142
|
-
export const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return next({ status: 400, message: "Token is required." });
|
|
147
|
-
}
|
|
148
|
-
await authService.savePushToken(req.user._id, token);
|
|
149
|
-
res.status(200).json({ success: true, message: "Push token saved successfully" });
|
|
150
|
-
} catch (error) {
|
|
151
|
-
logger.error("Error saving push token", error);
|
|
152
|
-
next(error);
|
|
117
|
+
export const googleLogin = asyncHandler(async (req: Request, res: Response) => {
|
|
118
|
+
const { idToken } = req.body;
|
|
119
|
+
if (!idToken) {
|
|
120
|
+
throw new ApiError(400, "idToken is required.");
|
|
153
121
|
}
|
|
154
|
-
|
|
122
|
+
const user = await authService.googleLogin(idToken);
|
|
123
|
+
const token = await generateToken(user, res);
|
|
124
|
+
const safeUser = toSafeUser(user);
|
|
125
|
+
SuccessResponse(res, 200, "Google Login successfully", { user: safeUser, token });
|
|
126
|
+
});
|
|
@@ -1,73 +1,66 @@
|
|
|
1
|
-
import { Request, Response
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
2
|
import PushSubscription from "../models/pushSubscription.model.js";
|
|
3
|
-
import
|
|
3
|
+
import { asyncHandler } from "../utils/asyncHandler.js";
|
|
4
|
+
import { SuccessResponse } from "../utils/SuccessResponse.js";
|
|
5
|
+
import { ApiError } from "../utils/ApiError.js";
|
|
4
6
|
|
|
5
|
-
export const subscribe = async (req: Request, res: Response
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const userId = req.user?._id || req.user?.id; // supports both mongoose and prisma IDs
|
|
9
|
-
|
|
10
|
-
if (!subscription) {
|
|
11
|
-
return next({ status: 400, message: "Invalid subscription payload" });
|
|
12
|
-
}
|
|
7
|
+
export const subscribe = asyncHandler(async (req: Request, res: Response) => {
|
|
8
|
+
const subscription = req.body;
|
|
9
|
+
const userId = req.user?._id || req.user?.id; // supports both mongoose and prisma IDs
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if (!subscription) {
|
|
12
|
+
throw new ApiError(400, "Invalid subscription payload");
|
|
13
|
+
}
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
15
|
+
const isExpo = !!subscription.token;
|
|
16
|
+
const isWeb = !!(subscription.endpoint && subscription.keys);
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (userId && String(existingSub.user) !== String(userId)) {
|
|
25
|
-
existingSub.user = userId; await existingSub.save();
|
|
26
|
-
}
|
|
27
|
-
return res.status(200).json({ success: true, message: "Already subscribed." });
|
|
28
|
-
}
|
|
18
|
+
if (!isExpo && !isWeb) {
|
|
19
|
+
throw new ApiError(400, "Missing token (EXPO) or endpoint/keys (WEB)");
|
|
20
|
+
}
|
|
29
21
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const existingSub = await PushSubscription.findOne({ endpoint: subscription.endpoint });
|
|
37
|
-
if (existingSub) {
|
|
38
|
-
if (userId && String(existingSub.user) !== String(userId)) {
|
|
39
|
-
existingSub.user = userId; await existingSub.save();
|
|
40
|
-
}
|
|
41
|
-
return res.status(200).json({ success: true, message: "Already subscribed." });
|
|
22
|
+
if (isExpo) {
|
|
23
|
+
const existingSub = await PushSubscription.findOne({ expoPushToken: subscription.token });
|
|
24
|
+
if (existingSub) {
|
|
25
|
+
if (userId && String(existingSub.user) !== String(userId)) {
|
|
26
|
+
existingSub.user = userId;
|
|
27
|
+
await existingSub.save();
|
|
42
28
|
}
|
|
29
|
+
return SuccessResponse(res, 200, "Already subscribed.");
|
|
30
|
+
}
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
await PushSubscription.create({
|
|
33
|
+
type: "EXPO",
|
|
34
|
+
expoPushToken: subscription.token,
|
|
35
|
+
user: userId || undefined,
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
const existingSub = await PushSubscription.findOne({ endpoint: subscription.endpoint });
|
|
39
|
+
if (existingSub) {
|
|
40
|
+
if (userId && String(existingSub.user) !== String(userId)) {
|
|
41
|
+
existingSub.user = userId;
|
|
42
|
+
await existingSub.save();
|
|
43
|
+
}
|
|
44
|
+
return SuccessResponse(res, 200, "Already subscribed.");
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
await PushSubscription.create({
|
|
48
|
+
type: "WEB",
|
|
49
|
+
endpoint: subscription.endpoint,
|
|
50
|
+
keys: subscription.keys,
|
|
51
|
+
user: userId || undefined,
|
|
52
|
+
});
|
|
56
53
|
}
|
|
57
|
-
};
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const { endpoint } = req.body;
|
|
62
|
-
if (!endpoint) {
|
|
63
|
-
return next({ status: 400, message: "Endpoint required" });
|
|
64
|
-
}
|
|
55
|
+
SuccessResponse(res, 201, "Subscription created.");
|
|
56
|
+
});
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
logger.error("Error in push unsubscribe controller", error);
|
|
71
|
-
next(error);
|
|
58
|
+
export const unsubscribe = asyncHandler(async (req: Request, res: Response) => {
|
|
59
|
+
const { endpoint } = req.body;
|
|
60
|
+
if (!endpoint) {
|
|
61
|
+
throw new ApiError(400, "Endpoint required");
|
|
72
62
|
}
|
|
73
|
-
|
|
63
|
+
|
|
64
|
+
await PushSubscription.deleteOne({ endpoint });
|
|
65
|
+
SuccessResponse(res, 200, "Unsubscribed.");
|
|
66
|
+
});
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import { Request, Response
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
2
|
import { uploadSingleToCloudinary } from "../utils/cloudinaryUpload.js";
|
|
3
|
-
import
|
|
3
|
+
import { asyncHandler } from "../utils/asyncHandler.js";
|
|
4
|
+
import { SuccessResponse } from "../utils/SuccessResponse.js";
|
|
5
|
+
import { ApiError } from "../utils/ApiError.js";
|
|
4
6
|
|
|
5
|
-
export const uploadFile = async (req: Request, res: Response
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return res.status(400).json({ success: false, message: "No file uploaded" });
|
|
9
|
-
}
|
|
10
|
-
const result = await uploadSingleToCloudinary(req.file, {
|
|
11
|
-
folder: req.body.folder || "general_uploads",
|
|
12
|
-
});
|
|
13
|
-
res.status(200).json({
|
|
14
|
-
success: true,
|
|
15
|
-
message: "File uploaded successfully",
|
|
16
|
-
data: result,
|
|
17
|
-
});
|
|
18
|
-
} catch (error) {
|
|
19
|
-
logger.error("Upload controller error", error);
|
|
20
|
-
next(error);
|
|
7
|
+
export const uploadFile = asyncHandler(async (req: Request, res: Response) => {
|
|
8
|
+
if (!req.file) {
|
|
9
|
+
throw new ApiError(400, "No file uploaded");
|
|
21
10
|
}
|
|
22
|
-
|
|
11
|
+
const result = await uploadSingleToCloudinary(req.file, {
|
|
12
|
+
folder: req.body.folder || "general_uploads",
|
|
13
|
+
});
|
|
14
|
+
SuccessResponse(res, 200, "File uploaded successfully", result);
|
|
15
|
+
});
|
|
@@ -2,8 +2,14 @@ import { Request, Response, NextFunction } from "express";
|
|
|
2
2
|
import User from "../models/user.model.js";
|
|
3
3
|
import { verifyToken } from "../utils/jwt.js";
|
|
4
4
|
import logger from "../utils/logger.js";
|
|
5
|
+
import { ApiError } from "../utils/ApiError.js";
|
|
5
6
|
|
|
6
|
-
export const protect = async (
|
|
7
|
+
export const protect = async (
|
|
8
|
+
req: Request,
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10
|
+
res: Response,
|
|
11
|
+
next: NextFunction
|
|
12
|
+
) => {
|
|
7
13
|
let token: string | undefined;
|
|
8
14
|
|
|
9
15
|
if (req.cookies?.token) {
|
|
@@ -16,23 +22,23 @@ export const protect = async (req: Request, res: Response, next: NextFunction) =
|
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
if (!token) {
|
|
19
|
-
return
|
|
25
|
+
return next(new ApiError(401, "Not authorized, no token provided"));
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
try {
|
|
23
|
-
const decoded
|
|
29
|
+
const decoded = verifyToken(token) as { id: string } | null;
|
|
24
30
|
if (!decoded) {
|
|
25
|
-
return
|
|
31
|
+
return next(new ApiError(401, "Not authorized, invalid token"));
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
req.user = await User.findById(decoded.id).select("-password");
|
|
29
35
|
if (!req.user) {
|
|
30
|
-
return
|
|
36
|
+
return next(new ApiError(401, "Not authorized, user not found"));
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
return next();
|
|
34
|
-
} catch (error:
|
|
40
|
+
} catch (error: unknown) {
|
|
35
41
|
logger.error("Auth middleware error", error);
|
|
36
|
-
return
|
|
42
|
+
return next(new ApiError(401, "Not authorized, token verification failed"));
|
|
37
43
|
}
|
|
38
44
|
};
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { ApiError } from "../utils/ApiError.js";
|
|
3
|
+
|
|
4
|
+
export interface HttpError extends Error {
|
|
5
|
+
statusCode?: number;
|
|
6
|
+
status?: number;
|
|
7
|
+
errors?: unknown[];
|
|
8
|
+
}
|
|
2
9
|
|
|
3
10
|
export const notFound = (req: Request, res: Response, next: NextFunction) => {
|
|
4
|
-
|
|
5
|
-
res.status(404);
|
|
6
|
-
next(error);
|
|
11
|
+
next(new ApiError(404, `Not Found - ${req.originalUrl}`));
|
|
7
12
|
};
|
|
8
13
|
|
|
9
|
-
export const errorHandler = (
|
|
10
|
-
|
|
14
|
+
export const errorHandler = (
|
|
15
|
+
err: HttpError,
|
|
16
|
+
req: Request,
|
|
17
|
+
res: Response,
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
+
next: NextFunction,
|
|
20
|
+
) => {
|
|
21
|
+
const statusCode = err.statusCode || err.status || (res.statusCode === 200 ? 500 : res.statusCode);
|
|
11
22
|
res.status(statusCode).json({
|
|
12
23
|
success: false,
|
|
24
|
+
statusCode,
|
|
13
25
|
message: err.message || "An unexpected error occurred",
|
|
26
|
+
errors: err.errors || [],
|
|
14
27
|
stack: process.env.NODE_ENV === "production" ? undefined : err.stack,
|
|
15
28
|
});
|
|
16
29
|
};
|
|
@@ -21,8 +21,8 @@ const createLimiter = ({
|
|
|
21
21
|
legacyHeaders: false,
|
|
22
22
|
skipSuccessfulRequests,
|
|
23
23
|
|
|
24
|
-
keyGenerator: (req:
|
|
25
|
-
return req.user?.id || req.ip || req.headers["x-forwarded-for"] || req.socket.remoteAddress;
|
|
24
|
+
keyGenerator: (req: Request) => {
|
|
25
|
+
return String(req.user?.id || req.user?._id || req.ip || req.headers["x-forwarded-for"] || req.socket.remoteAddress || "unknown");
|
|
26
26
|
},
|
|
27
27
|
|
|
28
28
|
handler: (req: Request, res: Response) => {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
updateMe,
|
|
8
8
|
genSignupOtp,
|
|
9
9
|
savePushToken,
|
|
10
|
+
googleLogin,
|
|
10
11
|
} from "../controllers/auth.controller.js";
|
|
11
12
|
import { protect } from "../middleware/auth.middleware.js";
|
|
12
13
|
import { apiLimiter } from "../middleware/rateLimiter.js";
|
|
@@ -18,6 +19,7 @@ router.use(apiLimiter);
|
|
|
18
19
|
router.post("/send-signup-otp", genSignupOtp);
|
|
19
20
|
router.post("/signup", signup);
|
|
20
21
|
router.post("/login", login);
|
|
22
|
+
router.post("/google", googleLogin);
|
|
21
23
|
router.post("/logout", logout);
|
|
22
24
|
router.get("/me", protect, getMe);
|
|
23
25
|
router.put("/me", protect, updateMe);
|