@imksh/create 1.0.0
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 +88 -0
- package/bin/index.js +3 -0
- package/package.json +43 -0
- package/src/commands/create.js +90 -0
- package/src/index.js +41 -0
- package/src/utils/askTemplate.js +25 -0
- package/src/utils/copyTemplate.js +36 -0
- package/src/utils/installPackages.js +25 -0
- package/src/utils/logger.js +17 -0
- package/src/utils/runGit.js +11 -0
- package/templates/mern/_gitignore +2 -0
- package/templates/mern/client/_gitignore +24 -0
- package/templates/mern/client/index.html +14 -0
- package/templates/mern/client/package.json +39 -0
- package/templates/mern/client/public/_redirects +1 -0
- package/templates/mern/client/public/favicon.ico +0 -0
- package/templates/mern/client/public/favicon.svg +1 -0
- package/templates/mern/client/public/logo.png +0 -0
- package/templates/mern/client/public/manifest.json +24 -0
- package/templates/mern/client/public/sw.js +56 -0
- package/templates/mern/client/src/App.jsx +68 -0
- package/templates/mern/client/src/assets/animations/loading.json +1 -0
- package/templates/mern/client/src/assets/data/navigation.js +29 -0
- package/templates/mern/client/src/assets/images/logo.png +0 -0
- package/templates/mern/client/src/components/common/Breadcrumbs.jsx +27 -0
- package/templates/mern/client/src/components/common/Loading.jsx +19 -0
- package/templates/mern/client/src/components/common/LottieIcon.jsx +36 -0
- package/templates/mern/client/src/components/common/NotFound.jsx +78 -0
- package/templates/mern/client/src/components/common/PwaInstallPrompt.jsx +72 -0
- package/templates/mern/client/src/components/common/SEO.jsx +67 -0
- package/templates/mern/client/src/components/common/Scroll.jsx +25 -0
- package/templates/mern/client/src/components/common/Table.jsx +110 -0
- package/templates/mern/client/src/components/common/ToggleSwitch.jsx +38 -0
- package/templates/mern/client/src/components/common/Unauthorized.jsx +76 -0
- package/templates/mern/client/src/components/layout/ProtectedRoute.jsx +17 -0
- package/templates/mern/client/src/components/layout/PublicLayout.jsx +13 -0
- package/templates/mern/client/src/components/layout/SidebarLayout.jsx +37 -0
- package/templates/mern/client/src/components/modals/ConfirmModal.jsx +135 -0
- package/templates/mern/client/src/components/modals/Modal.jsx +94 -0
- package/templates/mern/client/src/components/skeletons/common/CardSkeleton.jsx +23 -0
- package/templates/mern/client/src/components/skeletons/common/DashboardSkeleton.jsx +19 -0
- package/templates/mern/client/src/components/skeletons/common/ListSkeleton.jsx +24 -0
- package/templates/mern/client/src/components/skeletons/common/PageSkeleton.jsx +26 -0
- package/templates/mern/client/src/components/skeletons/common/ProfileSkeleton.jsx +23 -0
- package/templates/mern/client/src/components/skeletons/common/Skeleton.jsx +18 -0
- package/templates/mern/client/src/components/skeletons/common/TableSkeleton.jsx +33 -0
- package/templates/mern/client/src/components/ui/Header.jsx +230 -0
- package/templates/mern/client/src/components/ui/SidebarHeader.jsx +27 -0
- package/templates/mern/client/src/components/ui/sidebar.jsx +152 -0
- package/templates/mern/client/src/config/api.js +22 -0
- package/templates/mern/client/src/config/appConfig.js +44 -0
- package/templates/mern/client/src/config/navigation.js +14 -0
- package/templates/mern/client/src/hooks/useLenis.js +28 -0
- package/templates/mern/client/src/hooks/usePwaInstall.js +45 -0
- package/templates/mern/client/src/hooks/useWindowSize.js +25 -0
- package/templates/mern/client/src/index.css +158 -0
- package/templates/mern/client/src/main.jsx +24 -0
- package/templates/mern/client/src/pages/Home.jsx +154 -0
- package/templates/mern/client/src/pages/Login.jsx +196 -0
- package/templates/mern/client/src/pages/Profile.jsx +9 -0
- package/templates/mern/client/src/services/authService.js +16 -0
- package/templates/mern/client/src/store/useAuthStore.js +98 -0
- package/templates/mern/client/src/store/useUiStore.js +54 -0
- package/templates/mern/client/src/utils/getInitials.js +10 -0
- package/templates/mern/client/vite.config.js +8 -0
- package/templates/mern/package.json +18 -0
- package/templates/mern/server/.env.example +62 -0
- package/templates/mern/server/README.md +65 -0
- package/templates/mern/server/_gitignore +24 -0
- package/templates/mern/server/package.json +32 -0
- package/templates/mern/server/src/app.js +42 -0
- package/templates/mern/server/src/config/cloudinary.js +9 -0
- package/templates/mern/server/src/config/db.js +14 -0
- package/templates/mern/server/src/config/dotenv.js +2 -0
- package/templates/mern/server/src/config/email.js +30 -0
- package/templates/mern/server/src/config/socket.js +54 -0
- package/templates/mern/server/src/config/webPush.js +9 -0
- package/templates/mern/server/src/controllers/auth.controller.js +153 -0
- package/templates/mern/server/src/controllers/upload.controller.js +26 -0
- package/templates/mern/server/src/index.js +24 -0
- package/templates/mern/server/src/middleware/auth.middleware.js +43 -0
- package/templates/mern/server/src/middleware/errorHandler.js +22 -0
- package/templates/mern/server/src/middleware/multer.js +21 -0
- package/templates/mern/server/src/middleware/rateLimiter.js +57 -0
- package/templates/mern/server/src/models/otp.model.js +21 -0
- package/templates/mern/server/src/models/pushSubscription.model.js +32 -0
- package/templates/mern/server/src/models/user.model.js +43 -0
- package/templates/mern/server/src/routes/auth.route.js +22 -0
- package/templates/mern/server/src/routes/index.js +10 -0
- package/templates/mern/server/src/routes/upload.route.js +12 -0
- package/templates/mern/server/src/services/auth.service.js +162 -0
- package/templates/mern/server/src/services/auth.service.ts +0 -0
- package/templates/mern/server/src/utils/authToken.js +26 -0
- package/templates/mern/server/src/utils/cloudinary.js +27 -0
- package/templates/mern/server/src/utils/cloudinaryUpload.js +87 -0
- package/templates/mern/server/src/utils/emailOtp.js +190 -0
- package/templates/mern/server/src/utils/genOtpToken.js +20 -0
- package/templates/mern/server/src/utils/generateVapidKeys.js +12 -0
- package/templates/mern/server/src/utils/jwt.js +25 -0
- package/templates/mern/server/src/utils/logger.js +25 -0
- package/templates/mern-ts/_gitignore +2 -0
- package/templates/mern-ts/client/_gitignore +24 -0
- package/templates/mern-ts/client/index.html +14 -0
- package/templates/mern-ts/client/package.json +45 -0
- package/templates/mern-ts/client/public/_redirects +1 -0
- package/templates/mern-ts/client/public/favicon.ico +0 -0
- package/templates/mern-ts/client/public/favicon.svg +1 -0
- package/templates/mern-ts/client/public/logo.png +0 -0
- package/templates/mern-ts/client/public/manifest.json +24 -0
- package/templates/mern-ts/client/public/sw.js +56 -0
- package/templates/mern-ts/client/src/App.tsx +68 -0
- package/templates/mern-ts/client/src/assets/animations/loading.json +1 -0
- package/templates/mern-ts/client/src/assets/data/navigation.ts +29 -0
- package/templates/mern-ts/client/src/assets/images/logo.png +0 -0
- package/templates/mern-ts/client/src/components/common/Breadcrumbs.tsx +27 -0
- package/templates/mern-ts/client/src/components/common/Loading.tsx +19 -0
- package/templates/mern-ts/client/src/components/common/LottieIcon.tsx +36 -0
- package/templates/mern-ts/client/src/components/common/NotFound.tsx +78 -0
- package/templates/mern-ts/client/src/components/common/PwaInstallPrompt.tsx +72 -0
- package/templates/mern-ts/client/src/components/common/SEO.tsx +67 -0
- package/templates/mern-ts/client/src/components/common/Scroll.tsx +25 -0
- package/templates/mern-ts/client/src/components/common/Table.tsx +118 -0
- package/templates/mern-ts/client/src/components/common/ToggleSwitch.tsx +38 -0
- package/templates/mern-ts/client/src/components/common/Unauthorized.tsx +76 -0
- package/templates/mern-ts/client/src/components/layout/ProtectedRoute.tsx +23 -0
- package/templates/mern-ts/client/src/components/layout/PublicLayout.tsx +13 -0
- package/templates/mern-ts/client/src/components/layout/SidebarLayout.tsx +37 -0
- package/templates/mern-ts/client/src/components/modals/ConfirmModal.tsx +135 -0
- package/templates/mern-ts/client/src/components/modals/Modal.tsx +94 -0
- package/templates/mern-ts/client/src/components/skeletons/common/CardSkeleton.tsx +23 -0
- package/templates/mern-ts/client/src/components/skeletons/common/DashboardSkeleton.tsx +19 -0
- package/templates/mern-ts/client/src/components/skeletons/common/ListSkeleton.tsx +24 -0
- package/templates/mern-ts/client/src/components/skeletons/common/PageSkeleton.tsx +26 -0
- package/templates/mern-ts/client/src/components/skeletons/common/ProfileSkeleton.tsx +23 -0
- package/templates/mern-ts/client/src/components/skeletons/common/Skeleton.tsx +18 -0
- package/templates/mern-ts/client/src/components/skeletons/common/TableSkeleton.tsx +33 -0
- package/templates/mern-ts/client/src/components/ui/Header.tsx +230 -0
- package/templates/mern-ts/client/src/components/ui/SidebarHeader.tsx +27 -0
- package/templates/mern-ts/client/src/components/ui/sidebar.tsx +152 -0
- package/templates/mern-ts/client/src/config/api.ts +22 -0
- package/templates/mern-ts/client/src/config/appConfig.ts +44 -0
- package/templates/mern-ts/client/src/config/navigation.ts +14 -0
- package/templates/mern-ts/client/src/hooks/useLenis.ts +28 -0
- package/templates/mern-ts/client/src/hooks/usePwaInstall.ts +45 -0
- package/templates/mern-ts/client/src/hooks/useWindowSize.ts +25 -0
- package/templates/mern-ts/client/src/index.css +158 -0
- package/templates/mern-ts/client/src/main.tsx +24 -0
- package/templates/mern-ts/client/src/pages/Home.tsx +154 -0
- package/templates/mern-ts/client/src/pages/Login.tsx +196 -0
- package/templates/mern-ts/client/src/pages/Profile.tsx +9 -0
- package/templates/mern-ts/client/src/services/authService.ts +16 -0
- package/templates/mern-ts/client/src/store/useAuthStore.ts +98 -0
- package/templates/mern-ts/client/src/store/useUiStore.ts +54 -0
- package/templates/mern-ts/client/src/utils/getInitials.ts +10 -0
- package/templates/mern-ts/client/tsconfig.json +25 -0
- package/templates/mern-ts/client/tsconfig.node.json +10 -0
- package/templates/mern-ts/client/vite.config.ts +8 -0
- package/templates/mern-ts/package.json +19 -0
- package/templates/mern-ts/server/.env.example +62 -0
- package/templates/mern-ts/server/README.md +69 -0
- package/templates/mern-ts/server/_gitignore +24 -0
- package/templates/mern-ts/server/package.json +47 -0
- package/templates/mern-ts/server/src/app.ts +36 -0
- package/templates/mern-ts/server/src/config/cloudinary.ts +9 -0
- package/templates/mern-ts/server/src/config/db.ts +15 -0
- package/templates/mern-ts/server/src/config/dotenv.ts +2 -0
- package/templates/mern-ts/server/src/config/email.ts +28 -0
- package/templates/mern-ts/server/src/config/socket.ts +54 -0
- package/templates/mern-ts/server/src/config/webPush.ts +9 -0
- package/templates/mern-ts/server/src/controllers/auth.controller.ts +126 -0
- package/templates/mern-ts/server/src/controllers/upload.controller.ts +22 -0
- package/templates/mern-ts/server/src/index.ts +17 -0
- package/templates/mern-ts/server/src/middleware/auth.middleware.ts +38 -0
- package/templates/mern-ts/server/src/middleware/errorHandler.ts +16 -0
- package/templates/mern-ts/server/src/middleware/multer.ts +20 -0
- package/templates/mern-ts/server/src/middleware/rateLimiter.ts +53 -0
- package/templates/mern-ts/server/src/models/otp.model.ts +21 -0
- package/templates/mern-ts/server/src/models/pushSubscription.model.ts +32 -0
- package/templates/mern-ts/server/src/models/user.model.ts +43 -0
- package/templates/mern-ts/server/src/routes/auth.route.ts +22 -0
- package/templates/mern-ts/server/src/routes/index.ts +10 -0
- package/templates/mern-ts/server/src/routes/upload.route.ts +11 -0
- package/templates/mern-ts/server/src/services/auth.service.ts +115 -0
- package/templates/mern-ts/server/src/types/express.d.ts +10 -0
- package/templates/mern-ts/server/src/utils/cloudinaryUpload.ts +44 -0
- package/templates/mern-ts/server/src/utils/emailOtp.ts +30 -0
- package/templates/mern-ts/server/src/utils/genOtpToken.ts +22 -0
- package/templates/mern-ts/server/src/utils/generateVapidKeys.ts +12 -0
- package/templates/mern-ts/server/src/utils/jwt.ts +27 -0
- package/templates/mern-ts/server/src/utils/logger.ts +27 -0
- package/templates/mern-ts/server/tsconfig.json +14 -0
- package/templates/next/_gitignore +24 -0
- package/templates/next/package.json +20 -0
- package/templates/next/src/app/layout.js +7 -0
- package/templates/next/src/app/page.js +218 -0
- package/templates/next-ts/_gitignore +24 -0
- package/templates/next-ts/package.json +24 -0
- package/templates/next-ts/src/app/layout.tsx +9 -0
- package/templates/next-ts/src/app/page.tsx +218 -0
- package/templates/next-ts/tsconfig.json +27 -0
- package/templates/node/.env.example +62 -0
- package/templates/node/README.md +65 -0
- package/templates/node/_gitignore +24 -0
- package/templates/node/package.json +32 -0
- package/templates/node/src/app.js +42 -0
- package/templates/node/src/config/cloudinary.js +9 -0
- package/templates/node/src/config/db.js +14 -0
- package/templates/node/src/config/dotenv.js +2 -0
- package/templates/node/src/config/email.js +30 -0
- package/templates/node/src/config/socket.js +54 -0
- package/templates/node/src/config/webPush.js +9 -0
- package/templates/node/src/controllers/auth.controller.js +153 -0
- package/templates/node/src/controllers/upload.controller.js +26 -0
- package/templates/node/src/index.js +24 -0
- package/templates/node/src/middleware/auth.middleware.js +43 -0
- package/templates/node/src/middleware/errorHandler.js +22 -0
- package/templates/node/src/middleware/multer.js +21 -0
- package/templates/node/src/middleware/rateLimiter.js +57 -0
- package/templates/node/src/models/otp.model.js +21 -0
- package/templates/node/src/models/pushSubscription.model.js +32 -0
- package/templates/node/src/models/user.model.js +43 -0
- package/templates/node/src/routes/auth.route.js +22 -0
- package/templates/node/src/routes/index.js +10 -0
- package/templates/node/src/routes/upload.route.js +12 -0
- package/templates/node/src/services/auth.service.js +162 -0
- package/templates/node/src/services/auth.service.ts +0 -0
- package/templates/node/src/utils/authToken.js +26 -0
- package/templates/node/src/utils/cloudinary.js +27 -0
- package/templates/node/src/utils/cloudinaryUpload.js +87 -0
- package/templates/node/src/utils/emailOtp.js +190 -0
- package/templates/node/src/utils/genOtpToken.js +20 -0
- package/templates/node/src/utils/generateVapidKeys.js +12 -0
- package/templates/node/src/utils/jwt.js +25 -0
- package/templates/node/src/utils/logger.js +25 -0
- package/templates/node-prisma/.env.example +63 -0
- package/templates/node-prisma/README.md +69 -0
- package/templates/node-prisma/_gitignore +24 -0
- package/templates/node-prisma/package.json +35 -0
- package/templates/node-prisma/prisma/schema.prisma +41 -0
- package/templates/node-prisma/src/app.js +42 -0
- package/templates/node-prisma/src/config/cloudinary.js +9 -0
- package/templates/node-prisma/src/config/db.js +16 -0
- package/templates/node-prisma/src/config/dotenv.js +2 -0
- package/templates/node-prisma/src/config/email.js +30 -0
- package/templates/node-prisma/src/config/socket.js +54 -0
- package/templates/node-prisma/src/config/webPush.js +9 -0
- package/templates/node-prisma/src/controllers/auth.controller.js +146 -0
- package/templates/node-prisma/src/controllers/upload.controller.js +26 -0
- package/templates/node-prisma/src/index.js +24 -0
- package/templates/node-prisma/src/middleware/auth.middleware.js +44 -0
- package/templates/node-prisma/src/middleware/errorHandler.js +22 -0
- package/templates/node-prisma/src/middleware/multer.js +21 -0
- package/templates/node-prisma/src/middleware/rateLimiter.js +57 -0
- package/templates/node-prisma/src/routes/auth.route.js +22 -0
- package/templates/node-prisma/src/routes/index.js +10 -0
- package/templates/node-prisma/src/routes/upload.route.js +12 -0
- package/templates/node-prisma/src/services/auth.service.js +163 -0
- package/templates/node-prisma/src/services/auth.service.ts +0 -0
- package/templates/node-prisma/src/utils/authToken.js +26 -0
- package/templates/node-prisma/src/utils/cloudinary.js +27 -0
- package/templates/node-prisma/src/utils/cloudinaryUpload.js +87 -0
- package/templates/node-prisma/src/utils/emailOtp.js +190 -0
- package/templates/node-prisma/src/utils/genOtpToken.js +20 -0
- package/templates/node-prisma/src/utils/generateVapidKeys.js +12 -0
- package/templates/node-prisma/src/utils/jwt.js +25 -0
- package/templates/node-prisma/src/utils/logger.js +25 -0
- package/templates/node-prisma-ts/.env.example +63 -0
- package/templates/node-prisma-ts/README.md +73 -0
- package/templates/node-prisma-ts/_gitignore +24 -0
- package/templates/node-prisma-ts/package.json +48 -0
- package/templates/node-prisma-ts/prisma/schema.prisma +41 -0
- package/templates/node-prisma-ts/src/app.ts +36 -0
- package/templates/node-prisma-ts/src/config/cloudinary.ts +9 -0
- package/templates/node-prisma-ts/src/config/db.ts +16 -0
- package/templates/node-prisma-ts/src/config/dotenv.ts +2 -0
- package/templates/node-prisma-ts/src/config/email.ts +28 -0
- package/templates/node-prisma-ts/src/config/socket.ts +54 -0
- package/templates/node-prisma-ts/src/config/webPush.ts +9 -0
- package/templates/node-prisma-ts/src/controllers/auth.controller.ts +124 -0
- package/templates/node-prisma-ts/src/controllers/upload.controller.ts +22 -0
- package/templates/node-prisma-ts/src/index.ts +17 -0
- package/templates/node-prisma-ts/src/middleware/auth.middleware.ts +45 -0
- package/templates/node-prisma-ts/src/middleware/errorHandler.ts +16 -0
- package/templates/node-prisma-ts/src/middleware/multer.ts +20 -0
- package/templates/node-prisma-ts/src/middleware/rateLimiter.ts +53 -0
- package/templates/node-prisma-ts/src/routes/auth.route.ts +22 -0
- package/templates/node-prisma-ts/src/routes/index.ts +10 -0
- package/templates/node-prisma-ts/src/routes/upload.route.ts +11 -0
- package/templates/node-prisma-ts/src/services/auth.service.ts +163 -0
- package/templates/node-prisma-ts/src/types/express.d.ts +10 -0
- package/templates/node-prisma-ts/src/utils/cloudinaryUpload.ts +44 -0
- package/templates/node-prisma-ts/src/utils/emailOtp.ts +30 -0
- package/templates/node-prisma-ts/src/utils/genOtpToken.ts +22 -0
- package/templates/node-prisma-ts/src/utils/generateVapidKeys.ts +12 -0
- package/templates/node-prisma-ts/src/utils/jwt.ts +27 -0
- package/templates/node-prisma-ts/src/utils/logger.ts +27 -0
- package/templates/node-prisma-ts/tsconfig.json +14 -0
- package/templates/node-ts/.env.example +62 -0
- package/templates/node-ts/README.md +69 -0
- package/templates/node-ts/_gitignore +24 -0
- package/templates/node-ts/package.json +47 -0
- package/templates/node-ts/src/app.ts +36 -0
- package/templates/node-ts/src/config/cloudinary.ts +9 -0
- package/templates/node-ts/src/config/db.ts +15 -0
- package/templates/node-ts/src/config/dotenv.ts +2 -0
- package/templates/node-ts/src/config/email.ts +28 -0
- package/templates/node-ts/src/config/socket.ts +54 -0
- package/templates/node-ts/src/config/webPush.ts +9 -0
- package/templates/node-ts/src/controllers/auth.controller.ts +126 -0
- package/templates/node-ts/src/controllers/upload.controller.ts +22 -0
- package/templates/node-ts/src/index.ts +17 -0
- package/templates/node-ts/src/middleware/auth.middleware.ts +38 -0
- package/templates/node-ts/src/middleware/errorHandler.ts +16 -0
- package/templates/node-ts/src/middleware/multer.ts +20 -0
- package/templates/node-ts/src/middleware/rateLimiter.ts +53 -0
- package/templates/node-ts/src/models/otp.model.ts +21 -0
- package/templates/node-ts/src/models/pushSubscription.model.ts +32 -0
- package/templates/node-ts/src/models/user.model.ts +43 -0
- package/templates/node-ts/src/routes/auth.route.ts +22 -0
- package/templates/node-ts/src/routes/index.ts +10 -0
- package/templates/node-ts/src/routes/upload.route.ts +11 -0
- package/templates/node-ts/src/services/auth.service.ts +115 -0
- package/templates/node-ts/src/types/express.d.ts +10 -0
- package/templates/node-ts/src/utils/cloudinaryUpload.ts +44 -0
- package/templates/node-ts/src/utils/emailOtp.ts +30 -0
- package/templates/node-ts/src/utils/genOtpToken.ts +22 -0
- package/templates/node-ts/src/utils/generateVapidKeys.ts +12 -0
- package/templates/node-ts/src/utils/jwt.ts +27 -0
- package/templates/node-ts/src/utils/logger.ts +27 -0
- package/templates/node-ts/tsconfig.json +18 -0
- package/templates/react/.env.example +1 -0
- package/templates/react/_gitignore +24 -0
- package/templates/react/index.html +14 -0
- package/templates/react/package.json +39 -0
- package/templates/react/public/_redirects +1 -0
- package/templates/react/public/favicon.ico +0 -0
- package/templates/react/public/favicon.svg +1 -0
- package/templates/react/public/logo.png +0 -0
- package/templates/react/public/manifest.json +24 -0
- package/templates/react/public/sw.js +56 -0
- package/templates/react/src/App.jsx +68 -0
- package/templates/react/src/assets/animations/loading.json +1 -0
- package/templates/react/src/assets/data/navigation.js +29 -0
- package/templates/react/src/assets/images/logo.png +0 -0
- package/templates/react/src/components/common/Breadcrumbs.jsx +27 -0
- package/templates/react/src/components/common/Loading.jsx +19 -0
- package/templates/react/src/components/common/LottieIcon.jsx +36 -0
- package/templates/react/src/components/common/NotFound.jsx +78 -0
- package/templates/react/src/components/common/PwaInstallPrompt.jsx +72 -0
- package/templates/react/src/components/common/SEO.jsx +67 -0
- package/templates/react/src/components/common/Scroll.jsx +25 -0
- package/templates/react/src/components/common/Table.jsx +110 -0
- package/templates/react/src/components/common/ToggleSwitch.jsx +38 -0
- package/templates/react/src/components/common/Unauthorized.jsx +76 -0
- package/templates/react/src/components/layout/ProtectedRoute.jsx +17 -0
- package/templates/react/src/components/layout/PublicLayout.jsx +13 -0
- package/templates/react/src/components/layout/SidebarLayout.jsx +37 -0
- package/templates/react/src/components/modals/ConfirmModal.jsx +135 -0
- package/templates/react/src/components/modals/Modal.jsx +94 -0
- package/templates/react/src/components/skeletons/common/CardSkeleton.jsx +23 -0
- package/templates/react/src/components/skeletons/common/DashboardSkeleton.jsx +19 -0
- package/templates/react/src/components/skeletons/common/ListSkeleton.jsx +24 -0
- package/templates/react/src/components/skeletons/common/PageSkeleton.jsx +26 -0
- package/templates/react/src/components/skeletons/common/ProfileSkeleton.jsx +23 -0
- package/templates/react/src/components/skeletons/common/Skeleton.jsx +18 -0
- package/templates/react/src/components/skeletons/common/TableSkeleton.jsx +33 -0
- package/templates/react/src/components/ui/Header.jsx +230 -0
- package/templates/react/src/components/ui/SidebarHeader.jsx +27 -0
- package/templates/react/src/components/ui/sidebar.jsx +152 -0
- package/templates/react/src/config/api.js +22 -0
- package/templates/react/src/config/appConfig.js +44 -0
- package/templates/react/src/config/navigation.js +14 -0
- package/templates/react/src/hooks/useLenis.js +28 -0
- package/templates/react/src/hooks/usePwaInstall.js +45 -0
- package/templates/react/src/hooks/useWindowSize.js +25 -0
- package/templates/react/src/index.css +158 -0
- package/templates/react/src/main.jsx +24 -0
- package/templates/react/src/pages/Home.jsx +154 -0
- package/templates/react/src/pages/Login.jsx +196 -0
- package/templates/react/src/pages/Profile.jsx +9 -0
- package/templates/react/src/services/authService.js +16 -0
- package/templates/react/src/store/useAuthStore.js +98 -0
- package/templates/react/src/store/useUiStore.js +54 -0
- package/templates/react/src/utils/getInitials.js +10 -0
- package/templates/react/vite.config.js +8 -0
- package/templates/react-ts/_gitignore +24 -0
- package/templates/react-ts/index.html +14 -0
- package/templates/react-ts/package.json +45 -0
- package/templates/react-ts/public/_redirects +1 -0
- package/templates/react-ts/public/favicon.ico +0 -0
- package/templates/react-ts/public/favicon.svg +1 -0
- package/templates/react-ts/public/logo.png +0 -0
- package/templates/react-ts/public/manifest.json +24 -0
- package/templates/react-ts/public/sw.js +56 -0
- package/templates/react-ts/src/App.tsx +68 -0
- package/templates/react-ts/src/assets/animations/loading.json +1 -0
- package/templates/react-ts/src/assets/data/navigation.ts +29 -0
- package/templates/react-ts/src/assets/images/logo.png +0 -0
- package/templates/react-ts/src/components/common/Breadcrumbs.tsx +27 -0
- package/templates/react-ts/src/components/common/Loading.tsx +19 -0
- package/templates/react-ts/src/components/common/LottieIcon.tsx +36 -0
- package/templates/react-ts/src/components/common/NotFound.tsx +78 -0
- package/templates/react-ts/src/components/common/PwaInstallPrompt.tsx +72 -0
- package/templates/react-ts/src/components/common/SEO.tsx +67 -0
- package/templates/react-ts/src/components/common/Scroll.tsx +25 -0
- package/templates/react-ts/src/components/common/Table.tsx +118 -0
- package/templates/react-ts/src/components/common/ToggleSwitch.tsx +38 -0
- package/templates/react-ts/src/components/common/Unauthorized.tsx +76 -0
- package/templates/react-ts/src/components/layout/ProtectedRoute.tsx +23 -0
- package/templates/react-ts/src/components/layout/PublicLayout.tsx +13 -0
- package/templates/react-ts/src/components/layout/SidebarLayout.tsx +37 -0
- package/templates/react-ts/src/components/modals/ConfirmModal.tsx +135 -0
- package/templates/react-ts/src/components/modals/Modal.tsx +94 -0
- package/templates/react-ts/src/components/skeletons/common/CardSkeleton.tsx +23 -0
- package/templates/react-ts/src/components/skeletons/common/DashboardSkeleton.tsx +19 -0
- package/templates/react-ts/src/components/skeletons/common/ListSkeleton.tsx +24 -0
- package/templates/react-ts/src/components/skeletons/common/PageSkeleton.tsx +26 -0
- package/templates/react-ts/src/components/skeletons/common/ProfileSkeleton.tsx +23 -0
- package/templates/react-ts/src/components/skeletons/common/Skeleton.tsx +18 -0
- package/templates/react-ts/src/components/skeletons/common/TableSkeleton.tsx +33 -0
- package/templates/react-ts/src/components/ui/Header.tsx +230 -0
- package/templates/react-ts/src/components/ui/SidebarHeader.tsx +27 -0
- package/templates/react-ts/src/components/ui/sidebar.tsx +152 -0
- package/templates/react-ts/src/config/api.ts +22 -0
- package/templates/react-ts/src/config/appConfig.ts +44 -0
- package/templates/react-ts/src/config/navigation.ts +14 -0
- package/templates/react-ts/src/hooks/useLenis.ts +28 -0
- package/templates/react-ts/src/hooks/usePwaInstall.ts +45 -0
- package/templates/react-ts/src/hooks/useWindowSize.ts +25 -0
- package/templates/react-ts/src/index.css +158 -0
- package/templates/react-ts/src/main.tsx +24 -0
- package/templates/react-ts/src/pages/Home.tsx +154 -0
- package/templates/react-ts/src/pages/Login.tsx +196 -0
- package/templates/react-ts/src/pages/Profile.tsx +9 -0
- package/templates/react-ts/src/services/authService.ts +16 -0
- package/templates/react-ts/src/store/useAuthStore.ts +98 -0
- package/templates/react-ts/src/store/useUiStore.ts +54 -0
- package/templates/react-ts/src/utils/getInitials.ts +10 -0
- package/templates/react-ts/tsconfig.json +25 -0
- package/templates/react-ts/tsconfig.node.json +10 -0
- package/templates/react-ts/vite.config.ts +8 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Node.js Prisma Backend Boilerplate
|
|
2
|
+
|
|
3
|
+
A production-ready Node.js & Express boilerplate project with best-practice architectures, modular routing, and Prisma ORM integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ⚙️ **Modular Architecture:** Express application setup decoupled into `app.js` (middleware + router wiring) and `index.js` (server initialization & db connection).
|
|
8
|
+
- 🗄️ **Prisma ORM:** Built-in PostgreSQL datasource configuration and schema mapping for `User`, `Otp`, and `PushSubscription` models.
|
|
9
|
+
- 📝 **Colorized Logging:** Zero-dependency custom logger with timestamped success, warning, info, and error layouts.
|
|
10
|
+
- 🛡️ **Security Out-of-the-Box:** Pre-configured with Helmet headers, CORS policies, and global rate limiters (`apiLimiter`, `authLimiter`, `uploadLimiter`).
|
|
11
|
+
- 🔑 **Authentication & JWT:** Custom middlewares for route protection, sign-ups, and log-ins with HTTP-only cookie-based tokens.
|
|
12
|
+
- 📧 **SMTP Mailer & OTP:** Standard mailer transport using Gmail NodeMailer wrapper, integrated with an OTP generator and email template.
|
|
13
|
+
- 🖼️ **File Uploads:** Cloudinary integration utilizing Multer memory buffers for secure, single or multi-file uploads.
|
|
14
|
+
- 🔌 **Socket.io Setup:** Pre-installed Socket.io hooks mapping connected user sessions to active sockets.
|
|
15
|
+
- ✉️ **Web Push:** Push notifications integration powered by VAPID key generators and web-push subscriptions.
|
|
16
|
+
|
|
17
|
+
## Getting Started
|
|
18
|
+
|
|
19
|
+
### 1. Configure Environment Variables
|
|
20
|
+
|
|
21
|
+
Create a `.env` file in the root directory (based on `.env.example`):
|
|
22
|
+
|
|
23
|
+
```env
|
|
24
|
+
PORT=5001
|
|
25
|
+
JWT_SECRET=your_super_secret_jwt_key
|
|
26
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/db_name
|
|
27
|
+
|
|
28
|
+
# Cloudinary
|
|
29
|
+
CLOUDINARY_CLOUD_NAME=your_cloud_name
|
|
30
|
+
CLOUDINARY_API_KEY=your_api_key
|
|
31
|
+
CLOUDINARY_API_SECRET=your_api_secret
|
|
32
|
+
|
|
33
|
+
# SMTP Settings
|
|
34
|
+
GMAIL_USER=your_email@gmail.com
|
|
35
|
+
GMAIL_PASSCODE=your_app_password
|
|
36
|
+
|
|
37
|
+
# Web Push
|
|
38
|
+
VAPID_SUBJECT=mailto:your_email@example.com
|
|
39
|
+
VAPID_PUBLIC_KEY=your_vapid_public_key
|
|
40
|
+
VAPID_PRIVATE_KEY=your_vapid_private_key
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Install & Sync Schema
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Install dependencies
|
|
47
|
+
npm install
|
|
48
|
+
|
|
49
|
+
# Push database schema changes locally
|
|
50
|
+
npm run db:push
|
|
51
|
+
|
|
52
|
+
# Generate Prisma Client types
|
|
53
|
+
npm run db:generate
|
|
54
|
+
|
|
55
|
+
# Start development server with reload
|
|
56
|
+
npm run dev
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API Endpoints
|
|
60
|
+
|
|
61
|
+
### Auth Routes (`/api/auth`)
|
|
62
|
+
- `POST /signup` - Registers a new user session
|
|
63
|
+
- `POST /login` - Log in user and write token cookie
|
|
64
|
+
- `POST /logout` - Clear token session cookies
|
|
65
|
+
- `GET /me` - Returns logged-in user profile (requires auth)
|
|
66
|
+
- `PUT /me` - Edit profile info and upload avatars (requires auth)
|
|
67
|
+
|
|
68
|
+
### Upload Routes (`/api/upload`)
|
|
69
|
+
- `POST /` - Securely uploads image/file to Cloudinary (requires auth)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "node-prisma-template",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "src/index.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node src/index.js",
|
|
8
|
+
"dev": "nodemon src/index.js",
|
|
9
|
+
"db:push": "prisma db push",
|
|
10
|
+
"db:generate": "prisma generate",
|
|
11
|
+
"generate:vapid": "node ./src/utils/generateVapidKeys.js"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@prisma/client": "^5.6.0",
|
|
15
|
+
"bcrypt": "^5.1.1",
|
|
16
|
+
"compression": "^1.7.4",
|
|
17
|
+
"cookie-parser": "^1.4.6",
|
|
18
|
+
"cors": "^2.8.5",
|
|
19
|
+
"dotenv": "^16.3.1",
|
|
20
|
+
"express": "^4.18.2",
|
|
21
|
+
"express-rate-limit": "^7.1.4",
|
|
22
|
+
"helmet": "^7.1.0",
|
|
23
|
+
"jsonwebtoken": "^9.0.2",
|
|
24
|
+
"morgan": "^1.10.0",
|
|
25
|
+
"multer": "^1.4.5-lts.1",
|
|
26
|
+
"cloudinary": "^2.0.0",
|
|
27
|
+
"nodemailer": "^6.9.7",
|
|
28
|
+
"socket.io": "^4.7.2",
|
|
29
|
+
"web-push": "^3.6.6"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"nodemon": "^3.0.1",
|
|
33
|
+
"prisma": "^5.6.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
model User {
|
|
11
|
+
id String @id @default(uuid())
|
|
12
|
+
email String @unique
|
|
13
|
+
name String
|
|
14
|
+
phone String?
|
|
15
|
+
password String
|
|
16
|
+
role String @default("user")
|
|
17
|
+
avatarUrl String?
|
|
18
|
+
avatarPublicId String?
|
|
19
|
+
createdAt DateTime @default(now())
|
|
20
|
+
updatedAt DateTime @updatedAt
|
|
21
|
+
pushSubscriptions PushSubscription[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
model Otp {
|
|
25
|
+
id String @id @default(uuid())
|
|
26
|
+
email String @unique
|
|
27
|
+
otp String
|
|
28
|
+
createdAt DateTime @default(now())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
model PushSubscription {
|
|
32
|
+
id String @id @default(uuid())
|
|
33
|
+
endpoint String @unique
|
|
34
|
+
p256dh String
|
|
35
|
+
auth String
|
|
36
|
+
role String @default("user")
|
|
37
|
+
userId String?
|
|
38
|
+
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
39
|
+
createdAt DateTime @default(now())
|
|
40
|
+
updatedAt DateTime @updatedAt
|
|
41
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import helmet from "helmet";
|
|
3
|
+
import cors from "cors";
|
|
4
|
+
import compression from "compression";
|
|
5
|
+
import cookieParser from "cookie-parser";
|
|
6
|
+
import morgan from "morgan";
|
|
7
|
+
import apiRoutes from "./routes/index.js";
|
|
8
|
+
import { notFound, errorHandler } from "./middleware/errorHandler.js";
|
|
9
|
+
import { apiLimiter } from "./middleware/rateLimiter.js";
|
|
10
|
+
|
|
11
|
+
const app = express();
|
|
12
|
+
|
|
13
|
+
// Security and utility middlewares
|
|
14
|
+
app.use(helmet());
|
|
15
|
+
app.use(
|
|
16
|
+
cors({
|
|
17
|
+
origin: process.env.CLIENT_URL || "http://localhost:5173",
|
|
18
|
+
credentials: true,
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
app.use(compression());
|
|
22
|
+
app.use(express.json());
|
|
23
|
+
app.use(express.urlencoded({ extended: true }));
|
|
24
|
+
app.use(cookieParser());
|
|
25
|
+
app.use(morgan("dev"));
|
|
26
|
+
|
|
27
|
+
// Rate limiting
|
|
28
|
+
app.use(apiLimiter);
|
|
29
|
+
|
|
30
|
+
// API Routes
|
|
31
|
+
app.use("/api", apiRoutes);
|
|
32
|
+
|
|
33
|
+
// Example health route
|
|
34
|
+
app.get("/api/health", (req, res) => {
|
|
35
|
+
res.status(200).json({ success: true, message: "API is running" });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Error handling middlewares
|
|
39
|
+
app.use(notFound);
|
|
40
|
+
app.use(errorHandler);
|
|
41
|
+
|
|
42
|
+
export default app;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PrismaClient } from "@prisma/client";
|
|
2
|
+
import logger from "../utils/logger.js";
|
|
3
|
+
|
|
4
|
+
export const prisma = new PrismaClient();
|
|
5
|
+
|
|
6
|
+
const connectDB = async () => {
|
|
7
|
+
try {
|
|
8
|
+
await prisma.$connect();
|
|
9
|
+
logger.success("Prisma Database connected successfully");
|
|
10
|
+
} catch (error) {
|
|
11
|
+
logger.error("Prisma Database connection failed", error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default connectDB;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// import dotenv from "dotenv";
|
|
2
|
+
// dotenv.config();
|
|
3
|
+
import nodemailer from "nodemailer";
|
|
4
|
+
import logger from "../utils/logger.js";
|
|
5
|
+
|
|
6
|
+
const sendEmail = async (to, subject, message) => {
|
|
7
|
+
try {
|
|
8
|
+
const transporter = nodemailer.createTransport({
|
|
9
|
+
service: "gmail",
|
|
10
|
+
auth: {
|
|
11
|
+
user: process.env.GMAIL_USER,
|
|
12
|
+
pass: process.env.GMAIL_PASSCODE,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const mailOptions = {
|
|
17
|
+
from: process.env.GMAIL_USER,
|
|
18
|
+
to: to,
|
|
19
|
+
subject: subject,
|
|
20
|
+
html: message,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const res = await transporter.sendMail(mailOptions);
|
|
24
|
+
logger.success(`Email sent to ${to}: ${res.messageId}`);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
logger.error("Failed to send email", error);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default sendEmail;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Server } from "socket.io";
|
|
2
|
+
import logger from "../utils/logger.js";
|
|
3
|
+
|
|
4
|
+
let io;
|
|
5
|
+
|
|
6
|
+
const userSocketMap = {};
|
|
7
|
+
|
|
8
|
+
const initializeSocket = (server) => {
|
|
9
|
+
io = new Server(server, {
|
|
10
|
+
cors: {
|
|
11
|
+
origin: ["http://localhost:5173"],
|
|
12
|
+
credentials: true,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
io.on("connection", (socket) => {
|
|
17
|
+
const userId = socket.handshake.auth.userId;
|
|
18
|
+
|
|
19
|
+
if (!userId) {
|
|
20
|
+
logger.warn("No userId, disconnecting socket");
|
|
21
|
+
socket.disconnect();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
logger.info(`Socket connected: ${socket.id} (User: ${userId})`);
|
|
26
|
+
|
|
27
|
+
if (!userSocketMap[userId]) {
|
|
28
|
+
userSocketMap[userId] = new Set();
|
|
29
|
+
}
|
|
30
|
+
userSocketMap[userId].add(socket.id);
|
|
31
|
+
|
|
32
|
+
socket.on("disconnect", (reason) => {
|
|
33
|
+
if (!userId) return;
|
|
34
|
+
userSocketMap[userId].delete(socket.id);
|
|
35
|
+
logger.info(`Socket disconnected: ${socket.id} (Reason: ${reason})`);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return io;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const getIO = () => {
|
|
43
|
+
if (!io) {
|
|
44
|
+
throw new Error("Socket.IO has not been initialized yet");
|
|
45
|
+
}
|
|
46
|
+
return io;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const getReceiverSocketIds = (userId) =>
|
|
50
|
+
userSocketMap[userId] ? Array.from(userSocketMap[userId]) : [];
|
|
51
|
+
|
|
52
|
+
export { io, getReceiverSocketIds, userSocketMap };
|
|
53
|
+
|
|
54
|
+
export default initializeSocket;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { authService } from "../services/auth.service.js";
|
|
2
|
+
import { generateToken } from "../utils/jwt.js";
|
|
3
|
+
import genOtpToken from "../utils/genOtpToken.js";
|
|
4
|
+
import logger from "../utils/logger.js";
|
|
5
|
+
|
|
6
|
+
export const signup = async (req, res, next) => {
|
|
7
|
+
try {
|
|
8
|
+
const { name, email, phone, password } = req.body;
|
|
9
|
+
if (!email || !password || !name) {
|
|
10
|
+
return next({
|
|
11
|
+
status: 400,
|
|
12
|
+
message: "All fields are required.",
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const newUser = await authService.signup({ name, email, phone, password });
|
|
17
|
+
const token = await generateToken(newUser, res);
|
|
18
|
+
const safeUser = { ...newUser };
|
|
19
|
+
delete safeUser.password;
|
|
20
|
+
|
|
21
|
+
res.status(201).json({ message: "Registration Successful", data: safeUser, token });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
logger.error("Error in signup controller", error);
|
|
24
|
+
next(error);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const login = async (req, res, next) => {
|
|
29
|
+
try {
|
|
30
|
+
const { email, password } = req.body;
|
|
31
|
+
if (!email || !password) {
|
|
32
|
+
return next({
|
|
33
|
+
status: 400,
|
|
34
|
+
message: "All fields are required.",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const user = await authService.login({ email, password });
|
|
39
|
+
const token = await generateToken(user, res);
|
|
40
|
+
const safeUser = { ...user };
|
|
41
|
+
delete safeUser.password;
|
|
42
|
+
|
|
43
|
+
res.status(200).json({ message: "Login successfully", data: safeUser, token });
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger.error("Error in login controller", error);
|
|
46
|
+
next(error);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const logout = async (_req, res, next) => {
|
|
51
|
+
try {
|
|
52
|
+
res.clearCookie("token", {
|
|
53
|
+
httpOnly: true,
|
|
54
|
+
secure: process.env.NODE_ENV === "production",
|
|
55
|
+
sameSite: "strict",
|
|
56
|
+
path: "/",
|
|
57
|
+
});
|
|
58
|
+
res.status(200).json({ message: "Logout Successfully" });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logger.error("Error in logout controller", error);
|
|
61
|
+
next(error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const getMe = async (req, res, next) => {
|
|
66
|
+
try {
|
|
67
|
+
res.status(200).json({ message: "User Authenticated", data: req.user });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logger.error("Error in getMe controller", error);
|
|
70
|
+
next(error);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const genOtp = async (req, res, next) => {
|
|
75
|
+
try {
|
|
76
|
+
const { email } = req.body;
|
|
77
|
+
if (!email) {
|
|
78
|
+
return next({
|
|
79
|
+
status: 400,
|
|
80
|
+
message: "Email is required.",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
await authService.generateOtp(email);
|
|
85
|
+
res.status(200).json({ message: "Otp sent successfully" });
|
|
86
|
+
} catch (error) {
|
|
87
|
+
logger.error("Error in genOtp", error);
|
|
88
|
+
next(error);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const verifyOtp = async (req, res, next) => {
|
|
93
|
+
try {
|
|
94
|
+
const { email, otp } = req.body;
|
|
95
|
+
if (!email || !otp) {
|
|
96
|
+
return next({
|
|
97
|
+
status: 400,
|
|
98
|
+
message: "All fields are required.",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const user = await authService.verifyOtp({ email, otp });
|
|
103
|
+
await genOtpToken(user, res);
|
|
104
|
+
|
|
105
|
+
res.status(200).json({ message: "Otp verified successfully" });
|
|
106
|
+
} catch (error) {
|
|
107
|
+
logger.error("Error in verifyOtp", error);
|
|
108
|
+
next(error);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const resetPassword = async (req, res, next) => {
|
|
113
|
+
try {
|
|
114
|
+
const { newPassword } = req.body;
|
|
115
|
+
const currentUser = req.user;
|
|
116
|
+
if (!newPassword) {
|
|
117
|
+
return next({
|
|
118
|
+
status: 400,
|
|
119
|
+
message: "All fields are required.",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await authService.resetPassword(currentUser, newPassword);
|
|
124
|
+
res.status(200).json({ message: "Password updated successfully" });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
logger.error("Error in resetPassword", error);
|
|
127
|
+
next(error);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const updateMe = async (req, res, next) => {
|
|
132
|
+
try {
|
|
133
|
+
const { name, phone } = req.body;
|
|
134
|
+
const user = await authService.updateProfile(req.user.id, {
|
|
135
|
+
name,
|
|
136
|
+
phone,
|
|
137
|
+
file: req.file,
|
|
138
|
+
});
|
|
139
|
+
const safeUser = { ...user };
|
|
140
|
+
delete safeUser.password;
|
|
141
|
+
res.status(200).json({ success: true, data: safeUser });
|
|
142
|
+
} catch (error) {
|
|
143
|
+
logger.error("Error updating profile", error);
|
|
144
|
+
next(error);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { uploadSingleToCloudinary } from "../utils/cloudinaryUpload.js";
|
|
2
|
+
import logger from "../utils/logger.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handle single file uploads to Cloudinary
|
|
6
|
+
*/
|
|
7
|
+
export const uploadFile = async (req, res, next) => {
|
|
8
|
+
try {
|
|
9
|
+
if (!req.file) {
|
|
10
|
+
return res.status(400).json({ success: false, message: "No file uploaded" });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const result = await uploadSingleToCloudinary(req.file, {
|
|
14
|
+
folder: req.body.folder || "general_uploads",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
res.status(200).json({
|
|
18
|
+
success: true,
|
|
19
|
+
message: "File uploaded successfully",
|
|
20
|
+
data: result,
|
|
21
|
+
});
|
|
22
|
+
} catch (error) {
|
|
23
|
+
logger.error("Upload controller error", error);
|
|
24
|
+
next(error);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
import http from "http";
|
|
3
|
+
import app from "./app.js";
|
|
4
|
+
import connectDB from "./config/db.js";
|
|
5
|
+
import logger from "./utils/logger.js";
|
|
6
|
+
// import initializeSocket from "./config/socket.js";
|
|
7
|
+
|
|
8
|
+
dotenv.config();
|
|
9
|
+
|
|
10
|
+
const PORT = process.env.PORT || 5000;
|
|
11
|
+
|
|
12
|
+
// Connect to Database
|
|
13
|
+
connectDB();
|
|
14
|
+
|
|
15
|
+
// Create HTTP Server
|
|
16
|
+
const server = http.createServer(app);
|
|
17
|
+
|
|
18
|
+
// Wire Socket.io (Commented out by default)
|
|
19
|
+
// initializeSocket(server);
|
|
20
|
+
|
|
21
|
+
// Start Server
|
|
22
|
+
server.listen(PORT, () => {
|
|
23
|
+
logger.success(`Server is running on port ${PORT}`);
|
|
24
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { verifyToken } from "../utils/jwt.js";
|
|
2
|
+
import logger from "../utils/logger.js";
|
|
3
|
+
import { prisma } from "../config/db.js";
|
|
4
|
+
|
|
5
|
+
export const protect = async (req, res, next) => {
|
|
6
|
+
let token;
|
|
7
|
+
if (req.cookies?.token) {
|
|
8
|
+
token = req.cookies.token;
|
|
9
|
+
} else if (
|
|
10
|
+
req.headers.authorization &&
|
|
11
|
+
req.headers.authorization.startsWith("Bearer")
|
|
12
|
+
) {
|
|
13
|
+
token = req.headers.authorization.split(" ")[1];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!token) {
|
|
17
|
+
return res.status(401).json({ message: "Not authorized, no token provided" });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const decoded = verifyToken(token);
|
|
22
|
+
if (!decoded) {
|
|
23
|
+
return res.status(401).json({ message: "Not authorized, invalid token" });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const user = await prisma.user.findUnique({
|
|
27
|
+
where: { id: decoded.id },
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (!user) {
|
|
31
|
+
return res.status(401).json({ message: "Not authorized, user not found" });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Exclude password
|
|
35
|
+
const safeUser = { ...user };
|
|
36
|
+
delete safeUser.password;
|
|
37
|
+
|
|
38
|
+
req.user = safeUser;
|
|
39
|
+
return next();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
logger.error("Auth middleware error", error);
|
|
42
|
+
return res.status(401).json({ message: "Not authorized, token verification failed" });
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Not Found Middleware
|
|
3
|
+
* Catches all unmatched requests and forwards a 404 error
|
|
4
|
+
*/
|
|
5
|
+
export const notFound = (req, res, next) => {
|
|
6
|
+
const error = new Error(`Not Found - ${req.originalUrl}`);
|
|
7
|
+
res.status(404);
|
|
8
|
+
next(error);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Global Error Handler Middleware
|
|
13
|
+
* Formats error responses nicely in JSON
|
|
14
|
+
*/
|
|
15
|
+
export const errorHandler = (err, req, res, next) => {
|
|
16
|
+
const statusCode = err.status || err.statusCode || (res.statusCode === 200 ? 500 : res.statusCode);
|
|
17
|
+
res.status(statusCode).json({
|
|
18
|
+
success: false,
|
|
19
|
+
message: err.message || "An unexpected error occurred",
|
|
20
|
+
stack: process.env.NODE_ENV === "production" ? undefined : err.stack,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import multer from "multer";
|
|
2
|
+
|
|
3
|
+
// Configure memory storage to receive file buffers directly
|
|
4
|
+
const storage = multer.memoryStorage();
|
|
5
|
+
|
|
6
|
+
// Validate file types (only allow common image formats)
|
|
7
|
+
const fileFilter = (req, file, cb) => {
|
|
8
|
+
if (file.mimetype.startsWith("image/")) {
|
|
9
|
+
cb(null, true);
|
|
10
|
+
} else {
|
|
11
|
+
cb(new Error("Only image files are allowed!"), false);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const upload = multer({
|
|
16
|
+
storage,
|
|
17
|
+
fileFilter,
|
|
18
|
+
limits: {
|
|
19
|
+
fileSize: 5 * 1024 * 1024, // 5MB limit
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import rateLimit from "express-rate-limit";
|
|
2
|
+
|
|
3
|
+
const createLimiter = ({
|
|
4
|
+
windowMs,
|
|
5
|
+
max,
|
|
6
|
+
message,
|
|
7
|
+
skipSuccessfulRequests = false,
|
|
8
|
+
}) =>
|
|
9
|
+
rateLimit({
|
|
10
|
+
windowMs,
|
|
11
|
+
max,
|
|
12
|
+
standardHeaders: true,
|
|
13
|
+
legacyHeaders: false,
|
|
14
|
+
skipSuccessfulRequests,
|
|
15
|
+
|
|
16
|
+
keyGenerator: (req) => {
|
|
17
|
+
return req.user?.id || req.ip || req.headers["x-forwarded-for"] || req.socket.remoteAddress;
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
handler: (req, res) => {
|
|
21
|
+
res.status(429).json({
|
|
22
|
+
success: false,
|
|
23
|
+
message,
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* General API Limiter
|
|
30
|
+
* 100 requests / 15 minutes
|
|
31
|
+
*/
|
|
32
|
+
export const apiLimiter = createLimiter({
|
|
33
|
+
windowMs: 15 * 60 * 1000,
|
|
34
|
+
max: 100,
|
|
35
|
+
message: "Too many requests. Please try again later.",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Authentication Limiter
|
|
40
|
+
* 10 failed attempts / 15 minutes
|
|
41
|
+
*/
|
|
42
|
+
export const authLimiter = createLimiter({
|
|
43
|
+
windowMs: 15 * 60 * 1000,
|
|
44
|
+
max: 10,
|
|
45
|
+
skipSuccessfulRequests: true,
|
|
46
|
+
message: "Too many login attempts. Please try again later.",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Upload Limiter
|
|
51
|
+
* 20 uploads / hour
|
|
52
|
+
*/
|
|
53
|
+
export const uploadLimiter = createLimiter({
|
|
54
|
+
windowMs: 60 * 60 * 1000,
|
|
55
|
+
max: 20,
|
|
56
|
+
message: "Upload limit reached. Please try again in an hour.",
|
|
57
|
+
});
|