backend-scaffold-cli 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.
Files changed (2) hide show
  1. package/bin/cli.js +439 -0
  2. package/package.json +32 -0
package/bin/cli.js ADDED
@@ -0,0 +1,439 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ const { program } = require('commander');
5
+ const chalk = require('chalk');
6
+ const inquirer = require('inquirer');
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const { execSync } = require('child_process');
10
+
11
+ const version= '1.0.0';
12
+
13
+ program
14
+ .version(version)
15
+ .description('Create a new Express.js backend application')
16
+ .argument('<project-name>', 'Name of the project')
17
+ .action(async (projectName) => {
18
+ try{
19
+ console.log(chalk.blue(`Creating a new Express.js backend application: ${projectName}`));
20
+
21
+ const answers = await inquirer.prompt([
22
+ {
23
+ type: 'confirm',
24
+ name: 'useAuth',
25
+ message: 'Include JWT authentication?',
26
+ default: true
27
+ },
28
+ {
29
+ type:'confirm',
30
+ name: 'useLogging',
31
+ message: 'Include logging middleware?',
32
+ default: true
33
+ },
34
+ {
35
+ type: 'confirm',
36
+ name: 'useValidation',
37
+ message: 'Include input validation?',
38
+ default: true
39
+ },
40
+ {
41
+ type: 'confirm',
42
+ name: 'installDeps',
43
+ message: 'Install dependencies now?',
44
+ default: true
45
+ }
46
+ ]);
47
+
48
+ const projectPath = path.resolve(process.cwd(), projectName);
49
+
50
+ if (fs.existsSync(projectPath)) {
51
+ console.log(chalk.red(`Error: Directory ${projectName} already exists.`));
52
+ process.exit(1);
53
+ }
54
+
55
+ console.log(chalk.blue(`Creating project in ${projectPath}\n`));
56
+ fs.ensureDirSync(projectPath);
57
+
58
+ createFolderStructure(projectPath);
59
+ createConfigFiles(projectPath, answers);
60
+ createMiddlewareFiles(projectPath, answers);
61
+ createRouteFiles(projectPath, answers);
62
+
63
+ console.log(chalk.cyan(' Initializing git repository...'));
64
+ execSync('git init', { cwd: projectPath });
65
+
66
+ if (answers.installDeps) {
67
+ console.log(chalk.cyan(' Installing dependencies...\n'));
68
+ execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
69
+ }
70
+
71
+ console.log(chalk.green.bold('\n Project created successfully!\n'));
72
+ console.log(chalk.cyan('Next steps:'));
73
+ console.log(chalk.white(` cd ${projectName}`));
74
+ console.log(chalk.white(' cp .env.example .env'));
75
+ console.log(chalk.white(' npm start\n'));
76
+ }catch (error) {
77
+ console.error(chalk.red('\n Error creating project:'), error.message);
78
+ process.exit(1);
79
+ }
80
+ });
81
+
82
+ program.parse();
83
+
84
+ const createFolderStructure=(projectPath) =>{
85
+ const folders=[
86
+ 'src/config',
87
+ 'src/middleware',
88
+ 'src/routes',
89
+ 'src/controllers',
90
+ 'src/models',
91
+ 'src/utils',
92
+ 'src/validation'
93
+ ];
94
+
95
+ folders.forEach(folder => {
96
+ fs.ensureDirSync(path.join(projectPath, folder));
97
+ });
98
+
99
+ console.log(chalk.green(' Folder structure created'));
100
+
101
+ }
102
+
103
+
104
+ const createConfigFiles= (projectPath,answers) =>{
105
+ const packageJson={
106
+ name: path.basename(projectPath),
107
+ version: '1.0.0',
108
+ main: 'src/server.js',
109
+ scripts: {
110
+ start: 'node src/server.js',
111
+ dev: 'nodemon src/server.js',
112
+ test: 'jest'
113
+ },
114
+ keywords: ['express', 'nodejs', 'backend'],
115
+ author: '',
116
+ license: 'MIT',
117
+ dependencies: {
118
+ express: '^4.18.2',
119
+ mongoose: '^7.0.0',
120
+ dotenv: '^16.0.3',
121
+ cors: '^2.8.5',
122
+ ...(answers.useAuth && { jsonwebtoken: '^9.0.0' }),
123
+ ...(answers.useValidation && { joi: '^17.9.0' })
124
+ },
125
+ devDependencies: {
126
+ nodemon: '^2.0.22',
127
+ }
128
+
129
+ };
130
+
131
+ fs.writeFileSync(
132
+ path.join(projectPath, 'package.json'),
133
+ JSON.stringify(packageJson, null, 2)
134
+ );
135
+
136
+ const env = `# Server Configuration
137
+ PORT=5000
138
+ NODE_ENV=development
139
+
140
+ # MongoDB Configuration
141
+ MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/myappdb
142
+ DB_NAME=myapp
143
+
144
+ # DNS Configuration
145
+ DNS_SERVERS=8.8.8.8,8.8.4.4
146
+ PRIMARY_DNS=8.8.8.8
147
+ SECONDARY_DNS=8.8.4.4
148
+
149
+ # JWT Configuration
150
+ JWT_SECRET=your-secret-key-change-this-in-production
151
+ JWT_EXPIRE=7d
152
+
153
+ # CORS
154
+ CORS_ORIGIN=http://localhost:3000
155
+
156
+ # Logging
157
+ LOG_LEVEL=debug
158
+ `;
159
+
160
+ fs.writeFileSync(path.join(projectPath, '.env.example'), env);
161
+
162
+
163
+ const gitignore = `node_modules/
164
+ .env
165
+ .env.local
166
+ .env.*.local
167
+ dist/
168
+ build/
169
+ .DS_Store
170
+ *.log
171
+ npm-debug.log*
172
+ yarn-debug.log*
173
+ .idea/
174
+ .vscode/
175
+ `;
176
+
177
+ fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore);
178
+
179
+ console.log(chalk.green(' Config files created'));
180
+
181
+
182
+ };
183
+
184
+
185
+
186
+
187
+ function createMiddlewareFiles(projectPath, answers) {
188
+ const errorHandler = `// Middleware for handling errors
189
+ class ErrorHandler extends Error {
190
+ constructor(message, statusCode) {
191
+ super(message);
192
+ this.statusCode = statusCode;
193
+ }
194
+ }
195
+
196
+ const errorMiddleware = (err, req, res, next) => {
197
+ err.statusCode = err.statusCode || 500;
198
+ err.message = err.message || 'Internal Server Error';
199
+
200
+ if (err.code === 11000) {
201
+ const message = \`Duplicate field value entered\`;
202
+ err = new ErrorHandler(message, 400);
203
+ }
204
+
205
+ if (err.name === 'JsonWebTokenError') {
206
+ const message = \`JSON Web Token is invalid, try again\`;
207
+ err = new ErrorHandler(message, 400);
208
+ }
209
+
210
+ if (err.name === 'TokenExpiredError') {
211
+ const message = \`JSON Web Token is expired, try again\`;
212
+ err = new ErrorHandler(message, 400);
213
+ }
214
+
215
+ res.status(err.statusCode).json({
216
+ success: false,
217
+ message: err.message,
218
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
219
+ });
220
+ };
221
+
222
+ module.exports = { errorMiddleware, ErrorHandler };
223
+ `;
224
+
225
+ fs.writeFileSync(
226
+ path.join(projectPath, 'src/middleware/errorHandler.js'),
227
+ errorHandler
228
+ );
229
+
230
+
231
+ const logger = `// Simple logging middleware
232
+ const loggerMiddleware = (req, res, next) => {
233
+ const start = Date.now();
234
+
235
+ res.on('finish', () => {
236
+ const duration = Date.now() - start;
237
+ console.log(
238
+ \`[\${new Date().toISOString()}] \${req.method} \${req.path} - \${res.statusCode} - \${duration}ms\`
239
+ );
240
+ });
241
+
242
+ next();
243
+ };
244
+
245
+ module.exports = loggerMiddleware;
246
+ `;
247
+
248
+ fs.writeFileSync(
249
+ path.join(projectPath, 'src/middleware/logger.js'),
250
+ logger
251
+ );
252
+
253
+ if (answers.useAuth) {
254
+ const auth = `const jwt = require('jsonwebtoken');
255
+ const { ErrorHandler } = require('./errorHandler');
256
+
257
+ const authenticateToken = (req, res, next) => {
258
+ const token = req.headers['authorization']?.split(' ')[1];
259
+
260
+ if (!token) {
261
+ return next(new ErrorHandler('Access token is missing', 401));
262
+ }
263
+
264
+ try {
265
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
266
+ req.user = decoded;
267
+ next();
268
+ } catch (err) {
269
+ next(new ErrorHandler('Invalid or expired token', 401));
270
+ }
271
+ };
272
+
273
+ module.exports = authenticateToken;
274
+ `;
275
+
276
+ fs.writeFileSync(
277
+ path.join(projectPath, 'src/middleware/auth.js'),
278
+ auth
279
+ );
280
+ }
281
+
282
+ if (answers.useValidation) {
283
+ const validation = `const Joi = require('joi');
284
+
285
+ const validateRequest = (schema) => {
286
+ return (req, res, next) => {
287
+ const { error, value } = schema.validate(req.body, {
288
+ abortEarly: false,
289
+ stripUnknown: true
290
+ });
291
+
292
+ if (error) {
293
+ const details = error.details.map(d => ({
294
+ field: d.path.join('.'),
295
+ message: d.message
296
+ }));
297
+ return res.status(400).json({ success: false, errors: details });
298
+ }
299
+
300
+ req.validatedBody = value;
301
+ next();
302
+ };
303
+ };
304
+
305
+ module.exports = validateRequest;
306
+ `;
307
+
308
+ fs.writeFileSync(
309
+ path.join(projectPath, 'src/middleware/validation.js'),
310
+ validation
311
+ );
312
+ }
313
+
314
+ console.log(chalk.green(' Middleware files created'));
315
+ }
316
+
317
+
318
+ const createRouteFiles = (projectPath, answers) => {
319
+ const routes = `const express = require('express');
320
+ const router = express.Router();
321
+ ${answers.useAuth ? "const authenticateToken = require('../middleware/auth');" : ''}
322
+
323
+ // Public routes
324
+ router.get('/health', (req, res) => {
325
+ res.json({ status: 'API is running' });
326
+ });
327
+
328
+ ${answers.useAuth ? `
329
+ // Protected routes
330
+ router.get('/protected', authenticateToken, (req, res) => {
331
+ res.json({ message: 'This is a protected route', user: req.user });
332
+ });
333
+ ` : ''}
334
+
335
+ module.exports = router;
336
+ `;
337
+ fs.writeFileSync(
338
+ path.join(projectPath, 'src/routes/index.js'),
339
+ routes
340
+ );
341
+
342
+
343
+
344
+ const dbConfig = `const mongoose = require('mongoose');
345
+ const dns = require('dns');
346
+
347
+ // Set DNS servers
348
+ const dnsServers = (process.env.DNS_SERVERS || '8.8.8.8,8.8.4.4').split(',');
349
+ dns.setServers(dnsServers);
350
+
351
+ const connectDB = async () => {
352
+ try {
353
+ console.log(\`📡 Using DNS servers: \${dnsServers.join(', ')}\`);
354
+
355
+ const conn = await mongoose.connect(process.env.MONGODB_URI, {
356
+ useNewUrlParser: true,
357
+ useUnifiedTopology: true,
358
+ serverSelectionTimeoutMS: 5000,
359
+ socketTimeoutMS: 45000,
360
+ });
361
+
362
+ console.log(\`MongoDB Connected: \${conn.connection.host}\`);
363
+ return conn;
364
+ } catch (error) {
365
+ console.error(' MongoDB Connection Error:', error.message);
366
+
367
+ if (process.env.NODE_ENV === 'production') {
368
+ process.exit(1);
369
+ } else {
370
+ console.warn('âš  Warning: Running without MongoDB connection');
371
+ }
372
+ }
373
+ };
374
+
375
+ module.exports = connectDB;
376
+ `;
377
+
378
+ fs.writeFileSync(
379
+ path.join(projectPath, 'src/config/db.js'),
380
+ dbConfig
381
+ );
382
+
383
+ const server = `require('dotenv').config();
384
+ const express = require('express');
385
+ const cors = require('cors');
386
+ const connectDB = require('./config/db');
387
+ const routes = require('./routes');
388
+ const loggerMiddleware = require('./middleware/logger');
389
+ const { errorMiddleware } = require('./middleware/errorHandler');
390
+
391
+ const app = express();
392
+ const PORT = process.env.PORT || 5000;
393
+
394
+ // Connect to MongoDB
395
+ connectDB();
396
+
397
+ // Middleware
398
+ app.use(cors({
399
+ origin: process.env.CORS_ORIGIN || '*'
400
+ }));
401
+
402
+ app.use(express.json());
403
+ app.use(express.urlencoded({ extended: true }));
404
+ app.use(loggerMiddleware);
405
+
406
+
407
+ // Routes
408
+ app.use('/api', routes);
409
+
410
+
411
+ // Health check
412
+ app.get('/', (req, res) => {
413
+ res.json({ message: 'Express Backend is running' });
414
+ });
415
+
416
+
417
+ // Error handling middleware (must be last)
418
+ app.use(errorMiddleware);
419
+
420
+
421
+ // Start Server
422
+ app.listen(PORT, () => {
423
+ console.log(\` Server running on port \${PORT}\`);
424
+ console.log(\`Environment: \${process.env.NODE_ENV || 'development'}\`);
425
+ });
426
+
427
+ process.on('unhandledRejection', (err) => {
428
+ console.error('Unhandled Rejection:', err);
429
+ process.exit(1);
430
+ });
431
+ `;
432
+
433
+ fs.writeFileSync(
434
+ path.join(projectPath, 'src/server.js'),
435
+ server
436
+ );
437
+
438
+ console.log(chalk.green('Route and config files created'));
439
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "backend-scaffold-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool to scaffold Express.js backend projects with MongoDB, middleware, and common setup",
5
+ "main": "bin/cli.js",
6
+ "bin": {
7
+ "create-express-backend": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [
13
+ "express",
14
+ "nodejs",
15
+ "backend",
16
+ "scaffold",
17
+ "cli",
18
+ "mongodb"
19
+ ],
20
+ "author": "abhi0605",
21
+ "license": "MIT",
22
+ "preferGlobal": true,
23
+ "engines": {
24
+ "node": ">=14.0.0"
25
+ },
26
+ "dependencies": {
27
+ "chalk": "^4.1.2",
28
+ "commander": "^11.0.0",
29
+ "fs-extra": "^11.1.0",
30
+ "inquirer": "^8.2.5"
31
+ }
32
+ }