create-backlist 2.0.1 → 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/bin/index.js +13 -2
- package/package.json +1 -1
- package/src/generators/node.js +77 -39
- package/src/templates/node-ts-express/partials/Auth.controller.ts.ejs +89 -0
- package/src/templates/node-ts-express/partials/Auth.middleware.ts.ejs +27 -0
- package/src/templates/node-ts-express/partials/Auth.routes.ts.ejs +15 -0
- package/src/templates/node-ts-express/partials/routes.ts.ejs +16 -12
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
package/src/generators/node.js
CHANGED
|
@@ -6,7 +6,7 @@ const { analyzeFrontend } = require('../analyzer');
|
|
|
6
6
|
const { renderAndWrite, getTemplatePath } = require('./template');
|
|
7
7
|
|
|
8
8
|
async function generateNodeProject(options) {
|
|
9
|
-
const { projectDir, projectName, frontendSrcDir } = options;
|
|
9
|
+
const { projectDir, projectName, frontendSrcDir, addAuth } = options;
|
|
10
10
|
|
|
11
11
|
try {
|
|
12
12
|
// --- Step 1: Analyze Frontend to get Endpoints and Schema Info ---
|
|
@@ -21,53 +21,55 @@ async function generateNodeProject(options) {
|
|
|
21
21
|
// --- Step 2: Identify which Database Models to Generate ---
|
|
22
22
|
const modelsToGenerate = new Map();
|
|
23
23
|
endpoints.forEach(ep => {
|
|
24
|
-
// If an endpoint has schemaFields and a valid controllerName, add it to our map.
|
|
25
24
|
if (ep.schemaFields && ep.controllerName !== 'Default' && !modelsToGenerate.has(ep.controllerName)) {
|
|
26
25
|
modelsToGenerate.set(ep.controllerName, ep.schemaFields);
|
|
27
26
|
}
|
|
28
27
|
});
|
|
29
28
|
|
|
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
|
+
}
|
|
34
|
+
|
|
30
35
|
// --- Step 3: Scaffold Base Project Structure & Files ---
|
|
31
36
|
console.log(chalk.blue(' -> Scaffolding Node.js (Express + TS) project...'));
|
|
32
|
-
|
|
33
|
-
// Create the main source directory
|
|
34
37
|
const destSrcDir = path.join(projectDir, 'src');
|
|
35
38
|
await fs.ensureDir(destSrcDir);
|
|
36
|
-
|
|
37
|
-
// Copy static base files
|
|
38
39
|
await fs.copy(getTemplatePath('node-ts-express/base/server.ts'), path.join(destSrcDir, 'server.ts'));
|
|
39
40
|
await fs.copy(getTemplatePath('node-ts-express/base/tsconfig.json'), path.join(projectDir, 'tsconfig.json'));
|
|
40
41
|
|
|
41
|
-
// --- Step 4:
|
|
42
|
-
|
|
43
|
-
// Prepare package.json content (in memory)
|
|
42
|
+
// --- Step 4: Prepare and Write package.json ---
|
|
44
43
|
const packageJsonContent = JSON.parse(
|
|
45
44
|
await ejs.renderFile(getTemplatePath('node-ts-express/partials/package.json.ejs'), { projectName })
|
|
46
45
|
);
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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';
|
|
52
55
|
}
|
|
53
|
-
|
|
54
|
-
// Write the final package.json to the disk
|
|
55
56
|
await fs.writeJson(path.join(projectDir, 'package.json'), packageJsonContent, { spaces: 2 });
|
|
56
57
|
|
|
57
|
-
//
|
|
58
|
+
// --- Step 5: Generate Models and Controllers ---
|
|
58
59
|
if (modelsToGenerate.size > 0) {
|
|
59
60
|
console.log(chalk.blue(' -> Generating database models and controllers...'));
|
|
60
61
|
await fs.ensureDir(path.join(destSrcDir, 'models'));
|
|
61
62
|
await fs.ensureDir(path.join(destSrcDir, 'controllers'));
|
|
62
63
|
|
|
63
|
-
for (
|
|
64
|
-
|
|
64
|
+
for (let [modelName, schema] of modelsToGenerate.entries()) {
|
|
65
|
+
if (addAuth && modelName === 'User') {
|
|
66
|
+
schema = { name: 'String', email: 'String', password: 'String', ...schema };
|
|
67
|
+
}
|
|
65
68
|
await renderAndWrite(
|
|
66
69
|
getTemplatePath('node-ts-express/partials/Model.ts.ejs'),
|
|
67
70
|
path.join(destSrcDir, 'models', `${modelName}.model.ts`),
|
|
68
71
|
{ modelName, schema }
|
|
69
72
|
);
|
|
70
|
-
// Generate Controller File (e.g., controllers/User.controller.ts)
|
|
71
73
|
await renderAndWrite(
|
|
72
74
|
getTemplatePath('node-ts-express/partials/Controller.ts.ejs'),
|
|
73
75
|
path.join(destSrcDir, 'controllers', `${modelName}.controller.ts`),
|
|
@@ -75,25 +77,53 @@ async function generateNodeProject(options) {
|
|
|
75
77
|
);
|
|
76
78
|
}
|
|
77
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'));
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
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 });
|
|
86
117
|
|
|
87
|
-
// --- Step
|
|
88
|
-
|
|
89
|
-
let serverFileContent = await fs.readFile(serverDestPath, 'utf-8');
|
|
118
|
+
// --- Step 8: Inject Logic into Main Server File ---
|
|
119
|
+
let serverFileContent = await fs.readFile(path.join(destSrcDir, 'server.ts'), 'utf-8');
|
|
90
120
|
|
|
91
121
|
let dbConnectionCode = '';
|
|
92
|
-
if (modelsToGenerate.size > 0) {
|
|
122
|
+
if (modelsToGenerate.size > 0 || addAuth) {
|
|
93
123
|
dbConnectionCode = `
|
|
94
124
|
// --- Database Connection ---
|
|
95
125
|
import mongoose from 'mongoose';
|
|
96
|
-
const MONGO_URI = process.env.MONGO_URI || 'mongodb://
|
|
126
|
+
const MONGO_URI = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/${projectName}';
|
|
97
127
|
mongoose.connect(MONGO_URI)
|
|
98
128
|
.then(() => console.log('MongoDB Connected...'))
|
|
99
129
|
.catch(err => console.error('MongoDB Connection Error:', err));
|
|
@@ -101,27 +131,35 @@ mongoose.connect(MONGO_URI)
|
|
|
101
131
|
`;
|
|
102
132
|
}
|
|
103
133
|
|
|
104
|
-
|
|
134
|
+
let authRoutesInjector = '';
|
|
135
|
+
if (addAuth) {
|
|
136
|
+
authRoutesInjector = `import authRoutes from './routes/Auth.routes';\napp.use('/api/auth', authRoutes);\n\n`;
|
|
137
|
+
}
|
|
138
|
+
|
|
105
139
|
serverFileContent = serverFileContent
|
|
106
140
|
.replace("dotenv.config();", `dotenv.config();\n${dbConnectionCode}`)
|
|
107
|
-
.replace('// INJECT:ROUTES',
|
|
141
|
+
.replace('// INJECT:ROUTES', `${authRoutesInjector}import apiRoutes from './routes';\napp.use('/api', apiRoutes);`); // Changed to /api
|
|
108
142
|
|
|
109
|
-
await fs.writeFile(
|
|
143
|
+
await fs.writeFile(path.join(destSrcDir, 'server.ts'), serverFileContent);
|
|
110
144
|
|
|
111
|
-
// --- Step
|
|
112
|
-
console.log(chalk.magenta(' -> Installing dependencies
|
|
145
|
+
// --- Step 9: Install All Dependencies ---
|
|
146
|
+
console.log(chalk.magenta(' -> Installing all dependencies... This might take a moment.'));
|
|
113
147
|
await execa('npm', ['install'], { cwd: projectDir });
|
|
114
148
|
|
|
115
|
-
// --- Step
|
|
149
|
+
// --- Step 10: Generate Final Files (README, .env.example) ---
|
|
116
150
|
await renderAndWrite(
|
|
117
151
|
getTemplatePath('node-ts-express/partials/README.md.ejs'),
|
|
118
152
|
path.join(projectDir, 'README.md'),
|
|
119
153
|
{ projectName }
|
|
120
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
|
+
|
|
121
161
|
|
|
122
162
|
} catch (error) {
|
|
123
|
-
// Re-throw the error so it can be caught by the main CLI handler in index.js
|
|
124
|
-
// This allows for centralized error message display and cleanup.
|
|
125
163
|
throw error;
|
|
126
164
|
}
|
|
127
165
|
}
|
|
@@ -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,
|
|
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
|
|