create-backlist 2.0.0 β†’ 3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2025] [W.A.H.ISHAN]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # πŸš€ Create Backlist
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/create-backlist.svg)](https://www.npmjs.com/package/create-backlist)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Tired of manually creating backend boilerplate every time you build a frontend? **`create-backlist`** is an intelligent CLI tool that analyzes your frontend project and automatically generates a backend with all the necessary routes and controllers, saving you hours of repetitive work.
7
+
8
+ It's not just another scaffolder; it's a **context-aware, dynamic code generator** that builds a backend tailor-made for your frontend's specific API needs.
9
+
10
+ ![Demo GIF (Optional: Add a GIF of your tool in action here)](link-to-your-demo-gif.gif)
11
+
12
+ ## ✨ Key Features
13
+
14
+ - **πŸ€– Intelligent Code Analysis:** Scans your frontend codebase (React, Vue, etc.) using Abstract Syntax Trees (ASTs) to detect API calls (`fetch` requests).
15
+ - **🌐 Multi-Language Support:** Generate a backend in your preferred stack.
16
+ - βœ… **Currently Supports:**
17
+ - Node.js (with TypeScript & Express)
18
+ - C# (with ASP.NET Core Web API)
19
+ - ⏳ **Coming Soon:**
20
+ - Python (with FastAPI)
21
+ - Java (with Spring Boot)
22
+ - **⚑️ Fully Automated:** A single command handles everything from project scaffolding to dependency installation.
23
+ - **πŸ”§ Zero-Configuration:** No complex config files needed. Just run the command and answer a few simple questions.
24
+ - **🧼 Clean Code Generation:** Creates a well-structured backend, ready for you to implement your business logic.
25
+
26
+ ## πŸ“¦ Installation & Usage
27
+
28
+ No global installation needed! Just run this command inside your existing frontend project's root directory:
29
+
30
+ ```bash
31
+ npm create backlist@latest
32
+ ```
33
+
34
+ The tool will then guide you through an interactive setup process:
35
+
36
+ 1. **Enter a name for your backend directory:** (default: `backend`)
37
+ 2. **Select the backend stack:** (e.g., `Node.js (TypeScript, Express)`)
38
+ 3. **Enter the path to your frontend `src` directory:** (default: `src`)
39
+
40
+ That's it! The tool will analyze your code, generate the backend in a new directory, and install all the necessary dependencies.
41
+
42
+ ### Example
43
+
44
+ Let's say your frontend has this API call:
45
+
46
+ ```javascript
47
+ // in your React component
48
+ fetch('/api/products/123', { method: 'PUT' });
49
+ ```
50
+
51
+ `create-backlist` will automatically generate a backend with a `products` controller and a `PUT` route for `products/:id`.
52
+
53
+ ## πŸ’‘ How It's Different from Other Tools
54
+
55
+ | Tool | Approach | Use Case |
56
+ | --------------------- | -------------------------------------- | ----------------------------------------------------------- |
57
+ | **Express Generator** | Static Scaffolding | Quickly start a *new, empty* Express project. |
58
+ | **NestJS CLI** | Static Scaffolding & Code Generation | Start a *new, structured* NestJS project and add parts manually. |
59
+ | **`create-backlist`** | **Dynamic & Context-Aware Scaffolding** | Generate a backend that is **tailor-made** for an *existing* frontend. |
60
+
61
+ While traditional generators give you a blank canvas, `create-backlist` looks at your finished painting (the frontend) and builds the perfect frame (the backend) for it.
62
+
63
+ ## πŸ—ΊοΈ Roadmap
64
+
65
+ `create-backlist` is actively being developed. Here are some of the features planned for future releases:
66
+
67
+ - [ ] **Python Support:** Generate a backend using FastAPI.
68
+ - [ ] **Java Support:** Generate a backend using Spring Boot.
69
+ - [ ] **Database Model Generation:** Automatically create basic database models (e.g., Mongoose, Prisma) based on `POST`/`PUT` request bodies.
70
+ - [ ] **Authentication Boilerplate:** Add an option to generate basic JWT-based authentication routes (`/login`, `/register`).
71
+
72
+ Have an idea for a new feature? Feel free to [open an issue](https://github.com/WAH-ISHAN/create-backlist/issues) on GitHub!
73
+
74
+ ## πŸ› οΈ Contributing
75
+
76
+ Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
77
+
78
+ 1. Fork the Project
79
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
80
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
81
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
82
+ 5. Open a Pull Request
83
+
84
+ ## πŸ“„ License
85
+
86
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
87
+
88
+ ## πŸ™ Acknowledgements
89
+
90
+ - **Babel** for the amazing AST parser.
91
+ - **Inquirer.js** for the interactive CLI prompts.
92
+ - **fs-extra** for making file system operations a breeze.
93
+ - **Google's Gemini** for assistance with brainstorming and debugging.
94
+
95
+ ---
96
+
97
+ _Built with ❀️ by [W.A.H. ISHAN](https://github.com/WAH-ISHAN)._
package/bin/index.js CHANGED
@@ -38,11 +38,21 @@ async function main() {
38
38
  name: 'srcPath',
39
39
  message: 'Enter the path to your frontend `src` directory:',
40
40
  default: 'src',
41
+ },
42
+ // --- NEW QUESTION FOR V3.0 ---
43
+ {
44
+ type: 'confirm',
45
+ name: 'addAuth',
46
+ message: 'Do you want to add basic JWT authentication? (generates a User model, login/register routes)',
47
+ default: true,
48
+ // This question will only be asked if the user selects the Node.js stack
49
+ when: (answers) => answers.stack === 'node-ts-express'
41
50
  }
42
51
  ]);
43
52
 
53
+ // Pass all answers to the options object
44
54
  const options = {
45
- ...answers,
55
+ ...answers,
46
56
  projectDir: path.resolve(process.cwd(), answers.projectName),
47
57
  frontendSrcDir: path.resolve(process.cwd(), answers.srcPath),
48
58
  };
@@ -53,7 +63,7 @@ async function main() {
53
63
  // --- Dispatcher Logic ---
54
64
  switch (options.stack) {
55
65
  case 'node-ts-express':
56
- await generateNodeProject(options);
66
+ await generateNodeProject(options); // Pass the entire options object
57
67
  break;
58
68
 
59
69
  case 'dotnet-webapi':
@@ -61,6 +71,7 @@ async function main() {
61
71
  throw new Error('.NET SDK is not installed. Please install it from https://dotnet.microsoft.com/download');
62
72
  }
63
73
  await generateDotnetProject(options);
74
+
64
75
  break;
65
76
 
66
77
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-backlist",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "An advanced, multi-language backend generator based on frontend analysis.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -5,137 +5,163 @@ const path = require('path');
5
5
  const { analyzeFrontend } = require('../analyzer');
6
6
  const { renderAndWrite, getTemplatePath } = require('./template');
7
7
 
8
- /**
9
- * Generate a Node.js + TypeScript (Express) backend project automatically.
10
- */
11
8
  async function generateNodeProject(options) {
12
- const { projectDir, projectName, frontendSrcDir } = options;
9
+ const { projectDir, projectName, frontendSrcDir, addAuth } = options;
13
10
 
14
11
  try {
15
- // --- Step 1: Analyze Frontend ---
16
- console.log(chalk.blue(' -> Analyzing frontend for API endpoints...'));
12
+ // --- Step 1: Analyze Frontend to get Endpoints and Schema Info ---
13
+ console.log(chalk.blue(' -> Analyzing frontend for API endpoints...'));
17
14
  const endpoints = await analyzeFrontend(frontendSrcDir);
18
-
19
15
  if (endpoints.length > 0) {
20
- console.log(chalk.green(` -> Found ${endpoints.length} endpoints.`));
16
+ console.log(chalk.green(` -> Found ${endpoints.length} endpoints.`));
21
17
  } else {
22
- console.log(
23
- chalk.yellow(' -> No API endpoints found. A basic project will be created.')
24
- );
18
+ console.log(chalk.yellow(' -> No API endpoints found. A basic project will be created.'));
25
19
  }
26
20
 
27
- // --- Step 2: Scaffold Base Project ---
28
- console.log(chalk.blue(' -> Scaffolding Node.js (Express + TS) project...'));
29
-
30
- const baseDir = getTemplatePath('node-ts-express/base');
31
- const serverTemplatePath = path.join(baseDir, 'server.ts');
32
- const tsconfigTemplatePath = path.join(baseDir, 'tsconfig.json');
33
-
34
- const destSrcDir = path.join(projectDir, 'src');
35
- const serverDestPath = path.join(destSrcDir, 'server.ts');
36
- const tsconfigDestPath = path.join(projectDir, 'tsconfig.json');
37
-
38
- await fs.ensureDir(destSrcDir);
39
- await fs.copy(serverTemplatePath, serverDestPath);
40
- await fs.copy(tsconfigTemplatePath, tsconfigDestPath);
41
-
42
- console.log(chalk.gray(' -> Base server.ts and tsconfig.json copied.'));
43
-
44
- // --- Step 3: Generate package.json and routes.ts ---
45
- await renderAndWrite(
46
- getTemplatePath('node-ts-express/partials/package.json.ejs'),
47
- path.join(projectDir, 'package.json'),
48
- { projectName }
49
- );
50
-
51
- await renderAndWrite(
52
- getTemplatePath('node-ts-express/partials/routes.ts.ejs'),
53
- path.join(destSrcDir, 'routes.ts'),
54
- { endpoints }
55
- );
56
-
57
- console.log(chalk.gray(' -> package.json and routes.ts generated.'));
58
-
59
- // --- Step 4: Analyze endpoints for models/controllers ---
21
+ // --- Step 2: Identify which Database Models to Generate ---
60
22
  const modelsToGenerate = new Map();
61
-
62
- endpoints.forEach((ep) => {
63
- if (ep.schemaFields && !modelsToGenerate.has(ep.controllerName)) {
23
+ endpoints.forEach(ep => {
24
+ if (ep.schemaFields && ep.controllerName !== 'Default' && !modelsToGenerate.has(ep.controllerName)) {
64
25
  modelsToGenerate.set(ep.controllerName, ep.schemaFields);
65
26
  }
66
27
  });
67
28
 
68
- // --- Step 5: Generate Models and Controllers if applicable ---
69
- if (modelsToGenerate.size > 0) {
70
- console.log(chalk.blue(' -> Generating database models and controllers...'));
29
+ // If auth is enabled, we MUST have a 'User' model.
30
+ if (addAuth && !modelsToGenerate.has('User')) {
31
+ console.log(chalk.yellow(' -> Authentication requires a "User" model. Creating a default one.'));
32
+ modelsToGenerate.set('User', { name: 'String', email: 'String', password: 'String' });
33
+ }
71
34
 
72
- await fs.ensureDir(path.join(projectDir, 'src', 'models'));
73
- await fs.ensureDir(path.join(projectDir, 'src', 'controllers'));
35
+ // --- Step 3: Scaffold Base Project Structure & Files ---
36
+ console.log(chalk.blue(' -> Scaffolding Node.js (Express + TS) project...'));
37
+ const destSrcDir = path.join(projectDir, 'src');
38
+ await fs.ensureDir(destSrcDir);
39
+ await fs.copy(getTemplatePath('node-ts-express/base/server.ts'), path.join(destSrcDir, 'server.ts'));
40
+ await fs.copy(getTemplatePath('node-ts-express/base/tsconfig.json'), path.join(projectDir, 'tsconfig.json'));
41
+
42
+ // --- Step 4: Prepare and Write package.json ---
43
+ const packageJsonContent = JSON.parse(
44
+ await ejs.renderFile(getTemplatePath('node-ts-express/partials/package.json.ejs'), { projectName })
45
+ );
74
46
 
75
- for (const [modelName, schema] of modelsToGenerate.entries()) {
76
- // Generate Model file
47
+ if (modelsToGenerate.size > 0 || addAuth) {
48
+ packageJsonContent.dependencies['mongoose'] = '^7.5.0';
49
+ }
50
+ if (addAuth) {
51
+ packageJsonContent.dependencies['jsonwebtoken'] = '^9.0.2';
52
+ packageJsonContent.dependencies['bcryptjs'] = '^2.4.3';
53
+ packageJsonContent.devDependencies['@types/jsonwebtoken'] = '^9.0.2';
54
+ packageJsonContent.devDependencies['@types/bcryptjs'] = '^2.4.2';
55
+ }
56
+ await fs.writeJson(path.join(projectDir, 'package.json'), packageJsonContent, { spaces: 2 });
57
+
58
+ // --- Step 5: Generate Models and Controllers ---
59
+ if (modelsToGenerate.size > 0) {
60
+ console.log(chalk.blue(' -> Generating database models and controllers...'));
61
+ await fs.ensureDir(path.join(destSrcDir, 'models'));
62
+ await fs.ensureDir(path.join(destSrcDir, 'controllers'));
63
+
64
+ for (let [modelName, schema] of modelsToGenerate.entries()) {
65
+ if (addAuth && modelName === 'User') {
66
+ schema = { name: 'String', email: 'String', password: 'String', ...schema };
67
+ }
77
68
  await renderAndWrite(
78
69
  getTemplatePath('node-ts-express/partials/Model.ts.ejs'),
79
- path.join(projectDir, 'src', 'models', `${modelName}.model.ts`),
70
+ path.join(destSrcDir, 'models', `${modelName}.model.ts`),
80
71
  { modelName, schema }
81
72
  );
82
-
83
- // Generate Controller file
84
73
  await renderAndWrite(
85
74
  getTemplatePath('node-ts-express/partials/Controller.ts.ejs'),
86
- path.join(projectDir, 'src', 'controllers', `${modelName}.controller.ts`),
75
+ path.join(destSrcDir, 'controllers', `${modelName}.controller.ts`),
87
76
  { modelName }
88
77
  );
89
78
  }
90
-
91
- console.log(chalk.gray(' -> Models and controllers generated.'));
79
+ }
80
+
81
+ // --- Step 6 (v3.0): Generate Authentication Boilerplate ---
82
+ if (addAuth) {
83
+ console.log(chalk.blue(' -> Generating authentication boilerplate...'));
84
+ await fs.ensureDir(path.join(destSrcDir, 'routes'));
85
+ await fs.ensureDir(path.join(destSrcDir, 'middleware'));
86
+
87
+ await renderAndWrite(getTemplatePath('node-ts-express/partials/Auth.controller.ts.ejs'), path.join(destSrcDir, 'controllers', 'Auth.controller.ts'), {});
88
+ await renderAndWrite(getTemplatePath('node-ts-express/partials/Auth.routes.ts.ejs'), path.join(destSrcDir, 'routes', 'Auth.routes.ts'), {});
89
+ await renderAndWrite(getTemplatePath('node-ts-express/partials/Auth.middleware.ts.ejs'), path.join(destSrcDir, 'middleware', 'Auth.middleware.ts'), {});
90
+
91
+ // Modify the User model to add password hashing
92
+ const userModelPath = path.join(destSrcDir, 'models', 'User.model.ts');
93
+ if (await fs.pathExists(userModelPath)) {
94
+ let userModelContent = await fs.readFile(userModelPath, 'utf-8');
95
+ if (!userModelContent.includes('bcryptjs')) {
96
+ userModelContent = userModelContent.replace(`import mongoose, { Schema, Document } from 'mongoose';`, `import mongoose, { Schema, Document } from 'mongoose';\nimport bcrypt from 'bcryptjs';`);
97
+ const preSaveHook = `
98
+ // Hash password before saving
99
+ UserSchema.pre('save', async function(next) {
100
+ if (!this.isModified('password')) {
101
+ return next();
102
+ }
103
+ const salt = await bcrypt.genSalt(10);
104
+ this.password = await bcrypt.hash(this.password, salt);
105
+ next();
106
+ });
107
+ `;
108
+ userModelContent = userModelContent.replace(`// Create and export the Model`, `${preSaveHook}\n// Create and export the Model`);
109
+ await fs.writeFile(userModelPath, userModelContent);
110
+ }
111
+ }
92
112
  }
93
113
 
94
- // --- Step 6: Modify server.ts ---
95
- if (!(await fs.pathExists(serverDestPath))) {
96
- throw new Error(`Critical error: server.ts was not found at ${serverDestPath}.`);
114
+ // --- Step 7: Generate the Main Route File ---
115
+ console.log(chalk.gray(' -> Generating dynamic API routes...'));
116
+ await renderAndWrite(getTemplatePath('node-ts-express/partials/routes.ts.ejs'), path.join(destSrcDir, 'routes.ts'), { endpoints, addAuth });
117
+
118
+ // --- Step 8: Inject Logic into Main Server File ---
119
+ let serverFileContent = await fs.readFile(path.join(destSrcDir, 'server.ts'), 'utf-8');
120
+
121
+ let dbConnectionCode = '';
122
+ if (modelsToGenerate.size > 0 || addAuth) {
123
+ dbConnectionCode = `
124
+ // --- Database Connection ---
125
+ import mongoose from 'mongoose';
126
+ const MONGO_URI = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/${projectName}';
127
+ mongoose.connect(MONGO_URI)
128
+ .then(() => console.log('MongoDB Connected...'))
129
+ .catch(err => console.error('MongoDB Connection Error:', err));
130
+ // -------------------------
131
+ `;
97
132
  }
98
133
 
99
- let serverFileContent = await fs.readFile(serverDestPath, 'utf-8');
100
- serverFileContent = serverFileContent.replace(
101
- '// INJECT:ROUTES',
102
- `import apiRoutes from './routes';\napp.use(apiRoutes);`
103
- );
104
- await fs.writeFile(serverDestPath, serverFileContent);
134
+ let authRoutesInjector = '';
135
+ if (addAuth) {
136
+ authRoutesInjector = `import authRoutes from './routes/Auth.routes';\napp.use('/api/auth', authRoutes);\n\n`;
137
+ }
105
138
 
106
- console.log(chalk.gray(' -> server.ts modified successfully.'));
139
+ serverFileContent = serverFileContent
140
+ .replace("dotenv.config();", `dotenv.config();\n${dbConnectionCode}`)
141
+ .replace('// INJECT:ROUTES', `${authRoutesInjector}import apiRoutes from './routes';\napp.use('/api', apiRoutes);`); // Changed to /api
142
+
143
+ await fs.writeFile(path.join(destSrcDir, 'server.ts'), serverFileContent);
107
144
 
108
- // --- Step 7: Install dependencies ---
109
- console.log(chalk.magenta(' -> Installing dependencies (npm install)...'));
145
+ // --- Step 9: Install All Dependencies ---
146
+ console.log(chalk.magenta(' -> Installing all dependencies... This might take a moment.'));
110
147
  await execa('npm', ['install'], { cwd: projectDir });
111
148
 
112
- // --- Step 8: Add mongoose if models were generated ---
113
- if (modelsToGenerate.size > 0) {
114
- console.log(chalk.gray(' -> Adding Mongoose to dependencies...'));
115
-
116
- const packageJsonPath = path.join(projectDir, 'package.json');
117
- const packageJson = await fs.readJson(packageJsonPath);
118
- packageJson.dependencies = packageJson.dependencies || {};
119
- packageJson.dependencies['mongoose'] = '^7.5.0';
120
-
121
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
122
-
123
- console.log(chalk.magenta(' -> Installing new dependencies (mongoose)...'));
124
- await execa('npm', ['install'], { cwd: projectDir });
125
- }
126
-
127
- // --- Step 9: Generate README ---
149
+ // --- Step 10: Generate Final Files (README, .env.example) ---
128
150
  await renderAndWrite(
129
151
  getTemplatePath('node-ts-express/partials/README.md.ejs'),
130
152
  path.join(projectDir, 'README.md'),
131
153
  { projectName }
132
154
  );
155
+
156
+ if (addAuth) {
157
+ const envExampleContent = `PORT=8000\nMONGO_URI=mongodb://127.0.0.1:27017/${projectName}\nJWT_SECRET=your_super_secret_jwt_key_123`;
158
+ await fs.writeFile(path.join(projectDir, '.env.example'), envExampleContent);
159
+ }
160
+
133
161
 
134
- console.log(chalk.green('βœ… Project generation completed successfully!'));
135
162
  } catch (error) {
136
- console.error(chalk.red('❌ Error generating Node project:'), error);
137
- throw error; // Pass to main CLI handler
163
+ throw error;
138
164
  }
139
165
  }
140
166
 
141
- module.exports = { generateNodeProject };
167
+ module.exports = { generateNodeProject };
@@ -0,0 +1,89 @@
1
+ // Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
2
+ import { Request, Response } from 'express';
3
+ import bcrypt from 'bcryptjs';
4
+ import jwt from 'jsonwebtoken';
5
+ import User, { IUser } from '../models/User.model'; // We assume the model is named 'User'
6
+
7
+ // @desc Register a new user
8
+ export const registerUser = async (req: Request, res: Response) => {
9
+ const { name, email, password } = req.body;
10
+
11
+ try {
12
+ // Check if user already exists
13
+ let user = await User.findOne({ email });
14
+ if (user) {
15
+ return res.status(400).json({ message: 'User already exists' });
16
+ }
17
+
18
+ // Create a new user instance
19
+ user = new User({
20
+ name,
21
+ email,
22
+ password, // Password will be hashed by the pre-save hook in the model
23
+ });
24
+
25
+ // Save the user to the database
26
+ await user.save();
27
+
28
+ // Create JWT Payload
29
+ const payload = {
30
+ user: {
31
+ id: user.id,
32
+ },
33
+ };
34
+
35
+ // Sign the token
36
+ jwt.sign(
37
+ payload,
38
+ process.env.JWT_SECRET as string,
39
+ { expiresIn: '5h' }, // Token expires in 5 hours
40
+ (err, token) => {
41
+ if (err) throw err;
42
+ res.status(201).json({ token });
43
+ }
44
+ );
45
+ } catch (error) {
46
+ console.error(error);
47
+ res.status(500).send('Server Error');
48
+ }
49
+ };
50
+
51
+ // @desc Authenticate user & get token (Login)
52
+ export const loginUser = async (req: Request, res: Response) => {
53
+ const { email, password } = req.body;
54
+
55
+ try {
56
+ // Check if user exists
57
+ const user = await User.findOne({ email });
58
+ if (!user) {
59
+ return res.status(400).json({ message: 'Invalid Credentials' });
60
+ }
61
+
62
+ // Compare entered password with stored hashed password
63
+ const isMatch = await bcrypt.compare(password, user.password);
64
+ if (!isMatch) {
65
+ return res.status(400).json({ message: 'Invalid Credentials' });
66
+ }
67
+
68
+ // Create JWT Payload
69
+ const payload = {
70
+ user: {
71
+ id: user.id,
72
+ },
73
+ };
74
+
75
+ // Sign the token
76
+ jwt.sign(
77
+ payload,
78
+ process.env.JWT_SECRET as string,
79
+ { expiresIn: '5h' },
80
+ (err, token) => {
81
+ if (err) throw err;
82
+ res.json({ token });
83
+ }
84
+ );
85
+ } catch (error) {
86
+ console.error(error);
87
+ res.status(500).send('Server Error');
88
+ }
89
+ };
@@ -0,0 +1,27 @@
1
+ // Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
2
+ import { Request, Response, NextFunction } from 'express';
3
+ import jwt from 'jsonwebtoken';
4
+
5
+ // Extend the default Request interface to include our 'user' property
6
+ interface AuthRequest extends Request {
7
+ user?: any;
8
+ }
9
+
10
+ export const protect = (req: AuthRequest, res: Response, next: NextFunction) => {
11
+ // Get token from header
12
+ const token = req.header('x-auth-token');
13
+
14
+ // Check if not token
15
+ if (!token) {
16
+ return res.status(401).json({ message: 'No token, authorization denied' });
17
+ }
18
+
19
+ // Verify token
20
+ try {
21
+ const decoded = jwt.verify(token, process.env.JWT_SECRET as string);
22
+ req.user = decoded.user;
23
+ next();
24
+ } catch (err) {
25
+ res.status(401).json({ message: 'Token is not valid' });
26
+ }
27
+ };
@@ -0,0 +1,15 @@
1
+ // Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
2
+ import { Router } from 'express';
3
+ import { registerUser, loginUser } from '../controllers/Auth.controller';
4
+
5
+ const router = Router();
6
+
7
+ // @route POST /api/auth/register
8
+ // @desc Register a new user
9
+ router.post('/register', registerUser);
10
+
11
+ // @route POST /api/auth/login
12
+ // @desc Authenticate user and get token
13
+ router.post('/login', loginUser);
14
+
15
+ export default router;
@@ -1,4 +1,4 @@
1
- // Auto-generated by create-backlist on <%= new Date().toISOString() %>
1
+ // Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
2
2
  import { Router, Request, Response } from 'express';
3
3
  <%# Create a unique set of controller names from the endpoints array %>
4
4
  <% const controllersToImport = new Set(endpoints.map(ep => ep.controllerName).filter(name => name !== 'Default')); %>
@@ -8,6 +8,11 @@ import { Router, Request, Response } from 'express';
8
8
  import * as <%= controller %>Controller from '../controllers/<%= controller %>.controller';
9
9
  <% } %>
10
10
 
11
+ <%# Import the protect middleware only if authentication is enabled %>
12
+ <% if (addAuth) { %>
13
+ import { protect } from '../middleware/Auth.middleware';
14
+ <% } %>
15
+
11
16
  const router = Router();
12
17
 
13
18
  <%# Loop through each endpoint found by the analyzer %>
@@ -19,41 +24,40 @@ const router = Router();
19
24
  let handlerFunction;
20
25
 
21
26
  // --- LOGIC TO MAP ENDPOINT TO A CRUD CONTROLLER FUNCTION ---
22
- // This logic assumes a standard RESTful API structure.
23
-
24
27
  if (controllerName !== 'Default') {
25
28
  if (endpoint.method === 'POST' && !expressPath.includes(':')) {
26
- // e.g., POST /users -> create a new user
27
29
  handlerFunction = `${controllerName}Controller.create${controllerName}`;
28
30
  } else if (endpoint.method === 'GET' && !expressPath.includes(':')) {
29
- // e.g., GET /users -> get all users
30
31
  handlerFunction = `${controllerName}Controller.getAll${controllerName}s`;
31
32
  } else if (endpoint.method === 'GET' && expressPath.includes(':')) {
32
- // e.g., GET /users/:id -> get a single user by ID
33
33
  handlerFunction = `${controllerName}Controller.get${controllerName}ById`;
34
34
  } else if (endpoint.method === 'PUT' && expressPath.includes(':')) {
35
- // e.g., PUT /users/:id -> update a user by ID
36
35
  handlerFunction = `${controllerName}Controller.update${controllerName}ById`;
37
36
  } else if (endpoint.method === 'DELETE' && expressPath.includes(':')) {
38
- // e.g., DELETE /users/:id -> delete a user by ID
39
37
  handlerFunction = `${controllerName}Controller.delete${controllerName}ById`;
40
38
  }
41
39
  }
42
40
 
43
- // If no specific CRUD function matches, or if it's a default/unhandled route,
44
- // create a simple placeholder function.
41
+ // If no specific CRUD function matches, create a placeholder handler.
45
42
  if (!handlerFunction) {
46
43
  handlerFunction = `(req: Request, res: Response) => {
47
- // TODO: Implement logic for this custom endpoint
48
44
  res.status(501).json({ message: 'Handler not implemented for <%= endpoint.method %> <%= expressPath %>' });
49
45
  }`;
50
46
  }
47
+
48
+ // --- V3.0 AUTH LOGIC: Decide if the route should be protected ---
49
+ // We protect all routes that modify data (POST, PUT, DELETE) if auth is enabled.
50
+ // We leave GET routes public by default. This is a common pattern.
51
+ const middleware = (addAuth && (endpoint.method === 'POST' || endpoint.method === 'PUT' || endpoint.method === 'DELETE'))
52
+ ? 'protect, '
53
+ : '';
51
54
  %>
52
55
  /**
53
56
  * Route for <%= endpoint.method.toUpperCase() %> <%= endpoint.path %>
54
57
  * Mapped to: <%- handlerFunction.includes('=>') ? 'Inline Handler' : handlerFunction %>
58
+ * Protected: <%= middleware ? 'Yes' : 'No' %>
55
59
  */
56
- router.<%= endpoint.method.toLowerCase() %>('<%- expressPath %>', <%- handlerFunction %>);
60
+ router.<%= endpoint.method.toLowerCase() %>('<%- expressPath %>', <%- middleware %><%- handlerFunction %>);
57
61
 
58
62
  <% }); %>
59
63