backend-scaffold-cli 1.3.0 → 1.5.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 +173 -4
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -37,11 +37,23 @@ program
37
37
  message: 'Include rate limiting?',
38
38
  default: true
39
39
  },
40
+ {
41
+ type: 'confirm',
42
+ name: 'useFileUpload',
43
+ message: 'Include file upload support (multer)?',
44
+ default: true
45
+ },
40
46
  {
41
47
  type: 'confirm',
42
48
  name: 'installDeps',
43
49
  message: 'Install dependencies now?',
44
50
  default: true
51
+ },
52
+ {
53
+ type: 'confirm',
54
+ name: 'useAxios',
55
+ message: 'Include axios (for external API calls)?',
56
+ default: true
45
57
  }
46
58
  ]);
47
59
 
@@ -61,13 +73,16 @@ program
61
73
  console.log(chalk.blue(`Creating project in ${projectPath}\n`));
62
74
  fs.ensureDirSync(projectPath);
63
75
 
64
- createFolderStructure(projectPath);
76
+ createFolderStructure(projectPath, answers);
65
77
  createConfigFiles(projectPath, answers);
66
78
  createMiddlewareFiles(projectPath, answers);
67
79
  createRouteFiles(projectPath, answers);
68
80
  if (answers.useAuth) {
69
81
  createUserModel(projectPath);
70
82
  }
83
+ if(answers.useAxios){
84
+ createAxiosUtil(projectPath);
85
+ }
71
86
 
72
87
  console.log(chalk.cyan(' Initializing git repository...'));
73
88
  execSync('git init', { cwd: projectPath });
@@ -94,7 +109,7 @@ program.parse();
94
109
 
95
110
 
96
111
 
