create-fullstack-boilerplate 2.1.10 → 2.2.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # create-fullstack-app
1
+ # create-fullstack-boilerplate
2
2
 
3
3
  A powerful CLI tool to quickly scaffold a complete fullstack application with React, Node.js, Express, and Sequelize with multi-database support. Get started building real features instead of spending time on project setup!
4
4
 
@@ -25,14 +25,14 @@ A powerful CLI tool to quickly scaffold a complete fullstack application with Re
25
25
  ### Create a New Project
26
26
 
27
27
  ```bash
28
- npx create-fullstack-app
28
+ npx create-fullstack-boilerplate
29
29
  ```
30
30
 
31
31
  Or install globally:
32
32
 
33
33
  ```bash
34
- npm install -g create-fullstack-app
35
- create-fullstack-app
34
+ npm install -g create-fullstack-boilerplate
35
+ create-fullstack-boilerplate
36
36
  ```
37
37
 
38
38
  Follow the interactive prompts:
@@ -73,7 +73,7 @@ npm run dev
73
73
  Navigate to your project root and run:
74
74
 
75
75
  ```bash
76
- npx create-fullstack-app add-db
76
+ npx create-fullstack-boilerplate add-db
77
77
  ```
78
78
 
79
79
  The CLI will prompt you for:
@@ -125,7 +125,7 @@ The CLI provides appropriate data types based on your selected database dialect:
125
125
  Navigate to your project root and run:
126
126
 
127
127
  ```bash
128
- npx create-fullstack-app add-route
128
+ npx create-fullstack-boilerplate add-route
129
129
  ```
130
130
 
131
131
  The CLI will prompt you for:
package/index.js CHANGED
@@ -133,144 +133,4 @@
133
133
  }
134
134
  process.exit(1);
135
135
  }
136
- })();
137
-
138
-
139
-
140
- // #!/usr/bin/env node
141
-
142
- // (async () => {
143
- // const argv = process.argv.slice(2);
144
-
145
- // if (argv[0] === "add-db") {
146
- // await require("./lib/addDB")();
147
- // return;
148
- // }
149
-
150
- // if (argv[0] === "add-route") {
151
- // await require("./lib/addRoute")();
152
- // return;
153
- // }
154
-
155
- // // ---- Your existing create-project code ----
156
- // const path = require("path");
157
- // // const { ensure } = require("./lib/utils");
158
- // const copyProject = require('./lib/copyProject')
159
- // const { runInstall, installDBDriver } = require("./lib/utils");
160
- // const setupMainDB = require("./lib/setupMainDB");
161
- // const setupExtraDB = require("./lib/setupExtraDB");
162
- // const testDBConnection = require("./lib/testDBConnection");
163
- // const { mainPrompts, extraDBPrompts } = require("./lib/prompts");
164
-
165
- // const fs = require("fs-extra");
166
-
167
-
168
- // // Resolve template folder dynamically
169
- // let templateDir;
170
-
171
- // // Try __dirname first (works for local/dev)
172
- // const localTemplate = path.resolve(__dirname, "template");
173
- // console.log("🔍 Checking local template:", localTemplate);
174
-
175
- // if (fs.existsSync(localTemplate)) {
176
- // templateDir = localTemplate;
177
- // console.log("✅ Found local template");
178
- // } else {
179
- // // Fallback for npx (temp folder)
180
- // try {
181
- // const pkg = require.resolve("create-fullstack-boilerplate/package.json");
182
- // templateDir = path.resolve(path.dirname(pkg), "template");
183
- // console.log("✅ Found npm template:", templateDir);
184
- // } catch (err) {
185
- // console.error("❌ Could not resolve package:", err.message);
186
- // }
187
- // }
188
-
189
- // if (!templateDir || !fs.existsSync(templateDir)) {
190
- // throw new Error(
191
- // `Template folder not found!\nSearched: ${localTemplate}\nMake sure 'template' is included in package.json 'files' field.`
192
- // );
193
- // }
194
-
195
- // console.log("✅ Using template folder:", templateDir);
196
-
197
- // console.log("=== DEBUG INFO ===");
198
- // console.log("Current directory:", process.cwd());
199
- // console.log("Template directory:", templateDir);
200
- // console.log("Template exists:", fs.existsSync(templateDir));
201
- // if (fs.existsSync(templateDir)) {
202
- // console.log("Template contents:", fs.readdirSync(templateDir));
203
- // }
204
- // console.log("==================");
205
-
206
-
207
- // try {
208
- // console.log("\n🎛️ Setting Up Full Stack Project...\n");
209
-
210
- // const answers = await mainPrompts();
211
- // const targetDir = path.join(process.cwd(), answers.projectName);
212
-
213
- // console.log("Target directory:", targetDir);
214
-
215
- // // Remove the IIFE wrapper and just await directly
216
- // try {
217
- // console.log("📁 Copying project files...");
218
- // await copyProject(templateDir, targetDir);
219
- // console.log("✅ Project copied successfully");
220
- // } catch (err) {
221
- // console.error("❌ Failed to copy project files:", err.message);
222
- // throw err; // Re-throw to stop execution
223
- // }
224
-
225
- // await setupMainDB(targetDir, answers.dbDialect);
226
- // console.log("➡️ Installing backend dependencies...");
227
- // await runInstall(path.join(targetDir, "Backend"));
228
-
229
- // console.log("➡️ Installing frontend dependencies...");
230
- // await runInstall(path.join(targetDir, "Frontend"));
231
-
232
- // console.log("➡️ Installing Your Db Dialect: ", answers.dbDialect)
233
- // await installDBDriver(path.join(targetDir, "Backend"), answers.dbDialect);
234
-
235
-
236
- // if (answers.addExtraDB) {
237
- // const extraDB = await extraDBPrompts();
238
- // console.log(`\n🔍 Testing connection for ${extraDB.dbKey}...`);
239
- // await installDBDriver(path.join(targetDir, "Backend"), extraDB.dialect);
240
- // const ok = await testDBConnection(targetDir, extraDB);
241
-
242
- // if (ok) {
243
- // await setupExtraDB(targetDir, extraDB);
244
- // console.log(`✅ Extra DB '${extraDB.dbKey}' successfully integrated.\n`);
245
- // } else {
246
- // console.log(`⚠️ Connection failed. Skipping extra DB setup.\n`);
247
- // }
248
- // }
249
-
250
- // if (answers.initGit) {
251
- // try {
252
- // const execa = require("execa").execa || require("execa");
253
- // await execa("git", ["init"], { cwd: targetDir });
254
- // if (answers.remoteRepo) {
255
- // await execa("git", ["remote", "add", "origin", answers.remoteRepo], { cwd: targetDir });
256
- // }
257
- // console.log("✅ Git initialized.\n");
258
- // } catch (gitErr) {
259
- // console.log(`⚠️ Git initialization failed: ${gitErr.message}`);
260
- // console.log(` You can initialize git manually later.\n`);
261
- // }
262
- // }
263
-
264
- // console.log(`\n🎉 Project Ready!`);
265
- // console.log(`\n➡️ Next Steps:`);
266
- // console.log(` cd ${answers.projectName}`);
267
- // console.log(` cd backend && npm run dev`);
268
- // console.log(` cd ../frontend && npm run dev\n`);
269
- // } catch (err) {
270
- // console.error(`\n❌ Error creating project: ${err.message}\n`);
271
- // if (err.stack && process.env.DEBUG) {
272
- // console.error(err.stack);
273
- // }
274
- // process.exit(1);
275
- // }
276
- // })();
136
+ })();
package/lib/addDB.js CHANGED
@@ -2,8 +2,6 @@ const path = require("path");
2
2
  const { extraDBPrompts } = require("./prompts");
3
3
  const testDBConnection = require("./testDBConnection");
4
4
  const setupExtraDB = require("./setupExtraDB");
5
- // const { ensure } = require("./utils");
6
- // const fs = ensure("fs-extra");
7
5
  const fs = require("fs-extra");
8
6
 
9
7
 
package/lib/addRoute.js CHANGED
@@ -1,7 +1,5 @@
1
1
  const path = require("path");
2
- // const { ensure } = require("./utils");
3
2
  const { routePrompts } = require("./prompts");
4
- // const fs = ensure("fs-extra");
5
3
  const fs = require("fs-extra");
6
4
 
7
5
 
@@ -28,7 +26,7 @@ module.exports = async function addRoute() {
28
26
  try {
29
27
  // Get route info from user
30
28
  const routeInfo = await routePrompts();
31
-
29
+
32
30
  const routeFileName = `${routeInfo.routeName}Routes.js`;
33
31
  const serviceFileName = `${routeInfo.routeName}Service.js`;
34
32
  const routeFilePath = path.join(routesDir, routeFileName);
@@ -71,10 +69,10 @@ module.exports = async function addRoute() {
71
69
  };
72
70
 
73
71
  function generateRouteFile(routeInfo) {
74
- const requireAuth = routeInfo.needsAuth
75
- ? `const { authenticateToken } = require('../middleware/authMiddleware');\n`
72
+ const requireAuth = routeInfo.needsAuth
73
+ ? `const { authenticateToken } = require('../middleware/authMiddleware');\n`
76
74
  : '';
77
-
75
+
78
76
  const authMiddleware = routeInfo.needsAuth ? 'authenticateToken, ' : '';
79
77
 
80
78
  return `const express = require('express');
@@ -1,6 +1,5 @@
1
1
  const path = require("path");
2
2
  const fs = require("fs-extra");
3
- const { normalizePath } = require("./utils");
4
3
 
5
4
  module.exports = async function copyProject(src, dest) {
6
5
  try {
package/lib/prompts.js CHANGED
@@ -46,8 +46,8 @@ module.exports.mainPrompts = () => {
46
46
 
47
47
  module.exports.extraDBPrompts = async () => {
48
48
  const basicInfo = await inquirer.prompt([
49
- {
50
- name: 'dbKey',
49
+ {
50
+ name: 'dbKey',
51
51
  message: 'DB Identifier (e.g., REPORTING_DB):',
52
52
  validate: (input) => {
53
53
  if (!input || input.trim().length === 0) {
@@ -63,9 +63,9 @@ module.exports.extraDBPrompts = async () => {
63
63
  { name: 'username', message: 'DB Username:', validate: (input) => input.trim().length > 0 ? true : 'Cannot be empty' },
64
64
  { name: 'password', message: 'DB Password:' },
65
65
  { name: 'host', message: 'DB Host:', default: 'localhost' },
66
- {
67
- name: 'port',
68
- message: 'DB Port:',
66
+ {
67
+ name: 'port',
68
+ message: 'DB Port:',
69
69
  default: '3306',
70
70
  validate: (input) => {
71
71
  const port = parseInt(input);
@@ -81,9 +81,9 @@ module.exports.extraDBPrompts = async () => {
81
81
  message: 'DB Dialect:',
82
82
  choices: ['mysql', 'mariadb', 'postgres']
83
83
  },
84
- {
85
- name: 'tableName',
86
- message: 'Model / Table Name:',
84
+ {
85
+ name: 'tableName',
86
+ message: 'Model / Table Name:',
87
87
  default: 'sample_table',
88
88
  validate: (input) => {
89
89
  if (!input || input.trim().length === 0) {
@@ -113,9 +113,9 @@ module.exports.extraDBPrompts = async () => {
113
113
 
114
114
  async function collectTableAttributes(dialect) {
115
115
  const attributes = [];
116
-
116
+
117
117
  console.log('\n📋 Define table attributes. Start with the primary key.\n');
118
-
118
+
119
119
  // Primary key first
120
120
  const pkAnswers = await inquirer.prompt([
121
121
  {
@@ -1,24 +1,22 @@
1
1
  const path = require("path");
2
- // const { ensure } = require("./utils");
3
- // const fs = ensure("fs-extra");
4
- const fs = require("fs-extra"); // no assert needed
2
+ const fs = require("fs-extra");
5
3
 
6
4
 
7
5
  module.exports = async function setupExtraDB(targetDir, dbConfig) {
8
- const backendDir = path.join(targetDir, "Backend");
9
- const modelsDir = path.join(backendDir, "Models");
10
- const dbDir = path.join(backendDir, "DB");
11
-
12
- // 1. Create folder for this DB's models
13
- const dbFolderName = dbConfig.dbKey;
14
- const dbModelsFolder = path.join(modelsDir, dbFolderName);
15
- await fs.ensureDir(dbModelsFolder);
16
-
17
- // 2. Create config file for this DB
18
- const configFileName = `${dbFolderName}.config.js`;
19
- const configPath = path.join(dbDir, configFileName);
20
-
21
- const configContent = `module.exports = {
6
+ const backendDir = path.join(targetDir, "Backend");
7
+ const modelsDir = path.join(backendDir, "Models");
8
+ const dbDir = path.join(backendDir, "DB");
9
+
10
+ // 1. Create folder for this DB's models
11
+ const dbFolderName = dbConfig.dbKey;
12
+ const dbModelsFolder = path.join(modelsDir, dbFolderName);
13
+ await fs.ensureDir(dbModelsFolder);
14
+
15
+ // 2. Create config file for this DB
16
+ const configFileName = `${dbFolderName}.config.js`;
17
+ const configPath = path.join(dbDir, configFileName);
18
+
19
+ const configContent = `module.exports = {
22
20
  development: {
23
21
  username: process.env.${dbConfig.dbKey}_USER || "${dbConfig.username}",
24
22
  password: process.env.${dbConfig.dbKey}_PASSWORD || "${dbConfig.password}",
@@ -46,91 +44,91 @@ module.exports = async function setupExtraDB(targetDir, dbConfig) {
46
44
  };
47
45
  `;
48
46
 
49
- await fs.writeFile(configPath, configContent);
47
+ await fs.writeFile(configPath, configContent);
48
+
49
+ // 3. Create a sample model file
50
+ const modelContent = generateModelContent(dbConfig);
51
+ const modelFileName = `${dbConfig.tableName}.js`;
52
+ const modelPath = path.join(dbModelsFolder, modelFileName);
53
+ await fs.writeFile(modelPath, modelContent);
50
54
 
51
- // 3. Create a sample model file
52
- const modelContent = generateModelContent(dbConfig);
53
- const modelFileName = `${dbConfig.tableName}.js`;
54
- const modelPath = path.join(dbModelsFolder, modelFileName);
55
- await fs.writeFile(modelPath, modelContent);
55
+ // 4. Update dbConfigs.js to register this DB
56
+ const dbConfigsPath = path.join(dbDir, "dbConfigs.js");
57
+ let dbConfigsContent = await fs.readFile(dbConfigsPath, "utf8");
56
58
 
57
- // 4. Update dbConfigs.js to register this DB
58
- const dbConfigsPath = path.join(dbDir, "dbConfigs.js");
59
- let dbConfigsContent = await fs.readFile(dbConfigsPath, "utf8");
60
-
61
- const newEntry = ` {
59
+ const newEntry = ` {
62
60
  key: "${dbConfig.dbKey}",
63
61
  folder: "${dbConfig.dbKey}",
64
62
  configPath: "/../DB/${configFileName}"
65
63
  }`;
66
64
 
67
- // Insert before the closing bracket
68
- dbConfigsContent = dbConfigsContent.replace(
69
- /const dbConfigs = \[\s*\];/,
70
- `const dbConfigs = [
65
+ // Insert before the closing bracket
66
+ dbConfigsContent = dbConfigsContent.replace(
67
+ /const dbConfigs = \[\s*\];/,
68
+ `const dbConfigs = [
71
69
  ${newEntry}
72
70
  ];`
73
- );
71
+ );
74
72
 
75
- // If there are already entries, append
76
- if (!dbConfigsContent.includes(newEntry) && dbConfigsContent.includes("const dbConfigs = [")) {
77
- dbConfigsContent = dbConfigsContent.replace(
78
- /(const dbConfigs = \[[\s\S]*?)(\];)/,
79
- `$1,
73
+ // If there are already entries, append
74
+ if (!dbConfigsContent.includes(newEntry) && dbConfigsContent.includes("const dbConfigs = [")) {
75
+ dbConfigsContent = dbConfigsContent.replace(
76
+ /(const dbConfigs = \[[\s\S]*?)(\];)/,
77
+ `$1,
80
78
  ${newEntry}
81
79
  $2`
82
- );
83
- }
80
+ );
81
+ }
84
82
 
85
- await fs.writeFile(dbConfigsPath, dbConfigsContent);
86
-
87
- // 5. Update .env file with DB credentials
88
- const envPath = path.join(backendDir, ".env");
89
- let envContent = await fs.readFile(envPath, "utf8");
90
-
91
- const envVars = `\n# ${dbConfig.dbKey} Database Configuration\n${dbConfig.dbKey}_USER=${dbConfig.username}\n${dbConfig.dbKey}_PASSWORD=${dbConfig.password}\n${dbConfig.dbKey}_NAME=${dbConfig.database}\n${dbConfig.dbKey}_HOST=${dbConfig.host}\n${dbConfig.dbKey}_PORT=${dbConfig.port}\n`;
92
-
93
- if (!envContent.includes(`${dbConfig.dbKey}_USER`)) {
94
- envContent += envVars;
95
- await fs.writeFile(envPath, envContent);
96
- }
83
+ await fs.writeFile(dbConfigsPath, dbConfigsContent);
84
+
85
+ // 5. Update .env file with DB credentials
86
+ const envPath = path.join(backendDir, ".env");
87
+ let envContent = await fs.readFile(envPath, "utf8");
88
+
89
+ const envVars = `\n# ${dbConfig.dbKey} Database Configuration\n${dbConfig.dbKey}_USER=${dbConfig.username}\n${dbConfig.dbKey}_PASSWORD=${dbConfig.password}\n${dbConfig.dbKey}_NAME=${dbConfig.database}\n${dbConfig.dbKey}_HOST=${dbConfig.host}\n${dbConfig.dbKey}_PORT=${dbConfig.port}\n`;
97
90
 
98
- console.log(`✅ Database '${dbConfig.dbKey}' configured successfully.`);
91
+ if (!envContent.includes(`${dbConfig.dbKey}_USER`)) {
92
+ envContent += envVars;
93
+ await fs.writeFile(envPath, envContent);
94
+ }
95
+
96
+ console.log(`✅ Database '${dbConfig.dbKey}' configured successfully.`);
99
97
  };
100
98
 
101
99
  function generateModelContent(dbConfig) {
102
- const modelName = dbConfig.tableName.charAt(0).toUpperCase() + dbConfig.tableName.slice(1);
103
-
104
- // Generate model content based on whether attributes were provided
105
- if (dbConfig.attributes && dbConfig.attributes.length > 0) {
106
- const attributesStr = dbConfig.attributes.map(attr => {
107
- let attrDef = ` ${attr.name}: {\n type: DataTypes.${attr.type}`;
108
-
109
- if (attr.length) {
110
- attrDef += `(${attr.length})`;
111
- }
112
-
113
- if (attr.primaryKey) {
114
- attrDef += `,\n primaryKey: true,\n autoIncrement: true`;
115
- }
116
-
117
- if (attr.allowNull === false) {
118
- attrDef += `,\n allowNull: false`;
119
- }
120
-
121
- if (attr.unique) {
122
- attrDef += `,\n unique: true`;
123
- }
124
-
125
- if (attr.defaultValue !== undefined) {
126
- attrDef += `,\n defaultValue: ${JSON.stringify(attr.defaultValue)}`;
127
- }
128
-
129
- attrDef += `\n }`;
130
- return attrDef;
131
- }).join(',\n');
132
-
133
- return `'use strict';
100
+ const modelName = dbConfig.tableName.charAt(0).toUpperCase() + dbConfig.tableName.slice(1);
101
+
102
+ // Generate model content based on whether attributes were provided
103
+ if (dbConfig.attributes && dbConfig.attributes.length > 0) {
104
+ const attributesStr = dbConfig.attributes.map(attr => {
105
+ let attrDef = ` ${attr.name}: {\n type: DataTypes.${attr.type}`;
106
+
107
+ if (attr.length) {
108
+ attrDef += `(${attr.length})`;
109
+ }
110
+
111
+ if (attr.primaryKey) {
112
+ attrDef += `,\n primaryKey: true,\n autoIncrement: true`;
113
+ }
114
+
115
+ if (attr.allowNull === false) {
116
+ attrDef += `,\n allowNull: false`;
117
+ }
118
+
119
+ if (attr.unique) {
120
+ attrDef += `,\n unique: true`;
121
+ }
122
+
123
+ if (attr.defaultValue !== undefined) {
124
+ attrDef += `,\n defaultValue: ${JSON.stringify(attr.defaultValue)}`;
125
+ }
126
+
127
+ attrDef += `\n }`;
128
+ return attrDef;
129
+ }).join(',\n');
130
+
131
+ return `'use strict';
134
132
  module.exports = (sequelize, DataTypes) => {
135
133
  const ${modelName} = sequelize.define('${modelName}', {
136
134
  ${attributesStr}
@@ -147,9 +145,9 @@ ${attributesStr}
147
145
  return ${modelName};
148
146
  };
149
147
  `;
150
- } else {
151
- // Simple model with just ID
152
- return `'use strict';
148
+ } else {
149
+ // Simple model with just ID
150
+ return `'use strict';
153
151
  module.exports = (sequelize, DataTypes) => {
154
152
  const ${modelName} = sequelize.define('${modelName}', {
155
153
  id: {
@@ -170,5 +168,5 @@ module.exports = (sequelize, DataTypes) => {
170
168
  return ${modelName};
171
169
  };
172
170
  `;
173
- }
171
+ }
174
172
  }
@@ -1,39 +1,5 @@
1
- // const path = require("path");
2
-
3
- // async function testDBConnection(targetDir, dbConfig) {
4
- // const sequelizePath = path.join(targetDir, "backend", "node_modules", "sequelize");
5
- // const { Sequelize } = require(sequelizePath);
6
-
7
- // const sequelize = new Sequelize(
8
- // dbConfig.database,
9
- // dbConfig.username,
10
- // dbConfig.password,
11
- // {
12
- // host: dbConfig.host,
13
- // port: dbConfig.port,
14
- // dialect: dbConfig.dialect,
15
- // logging: false
16
- // }
17
- // );
18
-
19
- // try {
20
- // await sequelize.authenticate();
21
- // console.log(`✅ Connection successful to ${dbConfig.dbKey}`);
22
- // await sequelize.close();
23
- // return true;
24
- // } catch (err) {
25
- // console.log(`❌ Failed to connect to ${dbConfig.dbKey}`);
26
- // console.log("Error:", err.message);
27
- // return false;
28
- // }
29
- // }
30
-
31
- // module.exports = testDBConnection;
32
-
33
-
34
-
35
1
  const path = require("path");
36
- const { assertDependency } = require("./utils");
2
+ const { assertDependency } = require("./utils");
37
3
 
38
4
  async function testDBConnection(targetDir, dbConfig) {
39
5
  const backendDir = path.join(targetDir, "Backend");