create-parachute 1.0.2

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.
Files changed (49) hide show
  1. package/README.md +27 -0
  2. package/bin/index.js +474 -0
  3. package/package.json +29 -0
  4. package/templates/mysql/client/index.html +12 -0
  5. package/templates/mysql/client/package.json +18 -0
  6. package/templates/mysql/client/src/App.jsx +5 -0
  7. package/templates/mysql/client/src/api/client.js +6 -0
  8. package/templates/mysql/client/src/components/Navbar.jsx +57 -0
  9. package/templates/mysql/client/src/components/ProtectedRoute.jsx +10 -0
  10. package/templates/mysql/client/src/layouts/DashboardLayout.jsx +21 -0
  11. package/templates/mysql/client/src/main.jsx +9 -0
  12. package/templates/mysql/client/src/pages/Dashboard.jsx +38 -0
  13. package/templates/mysql/client/src/pages/Login.jsx +138 -0
  14. package/templates/mysql/client/src/pages/Page1.jsx +38 -0
  15. package/templates/mysql/client/src/pages/Page2.jsx +38 -0
  16. package/templates/mysql/client/src/pages/Page3.jsx +38 -0
  17. package/templates/mysql/client/src/router/index.jsx +43 -0
  18. package/templates/mysql/client/src/utils/auth.js +16 -0
  19. package/templates/mysql/client/vite.config.js +6 -0
  20. package/templates/mysql/server/config/db.js +13 -0
  21. package/templates/mysql/server/controllers/authController.js +66 -0
  22. package/templates/mysql/server/index.js +39 -0
  23. package/templates/mysql/server/middleware/authMiddleware.js +7 -0
  24. package/templates/mysql/server/package.json +18 -0
  25. package/templates/mysql/server/routes/authRoutes.js +14 -0
  26. package/templates/sequelize/client/index.html +12 -0
  27. package/templates/sequelize/client/package.json +18 -0
  28. package/templates/sequelize/client/src/App.jsx +5 -0
  29. package/templates/sequelize/client/src/api/client.js +6 -0
  30. package/templates/sequelize/client/src/components/Navbar.jsx +57 -0
  31. package/templates/sequelize/client/src/components/ProtectedRoute.jsx +10 -0
  32. package/templates/sequelize/client/src/layouts/DashboardLayout.jsx +21 -0
  33. package/templates/sequelize/client/src/main.jsx +9 -0
  34. package/templates/sequelize/client/src/pages/Dashboard.jsx +38 -0
  35. package/templates/sequelize/client/src/pages/Login.jsx +138 -0
  36. package/templates/sequelize/client/src/pages/Page1.jsx +38 -0
  37. package/templates/sequelize/client/src/pages/Page2.jsx +38 -0
  38. package/templates/sequelize/client/src/pages/Page3.jsx +38 -0
  39. package/templates/sequelize/client/src/router/index.jsx +43 -0
  40. package/templates/sequelize/client/src/utils/auth.js +16 -0
  41. package/templates/sequelize/client/vite.config.js +6 -0
  42. package/templates/sequelize/server/config/db.js +13 -0
  43. package/templates/sequelize/server/config/sequelize.js +17 -0
  44. package/templates/sequelize/server/controllers/authController.js +62 -0
  45. package/templates/sequelize/server/index.js +42 -0
  46. package/templates/sequelize/server/middleware/authMiddleware.js +7 -0
  47. package/templates/sequelize/server/models/User.js +24 -0
  48. package/templates/sequelize/server/package.json +19 -0
  49. package/templates/sequelize/server/routes/authRoutes.js +14 -0