97
- const createFolderStructure = (projectPath) => {
112
+ const createFolderStructure = (projectPath, answers) => {
98
113
  const folders = [
99
114
  'src/config',
100
115
  'src/middleware',
@@ -105,12 +120,15 @@ const createFolderStructure = (projectPath) => {
105
120
  'src/validation'
106
121
  ];
107
122
 
123
+ if (answers.useFileUpload) {
124
+ folders.push('uploads');
125
+ }
126
+
108
127
  folders.forEach(folder => {
109
128
  fs.ensureDirSync(path.join(projectPath, folder));
110
129
  });
111
130
 
112
131
  console.log(chalk.green(' Folder structure created'));
113
-
114
132
  }
115
133
 
116
134
 
@@ -139,6 +157,8 @@ const createConfigFiles = (projectPath, answers) => {
139
157
  ...(answers.useAuth && { jsonwebtoken: '^9.0.0' , bcryptjs: '^2.4.3'}),
140
158
  ...(answers.useValidation && { joi: '^17.9.0' }),
141
159
  ...(answers.useRateLimit && { 'express-rate-limit': '^6.7.0' }),
160
+ ...(answers.useFileUpload && { multer: '^2.0.0' }),
161
+ ...(answers.useAxios && { axios: '^1.6.0' }),
142
162
 
143
163
  },
144
164
  devDependencies: {
@@ -185,7 +205,6 @@ LOG_LEVEL=debug
185
205
 
186
206
 
187
207
 
188
-
189
208
  const gitignore = `node_modules/
190
209
  .env
191
210
  .env.local
@@ -198,10 +217,14 @@ npm-debug.log*
198
217
  yarn-debug.log*
199
218
  .idea/
200
219
  .vscode/
220
+ ${answers.useFileUpload ? 'uploads/*\n!uploads/.gitkeep' : ''}
201
221
  `;
202
222
 
203
223
  fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore);
204
224
 
225
+ if(answers.useFileUpload){
226
+ fs.writeFileSync(path.join(projectPath, 'uploads/.gitkeep'), '');
227
+ }
205
228
  console.log(chalk.green(' Config files created'));
206
229
 
207
230
 
@@ -312,6 +335,57 @@ module.exports=limiter;
312
335
 
313
336
 
314
337
 
338
+ if(answers.useFileUpload){
339
+ const multerMiddleware= ` const multer = require('multer');
340
+ const path = require('path');
341
+
342
+ // Set storage engine
343
+ const storage = multer.diskStorage({
344
+ destination: function (req,file ,cb){
345
+ cb(null, 'uploads/');
346
+ },
347
+ filename: function (req, file, cb) {
348
+ const uniqueSuffix = Date.now() + '-' + Math.round(Math.random()*1E9);
349
+ cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname))
350
+ }
351
+
352
+ });
353
+
354
+
355
+ //file filter
356
+ const fileFilter = (req, file, cb) =>{
357
+ const allowedTypes = /jpeg|jpg|png|gif/;
358
+ const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
359
+ const mimetype = allowedTypes.test(file.mimetype);
360
+
361
+ if(extname && mimetype){
362
+ return cb(null,true);
363
+ }else{
364
+ cb(new Error('Error: Images Only!'));
365
+ }
366
+ };
367
+
368
+ const upload = multer({
369
+ storage: storage,
370
+ limits: { fileSize: 5 * 1024 * 1024 }, // 5MB limit
371
+ fileFilter: fileFilter
372
+
373
+ });
374
+
375
+ module.exports = upload;
376
+
377
+
378
+ `;
379
+
380
+
381
+ fs.writeFileSync(
382
+ path.join(projectPath, 'src/middleware/upload.js'),
383
+ multerMiddleware
384
+ )
385
+ }
386
+
387
+
388
+
315
389
 
316
390
 
317
391
 
@@ -390,6 +464,7 @@ const createRouteFiles = (projectPath, answers) => {
390
464
  const routes = `const express = require('express');
391
465
  const router = express.Router();
392
466
  ${answers.useAuth ? "const authenticateToken = require('../middleware/auth');" : ''}
467
+ ${answers.useFileUpload ? "const upload = require('../middleware/upload');" : ''}
393
468
 
394
469
  // Public routes
395
470
  router.get('/health', (req, res) => {
@@ -403,6 +478,28 @@ router.get('/protected', authenticateToken, (req, res) => {
403
478
  });
404
479
  ` : ''}
405
480
 
481
+ ${answers.useFileUpload ? `
482
+ // File upload route
483
+ router.post('/upload', upload.single('file'), (req,res) =>{
484
+ if(!req.file){
485
+ return res.status(400).json({
486
+ success: false,
487
+ message: 'No file uploaded'
488
+ })
489
+ }
490
+ res.json({
491
+ success: true,
492
+ message: 'File uploaded successfully',
493
+ file: req.file
494
+ });
495
+
496
+ });
497
+
498
+
499
+ `: ''}
500
+
501
+
502
+
406
503
  module.exports = router;
407
504
  `;
408
505
  fs.writeFileSync(
@@ -577,4 +674,76 @@ function createUserModel(projectPath) {
577
674
  )
578
675
 
579
676
  console.log(chalk.green('User model created'));
677
+ }
678
+
679
+
680
+
681
+
682
+ function createAxiosUtil(projectPath){
683
+ const axiosUtil = ` const axios = require('axios');
684
+
685
+ //create an axios instance with default config
686
+ const axiosInstance = axios.create({
687
+ baseURL: process.env.API_BASE_URL || '',
688
+ timeout: 10000,
689
+ headers:{
690
+ 'Content-Type' : 'application/json',
691
+ }
692
+ });
693
+
694
+ //request interceptor
695
+ axiosInstance.interceptors.request.use(
696
+ (config) =>{
697
+ console.log(\`Making request to: \${config.url}\`);;
698
+ return config;
699
+ },
700
+ (error) => Promise.reject(error)
701
+ );
702
+
703
+ //response interceptor
704
+ axiosInstance.interceptors.response.use(
705
+ (response) => response,
706
+ (error) => {
707
+ console.error('API call error: ', error.response ? error.response.data : error.message);
708
+ return Promise.reject(error);
709
+ }
710
+ );
711
+
712
+ //fetch data function
713
+ const fetchData = async (url) => {
714
+ try{
715
+ const response = await axiosInstance.get(url);
716
+ return response.data;
717
+ }catch(error){
718
+ throw new Error(\`Failed to fetch data: \${error.message}\`);
719
+ }
720
+ };
721
+
722
+ //post data function
723
+ const postData = async (url, data) => {
724
+ try{
725
+ const response = await axiosInstance.post(url, data);
726
+ return response.data;
727
+ }catch(error){
728
+ throw new Error(\`Failed to post data: \${error.message}\`);
729
+ }
730
+ };
731
+
732
+ module.exports = {
733
+ axiosInstance,
734
+ fetchData,
735
+ postData,
736
+ };
737
+
738
+
739
+
740
+ `;
741
+
742
+
743
+ fs.writeFileSync(
744
+ path.join(projectPath, 'src/utils/axiosUtil.js'),
745
+ axiosUtil
746
+ );
747
+
748
+ console.log(chalk.green('Axios utility created'));
580
749
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-scaffold-cli",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "CLI tool to scaffold Express.js backend projects with MongoDB, middleware, and common setup",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {