create-fullstack-setup 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 +391 -0
- package/bin/index.js +175 -0
- package/package.json +19 -0
- package/templates/backend/express-js/.env.example +6 -0
- package/templates/backend/express-js/Utils/ApiError.js +17 -0
- package/templates/backend/express-js/Utils/ApiResponse.js +12 -0
- package/templates/backend/express-js/Utils/AsyncHandler.js +8 -0
- package/templates/backend/express-js/Utils/Cloudinary.js +31 -0
- package/templates/backend/express-js/app.js +35 -0
- package/templates/backend/express-js/config/db.js +18 -0
- package/templates/backend/express-js/middlewares/Auth.middleware.js +21 -0
- package/templates/backend/express-js/middlewares/Multer.middleware.js +18 -0
- package/templates/backend/express-js/package.json +17 -0
- package/templates/backend/express-js/server.js +10 -0
- package/templates/backend/express-ts/.env.example +3 -0
- package/templates/backend/express-ts/README.md +0 -0
- package/templates/backend/express-ts/nodemon.json +5 -0
- package/templates/backend/express-ts/package.json +20 -0
- package/templates/backend/express-ts/src/app.ts +14 -0
- package/templates/backend/express-ts/src/config/db.ts +0 -0
- package/templates/backend/express-ts/src/middlewares/auth.middleware.ts +23 -0
- package/templates/backend/express-ts/src/routes/index.ts +0 -0
- package/templates/backend/express-ts/src/server.ts +8 -0
- package/templates/backend/express-ts/src/utils/ApiError.ts +21 -0
- package/templates/backend/express-ts/src/utils/ApiResponse.ts +13 -0
- package/templates/backend/express-ts/src/utils/AsyncHandler.ts +9 -0
- package/templates/backend/express-ts/src/utils/Cloudinary.ts +11 -0
- package/templates/backend/express-ts/tsconfig.json +13 -0
- package/templates/frontend/next-js/app/layout.js +14 -0
- package/templates/frontend/next-js/app/page.js +8 -0
- package/templates/frontend/next-js/jsconfig.json +8 -0
- package/templates/frontend/next-js/next.config.js +6 -0
- package/templates/frontend/next-js/package.json +16 -0
- package/templates/frontend/next-ts/app/layout.tsx +18 -0
- package/templates/frontend/next-ts/app/page.tsx +7 -0
- package/templates/frontend/next-ts/next.config.js +6 -0
- package/templates/frontend/next-ts/package.json +22 -0
- package/templates/frontend/next-ts/tsconfig.json +17 -0
- package/templates/frontend/react-js/index.html +12 -0
- package/templates/frontend/react-js/package.json +19 -0
- package/templates/frontend/react-js/src/App.jsx +8 -0
- package/templates/frontend/react-js/src/index.css +0 -0
- package/templates/frontend/react-js/src/main.jsx +10 -0
- package/templates/frontend/react-js/vite.config.js +6 -0
- package/templates/frontend/react-ts/index.html +12 -0
- package/templates/frontend/react-ts/package.json +21 -0
- package/templates/frontend/react-ts/src/App.tsx +9 -0
- package/templates/frontend/react-ts/src/index.css +0 -0
- package/templates/frontend/react-ts/src/main.tsx +12 -0
- package/templates/frontend/react-ts/tsconfig.json +10 -0
- package/templates/frontend/react-ts/vite.config.ts +6 -0
- package/utils/features.config.js +72 -0
- package/utils/fileOps.js +0 -0
- package/utils/injectFeatures.js +171 -0
- package/utils/installer.js +157 -0
- package/utils/prompts.js +59 -0
- package/utils/replacePlaceholders.js +54 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
dotenv.config();
|
|
3
|
+
import mongoose from "mongoose"
|
|
4
|
+
import { ApiError } from "../Utils/ApiError.js";
|
|
5
|
+
|
|
6
|
+
const connectDB=async()=>{
|
|
7
|
+
try{
|
|
8
|
+
const connectionInstance=await mongoose.connect(process.env.MONGODB_URI);
|
|
9
|
+
console.log("database connected at",connectionInstance.connection.host)
|
|
10
|
+
}
|
|
11
|
+
catch(error){
|
|
12
|
+
throw new ApiError(500,"somthing went wrong while database is connect",error);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default connectDB;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import jwt from "jsonwebtoken";
|
|
2
|
+
import { AsyncHandler } from "../utils/AsyncHandler.js";
|
|
3
|
+
import { ApiError } from "../utils/ApiError.js";
|
|
4
|
+
|
|
5
|
+
export const verifyJWT = AsyncHandler(async (req, res, next) => {
|
|
6
|
+
const token =
|
|
7
|
+
req.cookies?.accessToken ||
|
|
8
|
+
req.header("Authorization")?.split(" ")[1];
|
|
9
|
+
|
|
10
|
+
if (!token) {
|
|
11
|
+
throw new ApiError(401, "Unauthorized request");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const decoded = jwt.verify(
|
|
15
|
+
token,
|
|
16
|
+
process.env.ACCESS_TOKEN_SECRET
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
req.user = decoded;
|
|
20
|
+
next();
|
|
21
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import multer from "multer";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
const storage = multer.diskStorage({
|
|
9
|
+
destination: function (req, file, cb) {
|
|
10
|
+
cb(null, path.join(__dirname, "../../File/temp"));
|
|
11
|
+
},
|
|
12
|
+
filename: function (req, file, cb) {
|
|
13
|
+
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
|
|
14
|
+
cb(null, `${file.fieldname}-${uniqueSuffix}`);
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const upload = multer({ storage });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "nodemon server.js",
|
|
8
|
+
"start": "node server.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"express": "^4.19.0",
|
|
12
|
+
"dotenv": "^16.4.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"nodemon": "^3.0.3"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "nodemon",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/server.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"express": "^4.19.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/express": "^4.17.21",
|
|
16
|
+
"typescript": "^5.4.0",
|
|
17
|
+
"ts-node": "^10.9.2",
|
|
18
|
+
"nodemon": "^3.0.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import express, { Application } from "express";
|
|
2
|
+
|
|
3
|
+
const app: Application = express();
|
|
4
|
+
|
|
5
|
+
app.use(express.json());
|
|
6
|
+
|
|
7
|
+
app.get("/", (_req, res) => {
|
|
8
|
+
res.json({
|
|
9
|
+
success: true,
|
|
10
|
+
message: "Express + TypeScript server running 🚀"
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default app;
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
|
|
4
|
+
export function authMiddleware(
|
|
5
|
+
req: Request,
|
|
6
|
+
res: Response,
|
|
7
|
+
next: NextFunction
|
|
8
|
+
) {
|
|
9
|
+
const token =
|
|
10
|
+
req.headers.authorization?.split(" ")[1] ||
|
|
11
|
+
req.cookies?.token;
|
|
12
|
+
|
|
13
|
+
if (!token) {
|
|
14
|
+
return res.status(401).json({ message: "Unauthorized" });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET as string);
|
|
19
|
+
next();
|
|
20
|
+
} catch {
|
|
21
|
+
return res.status(401).json({ message: "Invalid token" });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
public statusCode: number;
|
|
3
|
+
public errors: unknown[];
|
|
4
|
+
public override stack?: string;
|
|
5
|
+
|
|
6
|
+
constructor(statusCode: number, message = 'failed', errors: unknown[] = [], stack?: string) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'ApiError';
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
this.errors = errors;
|
|
11
|
+
|
|
12
|
+
// restore prototype chain (necessary when targeting ES5)
|
|
13
|
+
Object.setPrototypeOf(this, ApiError.prototype);
|
|
14
|
+
|
|
15
|
+
if (stack) {
|
|
16
|
+
this.stack = stack;
|
|
17
|
+
} else if (typeof Error.captureStackTrace === 'function') {
|
|
18
|
+
Error.captureStackTrace(this, this.constructor);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class ApiResponse<T = any> {
|
|
2
|
+
statusCode: number;
|
|
3
|
+
data: T | null;
|
|
4
|
+
message: string;
|
|
5
|
+
success: boolean;
|
|
6
|
+
|
|
7
|
+
constructor(statusCode: number, data: T | null = null, message = "success", success = true) {
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
this.data = data;
|
|
10
|
+
this.message = message;
|
|
11
|
+
this.success = success;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Request, Response, NextFunction, RequestHandler } from "express";
|
|
2
|
+
|
|
3
|
+
const AsyncHandler = (reqHandler: RequestHandler): RequestHandler => {
|
|
4
|
+
return (req: Request, res: Response, next: NextFunction): void => {
|
|
5
|
+
Promise.resolve(reqHandler(req, res, next)).catch(next);
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export { AsyncHandler };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { v2 as cloudinary } from "cloudinary";
|
|
2
|
+
|
|
3
|
+
export function connectCloudinary() {
|
|
4
|
+
cloudinary.config({
|
|
5
|
+
cloud_name: process.env.CLOUDINARY_NAME,
|
|
6
|
+
api_key: process.env.CLOUDINARY_API_KEY,
|
|
7
|
+
api_secret: process.env.CLOUDINARY_API_SECRET
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
console.log("☁️ Cloudinary connected");
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const metadata = {
|
|
2
|
+
title: "Next App",
|
|
3
|
+
description: "Generated by create-fullstack-app"
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export default function RootLayout({ children }) {
|
|
7
|
+
return (
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<body style={{ margin: 0, fontFamily: "sans-serif" }}>
|
|
10
|
+
{children}
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"next": "^14.1.0",
|
|
13
|
+
"react": "^18.2.0",
|
|
14
|
+
"react-dom": "^18.2.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const metadata = {
|
|
2
|
+
title: "Next App",
|
|
3
|
+
description: "Generated by create-fullstack-app"
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export default function RootLayout({
|
|
7
|
+
children
|
|
8
|
+
}: {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}) {
|
|
11
|
+
return (
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<body style={{ margin: 0, fontFamily: "sans-serif" }}>
|
|
14
|
+
{children}
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"next": "^14.1.0",
|
|
13
|
+
"react": "^18.2.0",
|
|
14
|
+
"react-dom": "^18.2.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"typescript": "^5.3.0",
|
|
18
|
+
"@types/react": "^18.2.0",
|
|
19
|
+
"@types/react-dom": "^18.2.0",
|
|
20
|
+
"@types/node": "^20.10.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
5
|
+
"allowJs": false,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"module": "ESNext",
|
|
10
|
+
"moduleResolution": "Bundler",
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"jsx": "preserve"
|
|
14
|
+
},
|
|
15
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
16
|
+
"exclude": ["node_modules"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>React App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react": "^18.2.0",
|
|
13
|
+
"react-dom": "^18.2.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@vitejs/plugin-react": "^4.2.0",
|
|
17
|
+
"vite": "^5.0.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>React TS App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"preview": "vite preview"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"react": "^18.2.0",
|
|
12
|
+
"react-dom": "^18.2.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/react": "^18.2.0",
|
|
16
|
+
"@types/react-dom": "^18.2.0",
|
|
17
|
+
"@vitejs/plugin-react": "^4.2.0",
|
|
18
|
+
"typescript": "^5.3.0",
|
|
19
|
+
"vite": "^5.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ReactDOM from "react-dom/client";
|
|
3
|
+
import App from "./App";
|
|
4
|
+
import "./index.css";
|
|
5
|
+
|
|
6
|
+
ReactDOM.createRoot(
|
|
7
|
+
document.getElementById("root") as HTMLElement
|
|
8
|
+
).render(
|
|
9
|
+
<React.StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
</React.StrictMode>
|
|
12
|
+
);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* -------------------------------------------------------------------------- */
|
|
2
|
+
/* Backend Feature Configuration */
|
|
3
|
+
/* -------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
export const FEATURES = {
|
|
6
|
+
/* =============================== CORS ================================= */
|
|
7
|
+
|
|
8
|
+
CORS: {
|
|
9
|
+
middleware: `
|
|
10
|
+
import cors from "cors";
|
|
11
|
+
app.use(cors());
|
|
12
|
+
`.trim(),
|
|
13
|
+
env: []
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/* =========================== COOKIE PARSER ============================= */
|
|
17
|
+
|
|
18
|
+
"Cookie-Parser": {
|
|
19
|
+
middleware: `
|
|
20
|
+
import cookieParser from "cookie-parser";
|
|
21
|
+
app.use(cookieParser());
|
|
22
|
+
`.trim(),
|
|
23
|
+
env: []
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/* ================================ JWT ================================= */
|
|
27
|
+
|
|
28
|
+
JWT: {
|
|
29
|
+
middleware: "",
|
|
30
|
+
files: {
|
|
31
|
+
js: [
|
|
32
|
+
{
|
|
33
|
+
path: "middlewares/Auth.middleware.js",
|
|
34
|
+
fromTemplate:true,
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
ts: [
|
|
38
|
+
{
|
|
39
|
+
path: "src/middlewares/auth.middleware.ts",
|
|
40
|
+
fromTemplate:true,
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/* ============================ CLOUDINARY ============================== */
|
|
47
|
+
|
|
48
|
+
Cloudinary: {
|
|
49
|
+
middleware: "",
|
|
50
|
+
files: {
|
|
51
|
+
js: [
|
|
52
|
+
{
|
|
53
|
+
path: "Utils/Cloudinary.js",
|
|
54
|
+
fromTemplate:true
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
ts: [
|
|
58
|
+
{
|
|
59
|
+
path: "src/utils/Cloudinary.ts",
|
|
60
|
+
fromTemplate:true,
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/* ============================== DOTENV ================================ */
|
|
67
|
+
|
|
68
|
+
Dotenv: {
|
|
69
|
+
middleware: `import "dotenv/config";`,
|
|
70
|
+
env: ["PORT=5000"]
|
|
71
|
+
}
|
|
72
|
+
};
|
package/utils/fileOps.js
ADDED
|
File without changes
|