@@ -0,0 +1,138 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useNavigate } from "react-router-dom";
3
+ import { api } from "../api/client";
4
+ import { saveUser } from "../utils/auth";
5
+
6
+ export default function Login() {
7
+ const navigate = useNavigate();
8
+
9
+ const [form, setForm] = useState({
10
+ Username: "",
11
+ Password: ""
12
+ });
13
+
14
+ useEffect(() => {
15
+ if (localStorage.getItem("user")) {
16
+ navigate("/");
17
+ }
18
+ }, [navigate]);
19
+
20
+ const register = async () => {
21
+ try {
22
+ await api.post("/auth/register", form);
23
+ alert("Registered successfully. Now login.");
24
+ } catch (err) {
25
+ alert(err.response?.data?.message || "Registration failed");
26
+ }
27
+ };
28
+
29
+ const login = async () => {
30
+ try {
31
+ const res = await api.post("/auth/login", form);
32
+ saveUser(res.data);
33
+ navigate("/");
34
+ } catch (err) {
35
+ alert(err.response?.data?.message || "Login failed");
36
+ }
37
+ };
38
+
39
+ return (
40
+ <div style={{
41
+ minHeight: "100vh",
42
+ display: "flex",
43
+ justifyContent: "center",
44
+ alignItems: "center",
45
+ background: "#f8fafc",
46
+ fontFamily: "Arial, sans-serif",
47
+ padding: "20px"
48
+ }}>
49
+ <div style={{
50
+ width: "380px",
51
+ background: "white",
52
+ padding: "32px",
53
+ borderRadius: "20px",
54
+ border: "1px solid #e5e7eb",
55
+ boxShadow: "0 1px 5px rgba(0,0,0,0.08)",
56
+ display: "flex",
57
+ flexDirection: "column",
58
+ gap: "14px"
59
+ }}>
60
+ <p style={{
61
+ color: "__THEME__",
62
+ fontWeight: "700",
63
+ margin: 0
64
+ }}>
65
+ Create Parachute
66
+ </p>
67
+
68
+ <h1 style={{
69
+ margin: 0,
70
+ fontSize: "28px"
71
+ }}>
72
+ Login or Register
73
+ </h1>
74
+
75
+ <p style={{
76
+ color: "#6b7280",
77
+ marginTop: 0,
78
+ lineHeight: "1.5"
79
+ }}>
80
+ Use a username and password. Passwords are hashed in the backend.
81
+ </p>
82
+
83
+ <input
84
+ placeholder="Username"
85
+ value={form.Username}
86
+ onChange={(e) => setForm({ ...form, Username: e.target.value })}
87
+ style={{
88
+ padding: "12px",
89
+ border: "1px solid #d1d5db",
90
+ borderRadius: "10px"
91
+ }}
92
+ />
93
+
94
+ <input
95
+ type="password"
96
+ placeholder="Password"
97
+ value={form.Password}
98
+ onChange={(e) => setForm({ ...form, Password: e.target.value })}
99
+ style={{
100
+ padding: "12px",
101
+ border: "1px solid #d1d5db",
102
+ borderRadius: "10px"
103
+ }}
104
+ />
105
+
106
+ <button
107
+ onClick={register}
108
+ style={{
109
+ background: "__THEME__",
110
+ color: "white",
111
+ border: "none",
112
+ padding: "12px",
113
+ borderRadius: "10px",
114
+ cursor: "pointer",
115
+ fontWeight: "700"
116
+ }}
117
+ >
118
+ Register
119
+ </button>
120
+
121
+ <button
122
+ onClick={login}
123
+ style={{
124
+ background: "black",
125
+ color: "white",
126
+ border: "none",
127
+ padding: "12px",
128
+ borderRadius: "10px",
129
+ cursor: "pointer",
130
+ fontWeight: "700"
131
+ }}
132
+ >
133
+ Login
134
+ </button>
135
+ </div>
136
+ </div>
137
+ );
138
+ }
@@ -0,0 +1,38 @@
1
+ import DashboardLayout from "../layouts/DashboardLayout";
2
+
3
+ export default function Page1() {
4
+ return (
5
+ <DashboardLayout>
6
+ <section style={{
7
+ background: "white",
8
+ padding: "32px",
9
+ borderRadius: "18px",
10
+ border: "1px solid #e5e7eb",
11
+ boxShadow: "0 1px 3px rgba(0,0,0,0.06)"
12
+ }}>
13
+ <p style={{
14
+ color: "__THEME__",
15
+ fontWeight: "700",
16
+ marginBottom: "8px"
17
+ }}>
18
+ Ready to customize
19
+ </p>
20
+
21
+ <h1 style={{
22
+ fontSize: "32px",
23
+ marginBottom: "12px"
24
+ }}>
25
+ Welcome to Page 1
26
+ </h1>
27
+
28
+ <p style={{
29
+ color: "#4b5563",
30
+ lineHeight: "1.7"
31
+ }}>
32
+ Start building your own features from this page. Add your forms,
33
+ tables, buttons, and API calls here.
34
+ </p>
35
+ </section>
36
+ </DashboardLayout>
37
+ );
38
+ }
@@ -0,0 +1,38 @@
1
+ import DashboardLayout from "../layouts/DashboardLayout";
2
+
3
+ export default function Page2() {
4
+ return (
5
+ <DashboardLayout>
6
+ <section style={{
7
+ background: "white",
8
+ padding: "32px",
9
+ borderRadius: "18px",
10
+ border: "1px solid #e5e7eb",
11
+ boxShadow: "0 1px 3px rgba(0,0,0,0.06)"
12
+ }}>
13
+ <p style={{
14
+ color: "__THEME__",
15
+ fontWeight: "700",
16
+ marginBottom: "8px"
17
+ }}>
18
+ Ready to customize
19
+ </p>
20
+
21
+ <h1 style={{
22
+ fontSize: "32px",
23
+ marginBottom: "12px"
24
+ }}>
25
+ Welcome to Page 2
26
+ </h1>
27
+
28
+ <p style={{
29
+ color: "#4b5563",
30
+ lineHeight: "1.7"
31
+ }}>
32
+ Start building your own features from this page. Add your forms,
33
+ tables, buttons, and API calls here.
34
+ </p>
35
+ </section>
36
+ </DashboardLayout>
37
+ );
38
+ }
@@ -0,0 +1,38 @@
1
+ import DashboardLayout from "../layouts/DashboardLayout";
2
+
3
+ export default function Page3() {
4
+ return (
5
+ <DashboardLayout>
6
+ <section style={{
7
+ background: "white",
8
+ padding: "32px",
9
+ borderRadius: "18px",
10
+ border: "1px solid #e5e7eb",
11
+ boxShadow: "0 1px 3px rgba(0,0,0,0.06)"
12
+ }}>
13
+ <p style={{
14
+ color: "__THEME__",
15
+ fontWeight: "700",
16
+ marginBottom: "8px"
17
+ }}>
18
+ Ready to customize
19
+ </p>
20
+
21
+ <h1 style={{
22
+ fontSize: "32px",
23
+ marginBottom: "12px"
24
+ }}>
25
+ Welcome to Page 3
26
+ </h1>
27
+
28
+ <p style={{
29
+ color: "#4b5563",
30
+ lineHeight: "1.7"
31
+ }}>
32
+ Start building your own features from this page. Add your forms,
33
+ tables, buttons, and API calls here.
34
+ </p>
35
+ </section>
36
+ </DashboardLayout>
37
+ );
38
+ }
@@ -0,0 +1,43 @@
1
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
2
+
3
+ import ProtectedRoute from "../components/ProtectedRoute";
4
+
5
+ import Login from "../pages/Login";
6
+ import Dashboard from "../pages/Dashboard";
7
+ import Page1 from "../pages/Page1";
8
+ import Page2 from "../pages/Page2";
9
+ import Page3 from "../pages/Page3";
10
+
11
+ export default function Router() {
12
+ return (
13
+ <BrowserRouter>
14
+ <Routes>
15
+ <Route path="/login" element={<Login />} />
16
+
17
+ <Route path="/" element={
18
+ <ProtectedRoute>
19
+ <Dashboard />
20
+ </ProtectedRoute>
21
+ } />
22
+
23
+ <Route path="/page1" element={
24
+ <ProtectedRoute>
25
+ <Page1 />
26
+ </ProtectedRoute>
27
+ } />
28
+
29
+ <Route path="/page2" element={
30
+ <ProtectedRoute>
31
+ <Page2 />
32
+ </ProtectedRoute>
33
+ } />
34
+
35
+ <Route path="/page3" element={
36
+ <ProtectedRoute>
37
+ <Page3 />
38
+ </ProtectedRoute>
39
+ } />
40
+ </Routes>
41
+ </BrowserRouter>
42
+ );
43
+ }
@@ -0,0 +1,16 @@
1
+ export const isAuthenticated = () => {
2
+ return !!localStorage.getItem("user");
3
+ };
4
+
5
+ export const getUser = () => {
6
+ const user = localStorage.getItem("user");
7
+ return user ? JSON.parse(user) : null;
8
+ };
9
+
10
+ export const saveUser = (user) => {
11
+ localStorage.setItem("user", JSON.stringify(user));
12
+ };
13
+
14
+ export const clearUser = () => {
15
+ localStorage.removeItem("user");
16
+ };
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ plugins: [react()]
6
+ });
@@ -0,0 +1,13 @@
1
+ import dotenv from "dotenv";
2
+ import mysql from "mysql2";
3
+
4
+ dotenv.config();
5
+
6
+ const db = mysql.createPool({
7
+ host: process.env.DB_HOST || "localhost",
8
+ user: process.env.DB_USER || "root",
9
+ password: process.env.DB_PASSWORD || "",
10
+ database: process.env.DB_NAME
11
+ });
12
+
13
+ export default db;
@@ -0,0 +1,17 @@
1
+ import dotenv from "dotenv";
2
+ import { Sequelize } from "sequelize";
3
+
4
+ dotenv.config();
5
+
6
+ const sequelize = new Sequelize(
7
+ process.env.DB_NAME,
8
+ process.env.DB_USER || "root",
9
+ process.env.DB_PASSWORD || "",
10
+ {
11
+ host: process.env.DB_HOST || "localhost",
12
+ dialect: "mysql",
13
+ logging: false
14
+ }
15
+ );
16
+
17
+ export default sequelize;
@@ -0,0 +1,62 @@
1
+ import bcrypt from "bcrypt";
2
+ import User from "../models/User.js";
3
+
4
+ export const register = async (req, res) => {
5
+ try {
6
+ const { Username, Password } = req.body;
7
+
8
+ if (!Username || !Password) {
9
+ return res.status(400).json({ message: "Username and Password are required" });
10
+ }
11
+
12
+ const existingUser = await User.findOne({ where: { Username } });
13
+
14
+ if (existingUser) {
15
+ return res.status(409).json({ message: "Username already exists" });
16
+ }
17
+
18
+ const hashedPassword = await bcrypt.hash(Password, 10);
19
+
20
+ await User.create({
21
+ Username,
22
+ Password: hashedPassword
23
+ });
24
+
25
+ res.status(201).json({ message: "Registered successfully" });
26
+ } catch (err) {
27
+ res.status(500).json({ message: "Registration failed", error: err.message });
28
+ }
29
+ };
30
+
31
+ export const login = async (req, res) => {
32
+ try {
33
+ const { Username, Password } = req.body;
34
+
35
+ const user = await User.findOne({ where: { Username } });
36
+
37
+ if (!user) {
38
+ return res.status(404).json({ message: "User not found" });
39
+ }
40
+
41
+ const validPassword = await bcrypt.compare(Password, user.Password);
42
+
43
+ if (!validPassword) {
44
+ return res.status(401).json({ message: "Invalid credentials" });
45
+ }
46
+
47
+ req.session.user = {
48
+ UserID: user.UserID,
49
+ Username: user.Username
50
+ };
51
+
52
+ res.json(req.session.user);
53
+ } catch (err) {
54
+ res.status(500).json({ message: "Login failed", error: err.message });
55
+ }
56
+ };
57
+
58
+ export const logout = (req, res) => {
59
+ req.session.destroy(() => {
60
+ res.json({ message: "Logged out" });
61
+ });
62
+ };
@@ -0,0 +1,42 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import dotenv from "dotenv";
4
+ import session from "express-session";
5
+ import authRoutes from "./routes/authRoutes.js";
6
+ import sequelize from "./config/sequelize.js";
7
+
8
+ dotenv.config();
9
+
10
+ const app = express();
11
+
12
+ app.use(cors({
13
+ origin: process.env.CLIENT_URL,
14
+ credentials: true
15
+ }));
16
+
17
+ app.use(express.json());
18
+
19
+ app.use(session({
20
+ secret: process.env.SESSION_SECRET,
21
+ resave: false,
22
+ saveUninitialized: false,
23
+ cookie: {
24
+ httpOnly: true,
25
+ secure: false
26
+ }
27
+ }));
28
+
29
+ app.use("/auth", authRoutes);
30
+
31
+ app.get("/", (req, res) => {
32
+ res.json({ message: "Parachute backend running" });
33
+ });
34
+
35
+
36
+ await sequelize.authenticate();
37
+ await sequelize.sync();
38
+
39
+
40
+ app.listen(process.env.PORT, () => {
41
+ console.log(`Server running on port ${process.env.PORT}`);
42
+ });
@@ -0,0 +1,7 @@
1
+ export const protect = (req, res, next) => {
2
+ if (!req.session.user) {
3
+ return res.status(401).json({ message: "Unauthorized" });
4
+ }
5
+
6
+ next();
7
+ };
@@ -0,0 +1,24 @@
1
+ import { DataTypes } from "sequelize";
2
+ import sequelize from "../config/sequelize.js";
3
+
4
+ const User = sequelize.define("User", {
5
+ UserID: {
6
+ type: DataTypes.INTEGER,
7
+ primaryKey: true,
8
+ autoIncrement: true
9
+ },
10
+ Username: {
11
+ type: DataTypes.STRING,
12
+ allowNull: false,
13
+ unique: true
14
+ },
15
+ Password: {
16
+ type: DataTypes.STRING,
17
+ allowNull: false
18
+ }
19
+ }, {
20
+ tableName: "Users",
21
+ timestamps: false
22
+ });
23
+
24
+ export default User;
@@ -0,0 +1,19 @@
1
+ {
2
+ "type": "module",
3
+ "scripts": {
4
+ "dev": "nodemon index.js",
5
+ "start": "node index.js"
6
+ },
7
+ "dependencies": {
8
+ "bcrypt": "^5.1.1",
9
+ "cors": "^2.8.5",
10
+ "dotenv": "^16.4.5",
11
+ "express": "^4.19.2",
12
+ "express-session": "^1.18.0",
13
+ "mysql2": "^3.10.3",
14
+ "sequelize": "^6.37.3"
15
+ },
16
+ "devDependencies": {
17
+ "nodemon": "^3.1.4"
18
+ }
19
+ }
@@ -0,0 +1,14 @@
1
+ import express from "express";
2
+ import {
3
+ register,
4
+ login,
5
+ logout
6
+ } from "../controllers/authController.js";
7
+
8
+ const router = express.Router();
9
+
10
+ router.post("/register", register);
11
+ router.post("/login", login);
12
+ router.post("/logout", logout);
13
+
14
+ export default router;