@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,73 @@
|
|
|
1
|
+
# Node.js TypeScript Prisma Backend Boilerplate
|
|
2
|
+
|
|
3
|
+
A production-ready, strongly-typed Node.js & Express boilerplate project with best-practice architectures, modular routing, Prisma ORM, and TSX engine compilation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ⚙️ **Modular Architecture:** Express application setup decoupled into `app.ts` (middleware + router wiring) and `index.ts` (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
|
+
- 📦 **TSX Engine:** Fast TS runner with native ESM specifier resolution support.
|
|
17
|
+
|
|
18
|
+
## Getting Started
|
|
19
|
+
|
|
20
|
+
### 1. Configure Environment Variables
|
|
21
|
+
|
|
22
|
+
Create a `.env` file in the root directory (based on `.env.example`):
|
|
23
|
+
|
|
24
|
+
```env
|
|
25
|
+
PORT=5002
|
|
26
|
+
JWT_SECRET=your_super_secret_jwt_key
|
|
27
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/db_name
|
|
28
|
+
|
|
29
|
+
# Cloudinary
|
|
30
|
+
CLOUDINARY_CLOUD_NAME=your_cloud_name
|
|
31
|
+
CLOUDINARY_API_KEY=your_api_key
|
|
32
|
+
CLOUDINARY_API_SECRET=your_api_secret
|
|
33
|
+
|
|
34
|
+
# SMTP Settings
|
|
35
|
+
GMAIL_USER=your_email@gmail.com
|
|
36
|
+
GMAIL_PASSCODE=your_app_password
|
|
37
|
+
|
|
38
|
+
# Web Push
|
|
39
|
+
VAPID_SUBJECT=mailto:your_email@example.com
|
|
40
|
+
VAPID_PUBLIC_KEY=your_vapid_public_key
|
|
41
|
+
VAPID_PRIVATE_KEY=your_vapid_private_key
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Install & Sync Schema
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install dependencies
|
|
48
|
+
npm install
|
|
49
|
+
|
|
50
|
+
# Push database schema changes locally
|
|
51
|
+
npm run db:push
|
|
52
|
+
|
|
53
|
+
# Generate Prisma Client types
|
|
54
|
+
npm run db:generate
|
|
55
|
+
|
|
56
|
+
# Start development server with reload (via tsx)
|
|
57
|
+
npm run dev
|
|
58
|
+
|
|
59
|
+
# Build the project to JS
|
|
60
|
+
npm run build
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Endpoints
|
|
64
|
+
|
|
65
|
+
### Auth Routes (`/api/auth`)
|
|
66
|
+
- `POST /signup` - Registers a new user session
|
|
67
|
+
- `POST /login` - Log in user and write token cookie
|
|
68
|
+
- `POST /logout` - Clear token session cookies
|
|
69
|
+
- `GET /me` - Returns logged-in user profile (requires auth)
|
|
70
|
+
- `PUT /me` - Edit profile info and upload avatars (requires auth)
|
|
71
|
+
|
|
72
|
+
### Upload Routes (`/api/upload`)
|
|
73
|
+
- `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,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "node-prisma-ts-template",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "tsx src/index.ts",
|
|
8
|
+
"dev": "tsx watch src/index.ts",
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"db:push": "prisma db push",
|
|
11
|
+
"db:generate": "prisma generate",
|
|
12
|
+
"generate:vapid": "node ./src/utils/generateVapidKeys.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@prisma/client": "^5.6.0",
|
|
16
|
+
"bcrypt": "^5.1.1",
|
|
17
|
+
"compression": "^1.7.4",
|
|
18
|
+
"cookie-parser": "^1.4.6",
|
|
19
|
+
"cors": "^2.8.5",
|
|
20
|
+
"dotenv": "^16.3.1",
|
|
21
|
+
"express": "^4.18.2",
|
|
22
|
+
"express-rate-limit": "^7.1.4",
|
|
23
|
+
"helmet": "^7.1.0",
|
|
24
|
+
"jsonwebtoken": "^9.0.2",
|
|
25
|
+
"morgan": "^1.10.0",
|
|
26
|
+
"multer": "^1.4.5-lts.1",
|
|
27
|
+
"cloudinary": "^2.0.0",
|
|
28
|
+
"nodemailer": "^6.9.7",
|
|
29
|
+
"socket.io": "^4.7.2",
|
|
30
|
+
"web-push": "^3.6.6"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/bcrypt": "^5.0.2",
|
|
34
|
+
"@types/compression": "^1.7.5",
|
|
35
|
+
"@types/cookie-parser": "^1.4.6",
|
|
36
|
+
"@types/cors": "^2.8.17",
|
|
37
|
+
"@types/express": "^4.17.21",
|
|
38
|
+
"@types/jsonwebtoken": "^9.0.5",
|
|
39
|
+
"@types/morgan": "^1.9.9",
|
|
40
|
+
"@types/multer": "^1.4.11",
|
|
41
|
+
"@types/nodemailer": "^6.4.14",
|
|
42
|
+
"@types/web-push": "^3.6.3",
|
|
43
|
+
"@types/node": "^20.9.0",
|
|
44
|
+
"prisma": "^5.6.0",
|
|
45
|
+
"tsx": "^4.23.1",
|
|
46
|
+
"typescript": "^5.2.2"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -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,36 @@
|
|
|
1
|
+
import express, { Request, Response, NextFunction } 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
|
+
app.use(helmet());
|
|
14
|
+
app.use(
|
|
15
|
+
cors({
|
|
16
|
+
origin: process.env.CLIENT_URL || "http://localhost:5173",
|
|
17
|
+
credentials: true,
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
app.use(compression());
|
|
21
|
+
app.use(express.json());
|
|
22
|
+
app.use(express.urlencoded({ extended: true }));
|
|
23
|
+
app.use(cookieParser());
|
|
24
|
+
app.use(morgan("dev"));
|
|
25
|
+
|
|
26
|
+
app.use(apiLimiter);
|
|
27
|
+
app.use("/api", apiRoutes);
|
|
28
|
+
|
|
29
|
+
app.get("/api/health", (req: Request, res: Response) => {
|
|
30
|
+
res.status(200).json({ success: true, message: "API is running" });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
app.use(notFound);
|
|
34
|
+
app.use(errorHandler);
|
|
35
|
+
|
|
36
|
+
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: any) {
|
|
11
|
+
logger.error(`Prisma Database connection failed: ${error.message}`, error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default connectDB;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import nodemailer from "nodemailer";
|
|
2
|
+
import logger from "../utils/logger.js";
|
|
3
|
+
|
|
4
|
+
const sendEmail = async (to: string, subject: string, message: string) => {
|
|
5
|
+
try {
|
|
6
|
+
const transporter = nodemailer.createTransport({
|
|
7
|
+
service: "gmail",
|
|
8
|
+
auth: {
|
|
9
|
+
user: process.env.GMAIL_USER,
|
|
10
|
+
pass: process.env.GMAIL_PASSCODE,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const mailOptions = {
|
|
15
|
+
from: process.env.GMAIL_USER,
|
|
16
|
+
to,
|
|
17
|
+
subject,
|
|
18
|
+
html: message,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const res = await transporter.sendMail(mailOptions);
|
|
22
|
+
logger.success(`Email sent to ${to}: ${res.messageId}`);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
logger.error("Failed to send email", error);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default sendEmail;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Server } from "socket.io";
|
|
2
|
+
import logger from "../utils/logger.js";
|
|
3
|
+
|
|
4
|
+
let io: Server;
|
|
5
|
+
|
|
6
|
+
const userSocketMap: { [key: string]: Set<string> } = {};
|
|
7
|
+
|
|
8
|
+
const initializeSocket = (server: any) => {
|
|
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 as string | undefined;
|
|
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<string>();
|
|
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: string) =>
|
|
50
|
+
userSocketMap[userId] ? Array.from(userSocketMap[userId]) : [];
|
|
51
|
+
|
|
52
|
+
export { io, getReceiverSocketIds, userSocketMap };
|
|
53
|
+
|
|
54
|
+
export default initializeSocket;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { authService } from "../services/auth.service.js";
|
|
3
|
+
import { generateToken } from "../utils/jwt.js";
|
|
4
|
+
import genOtpToken from "../utils/genOtpToken.js";
|
|
5
|
+
import logger from "../utils/logger.js";
|
|
6
|
+
|
|
7
|
+
export const signup = async (req: Request, res: Response, next: NextFunction) => {
|
|
8
|
+
try {
|
|
9
|
+
const { name, email, phone, password } = req.body;
|
|
10
|
+
if (!email || !password || !name) {
|
|
11
|
+
return next({ status: 400, message: "All fields are required." });
|
|
12
|
+
}
|
|
13
|
+
const newUser = await authService.signup({ name, email, phone, password });
|
|
14
|
+
const token = await generateToken(newUser, res);
|
|
15
|
+
const safeUser: any = { ...newUser };
|
|
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
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const login = async (req: Request, res: Response, next: NextFunction) => {
|
|
25
|
+
try {
|
|
26
|
+
const { email, password } = req.body;
|
|
27
|
+
if (!email || !password) {
|
|
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 };
|
|
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);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const logout = async (req: Request, res: Response, next: NextFunction) => {
|
|
42
|
+
try {
|
|
43
|
+
res.clearCookie("token", {
|
|
44
|
+
httpOnly: true,
|
|
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);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const getMe = async (req: Request, res: Response, next: NextFunction) => {
|
|
57
|
+
try {
|
|
58
|
+
res.status(200).json({ message: "User Authenticated", data: req.user });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logger.error("Error in getMe controller", error);
|
|
61
|
+
next(error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const genOtp = async (req: Request, res: Response, next: NextFunction) => {
|
|
66
|
+
try {
|
|
67
|
+
const { email } = req.body;
|
|
68
|
+
if (!email) {
|
|
69
|
+
return next({ status: 400, message: "Email is required." });
|
|
70
|
+
}
|
|
71
|
+
await authService.generateOtp(email);
|
|
72
|
+
res.status(200).json({ message: "Otp sent successfully" });
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.error("Error in genOtp", error);
|
|
75
|
+
next(error);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const verifyOtp = async (req: Request, res: Response, next: NextFunction) => {
|
|
80
|
+
try {
|
|
81
|
+
const { email, otp } = req.body;
|
|
82
|
+
if (!email || !otp) {
|
|
83
|
+
return next({ status: 400, message: "All fields are required." });
|
|
84
|
+
}
|
|
85
|
+
const user = await authService.verifyOtp({ email, otp });
|
|
86
|
+
await genOtpToken(user, res);
|
|
87
|
+
res.status(200).json({ message: "Otp verified successfully" });
|
|
88
|
+
} catch (error) {
|
|
89
|
+
logger.error("Error in verifyOtp", error);
|
|
90
|
+
next(error);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const resetPassword = async (req: Request, res: Response, next: NextFunction) => {
|
|
95
|
+
try {
|
|
96
|
+
const { newPassword } = req.body;
|
|
97
|
+
const currentUser = req.user;
|
|
98
|
+
if (!newPassword) {
|
|
99
|
+
return next({ status: 400, message: "All fields are required." });
|
|
100
|
+
}
|
|
101
|
+
await authService.resetPassword(currentUser, newPassword);
|
|
102
|
+
res.status(200).json({ message: "Password updated successfully" });
|
|
103
|
+
} catch (error) {
|
|
104
|
+
logger.error("Error in resetPassword", error);
|
|
105
|
+
next(error);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const updateMe = async (req: Request, res: Response, next: NextFunction) => {
|
|
110
|
+
try {
|
|
111
|
+
const { name, phone } = req.body;
|
|
112
|
+
const user = await authService.updateProfile(req.user.id, {
|
|
113
|
+
name,
|
|
114
|
+
phone,
|
|
115
|
+
file: req.file,
|
|
116
|
+
});
|
|
117
|
+
const safeUser: any = { ...user };
|
|
118
|
+
delete safeUser.password;
|
|
119
|
+
res.status(200).json({ success: true, data: safeUser });
|
|
120
|
+
} catch (error) {
|
|
121
|
+
logger.error("Error updating profile", error);
|
|
122
|
+
next(error);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { uploadSingleToCloudinary } from "../utils/cloudinaryUpload.js";
|
|
3
|
+
import logger from "../utils/logger.js";
|
|
4
|
+
|
|
5
|
+
export const uploadFile = async (req: Request, res: Response, next: NextFunction) => {
|
|
6
|
+
try {
|
|
7
|
+
if (!req.file) {
|
|
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);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
|
|
7
|
+
dotenv.config();
|
|
8
|
+
|
|
9
|
+
const PORT = process.env.PORT || 5000;
|
|
10
|
+
|
|
11
|
+
connectDB();
|
|
12
|
+
|
|
13
|
+
const server = http.createServer(app);
|
|
14
|
+
|
|
15
|
+
server.listen(PORT, () => {
|
|
16
|
+
logger.success(`Server is running on port ${PORT}`);
|
|
17
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import { verifyToken } from "../utils/jwt.js";
|
|
3
|
+
import logger from "../utils/logger.js";
|
|
4
|
+
import { prisma } from "../config/db.js";
|
|
5
|
+
|
|
6
|
+
export const protect = async (req: Request, res: Response, next: NextFunction) => {
|
|
7
|
+
let token: string | undefined;
|
|
8
|
+
|
|
9
|
+
if (req.cookies?.token) {
|
|
10
|
+
token = req.cookies.token;
|
|
11
|
+
} else if (
|
|
12
|
+
req.headers.authorization &&
|
|
13
|
+
req.headers.authorization.startsWith("Bearer")
|
|
14
|
+
) {
|
|
15
|
+
token = req.headers.authorization.split(" ")[1];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!token) {
|
|
19
|
+
return res.status(401).json({ message: "Not authorized, no token provided" });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const decoded: any = verifyToken(token);
|
|
24
|
+
if (!decoded) {
|
|
25
|
+
return res.status(401).json({ message: "Not authorized, invalid token" });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const user = await prisma.user.findUnique({
|
|
29
|
+
where: { id: decoded.id },
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (!user) {
|
|
33
|
+
return res.status(401).json({ message: "Not authorized, user not found" });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const safeUser: any = { ...user };
|
|
37
|
+
delete safeUser.password;
|
|
38
|
+
|
|
39
|
+
req.user = safeUser;
|
|
40
|
+
return next();
|
|
41
|
+
} catch (error: any) {
|
|
42
|
+
logger.error("Auth middleware error", error);
|
|
43
|
+
return res.status(401).json({ message: "Not authorized, token verification failed" });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
|
|
3
|
+
export const notFound = (req: Request, res: Response, next: NextFunction) => {
|
|
4
|
+
const error = new Error(`Not Found - ${req.originalUrl}`);
|
|
5
|
+
res.status(404);
|
|
6
|
+
next(error);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const errorHandler = (err: any, req: Request, res: Response, next: NextFunction) => {
|
|
10
|
+
const statusCode = err.status || err.statusCode || (res.statusCode === 200 ? 500 : res.statusCode);
|
|
11
|
+
res.status(statusCode).json({
|
|
12
|
+
success: false,
|
|
13
|
+
message: err.message || "An unexpected error occurred",
|
|
14
|
+
stack: process.env.NODE_ENV === "production" ? undefined : err.stack,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import multer, { FileFilterCallback } from "multer";
|
|
2
|
+
import { Request } from "express";
|
|
3
|
+
|
|
4
|
+
const storage = multer.memoryStorage();
|
|
5
|
+
|
|
6
|
+
const fileFilter = (req: Request, file: Express.Multer.File, cb: FileFilterCallback) => {
|
|
7
|
+
if (file.mimetype.startsWith("image/")) {
|
|
8
|
+
cb(null, true);
|
|
9
|
+
} else {
|
|
10
|
+
cb(new Error("Only image files are allowed!"));
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const upload = multer({
|
|
15
|
+
storage,
|
|
16
|
+
fileFilter,
|
|
17
|
+
limits: {
|
|
18
|
+
fileSize: 5 * 1024 * 1024, // 5MB limit
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import rateLimit from "express-rate-limit";
|
|
2
|
+
import { Request, Response } from "express";
|
|
3
|
+
|
|
4
|
+
interface LimiterConfig {
|
|
5
|
+
windowMs: number;
|
|
6
|
+
max: number;
|
|
7
|
+
message: string;
|
|
8
|
+
skipSuccessfulRequests?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const createLimiter = ({
|
|
12
|
+
windowMs,
|
|
13
|
+
max,
|
|
14
|
+
message,
|
|
15
|
+
skipSuccessfulRequests = false,
|
|
16
|
+
}: LimiterConfig) =>
|
|
17
|
+
rateLimit({
|
|
18
|
+
windowMs,
|
|
19
|
+
max,
|
|
20
|
+
standardHeaders: true,
|
|
21
|
+
legacyHeaders: false,
|
|
22
|
+
skipSuccessfulRequests,
|
|
23
|
+
|
|
24
|
+
keyGenerator: (req: any) => {
|
|
25
|
+
return req.user?.id || req.ip || req.headers["x-forwarded-for"] || req.socket.remoteAddress;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
handler: (req: Request, res: Response) => {
|
|
29
|
+
res.status(429).json({
|
|
30
|
+
success: false,
|
|
31
|
+
message,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const apiLimiter = createLimiter({
|
|
37
|
+
windowMs: 15 * 60 * 1000,
|
|
38
|
+
max: 100,
|
|
39
|
+
message: "Too many requests. Please try again later.",
|
|
40
|
+
});
|
|
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
|
+
export const uploadLimiter = createLimiter({
|
|
50
|
+
windowMs: 60 * 60 * 1000,
|
|
51
|
+
max: 20,
|
|
52
|
+
message: "Upload limit reached. Please try again in an hour.",
|
|
53
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import {
|
|
3
|
+
signup,
|
|
4
|
+
login,
|
|
5
|
+
getMe,
|
|
6
|
+
logout,
|
|
7
|
+
updateMe,
|
|
8
|
+
} from "../controllers/auth.controller.js";
|
|
9
|
+
import { protect } from "../middleware/auth.middleware.js";
|
|
10
|
+
import { apiLimiter } from "../middleware/rateLimiter.js";
|
|
11
|
+
|
|
12
|
+
const router = express.Router();
|
|
13
|
+
|
|
14
|
+
router.use(apiLimiter);
|
|
15
|
+
|
|
16
|
+
router.post("/signup", signup);
|
|
17
|
+
router.post("/login", login);
|
|
18
|
+
router.post("/logout", logout);
|
|
19
|
+
router.get("/me", protect, getMe);
|
|
20
|
+
router.put("/me", protect, updateMe);
|
|
21
|
+
|
|
22
|
+
export default router;
|