create-express-kickstart 1.2.3 โ†’ 1.2.5

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 (3) hide show
  1. package/README.md +27 -3
  2. package/bin/cli.js +49 -29
  3. package/package.json +10 -3
package/README.md CHANGED
@@ -8,7 +8,7 @@ A powerful CLI tool to instantly scaffold a production-ready, feature-rich backe
8
8
 
9
9
  ---
10
10
 
11
- ## ๐Ÿš€ Getting Started
11
+ ## Getting Started
12
12
 
13
13
  You do not need to clone this repository, install dependencies manually, or write an initial configuration yourself. Use `npx` (which comes with npm 5.2+) to instantly generate your backend boilerplate!
14
14
 
@@ -41,7 +41,7 @@ npm run dev
41
41
 
42
42
  ---
43
43
 
44
- ## ๐ŸŒŸ Features
44
+ ## Features
45
45
 
46
46
  - **Modern JavaScript**: ES6 Modules (`import`/`export`) enabled by default.
47
47
  - **Robust Error Handling**: Centralized error management using custom `ApiError` and `errorHandler` middleware.
@@ -54,7 +54,7 @@ npm run dev
54
54
 
55
55
  ---
56
56
 
57
- ## ๐Ÿ› ๏ธ Core Utilities Built-In
57
+ ## Core Utilities Built-In
58
58
 
59
59
  This template shines in its standardized utilities available out of the box for you:
60
60
 
@@ -82,3 +82,27 @@ const restrictedRoute = asyncHandler(async (req, res) => {
82
82
 
83
83
  ### `asyncHandler`
84
84
  A wrapper for your async route handlers that eliminates the need for repetitive `try-catch` blocks.
85
+
86
+ ### `hash.util.js`
87
+ If you choose to install the basic JWT Auth boilerplate, we automatically generate a generic hashing utility utilizing `bcryptjs` to help you securely hash and compare data (like passwords) natively.
88
+ ```javascript
89
+ import { hashData, compareData } from "#utils/hash.util.js";
90
+
91
+ const registerUser = asyncHandler(async (req, res) => {
92
+ const hashedPassword = await hashData("supersecret123");
93
+ // Store hashedPassword...
94
+ });
95
+
96
+ const loginUser = asyncHandler(async (req, res) => {
97
+ const isMatch = await compareData("supersecret123", user.hashedPassword);
98
+ // ...
99
+ });
100
+ ```
101
+
102
+ ## Contributing & Repository
103
+
104
+ Love this tool? Want to add a feature or fix a bug?
105
+ Feel free to open an issue or submit a pull request on our GitHub Repository!
106
+
107
+ **GitHub Repository:** [https://github.com/aasifashraf/create-express-kickstart](https://github.com/aasifashraf/create-express-kickstart)
108
+
package/bin/cli.js CHANGED
@@ -21,11 +21,11 @@ async function init() {
21
21
 
22
22
  let projectName = projectNameArg;
23
23
  if (!projectName) {
24
- projectName = await question('\n๐Ÿ‘‰ Project Directory Name (e.g. my-awesome-api): ');
24
+ projectName = await question('\n> Project Directory Name (e.g. my-awesome-api): ');
25
25
  }
26
26
 
27
27
  if (!projectName) {
28
- console.error('\nโŒ Error: Project Directory Name is required.');
28
+ console.error('\nError: Project Directory Name is required.');
29
29
  process.exit(1);
30
30
  }
31
31
 
@@ -33,19 +33,19 @@ async function init() {
33
33
  const projectPath = path.join(currentPath, projectName);
34
34
 
35
35
  if (fs.existsSync(projectPath)) {
36
- console.error(`\nโŒ Error: Folder ${projectName} already exists. Please choose a different directory name.\n`);
36
+ console.error(`\nError: Folder ${projectName} already exists. Please choose a different directory name.\n`);
37
37
  process.exit(1);
38
38
  }
39
39
 
40
- let packageJsonName = await question(`๐Ÿ‘‰ package.json name (${projectName}): `);
40
+ let packageJsonName = await question(`> package.json name (${projectName}): `);
41
41
  if (!packageJsonName.trim()) {
42
42
  packageJsonName = projectName; // Fallback to directory name
43
43
  }
44
44
 
45
- const description = await question('๐Ÿ‘‰ Project description: ');
46
- const author = await question('๐Ÿ‘‰ Author name: ');
45
+ const description = await question('> Project description: ');
46
+ const author = await question('> Author name: ');
47
47
 
48
- console.log('\n--- ๐Ÿ“ฆ Select Dependencies ---');
48
+ console.log('\n--- Select Dependencies ---');
49
49
  console.log('Press Enter for Yes (Y), type "n" for No.\n');
50
50
 
51
51
  const deps = {
@@ -65,19 +65,19 @@ async function init() {
65
65
  installPinoPretty = (await question('Include pino-pretty for clean development logs? [Y/n] ')).toLowerCase() !== 'n';
66
66
  }
67
67
 
68
- const packageManagerChoice = await question('\n๐Ÿ‘‰ Which package manager would you like to use? [npm/yarn/pnpm/bun] (default: npm): ');
68
+ const packageManagerChoice = await question('\n> Which package manager would you like to use? [npm/yarn/pnpm/bun] (default: npm): ');
69
69
  const packageManager = ['yarn', 'pnpm', 'bun'].includes(packageManagerChoice.trim().toLowerCase())
70
70
  ? packageManagerChoice.trim().toLowerCase()
71
71
  : 'npm';
72
72
 
73
- const initGit = (await question('\n๐Ÿ‘‰ Initialize a git repository? [Y/n] ')).toLowerCase() !== 'n';
74
- const initDocker = (await question('๐Ÿ‘‰ Include Dockerfile & docker-compose.yml? [Y/n] ')).toLowerCase() !== 'n';
75
- const initAuth = (await question('๐Ÿ‘‰ Include basic JWT Auth boilerplate? [Y/n] ')).toLowerCase() !== 'n';
76
- const initTests = (await question('๐Ÿ‘‰ Include Jest setup and boilerplate tests? [Y/n] ')).toLowerCase() !== 'n';
73
+ const initGit = (await question('\n> Initialize a git repository? [Y/n] ')).toLowerCase() !== 'n';
74
+ const initDocker = (await question('> Include Dockerfile & docker-compose.yml? [Y/n] ')).toLowerCase() !== 'n';
75
+ const initAuth = (await question('> Include basic JWT Auth boilerplate? [Y/n] ')).toLowerCase() !== 'n';
76
+ const initTests = (await question('> Include Jest setup and boilerplate tests? [Y/n] ')).toLowerCase() !== 'n';
77
77
 
78
78
  rl.close();
79
79
 
80
- console.log(`\n๐Ÿš€ Creating a new Node.js Express API in ${projectPath}...`);
80
+ console.log(`\n Creating a new Node.js Express API in ${projectPath}...`);
81
81
  fs.mkdirSync(projectPath, { recursive: true });
82
82
 
83
83
  function copyRecursiveSync(src, dest) {
@@ -99,15 +99,15 @@ async function init() {
99
99
  const targetSrcDir = path.join(projectPath, 'src');
100
100
 
101
101
  if (!fs.existsSync(sourceDir)) {
102
- console.error('\nโŒ Error: Could not find "src" directory in the template generator.');
102
+ console.error('\nError: Could not find "src" directory in the template generator.');
103
103
  process.exit(1);
104
104
  }
105
105
 
106
- console.log(`๐Ÿ“‚ Bootstrapping application structure (errorHandler, ApiResponse, async handlers)...`);
106
+ console.log(` Bootstrapping application structure (errorHandler, ApiResponse, async handlers)...`);
107
107
  copyRecursiveSync(sourceDir, targetSrcDir);
108
108
 
109
109
  // 2. Copy .env.example
110
- console.log(`๐Ÿ”ง Generating environment files...`);
110
+ console.log(` Generating environment files...`);
111
111
  const envExamplePath = path.join(__dirname, '..', '.env.example');
112
112
  if (fs.existsSync(envExamplePath)) {
113
113
  fs.copyFileSync(envExamplePath, path.join(projectPath, '.env.example'));
@@ -115,7 +115,7 @@ async function init() {
115
115
  }
116
116
 
117
117
  if (initDocker) {
118
- console.log(`๐Ÿณ Adding Docker files...`);
118
+ console.log(` Adding Docker files...`);
119
119
  const dockerfilePath = path.join(__dirname, '..', 'templates', 'Dockerfile');
120
120
  const dockerComposePath = path.join(__dirname, '..', 'templates', 'docker-compose.yml');
121
121
 
@@ -127,7 +127,7 @@ async function init() {
127
127
  }
128
128
 
129
129
  if (initAuth) {
130
- console.log(`๐Ÿ” Adding Auth templates...`);
130
+ console.log(` Adding Auth templates...`);
131
131
  // Need to ensure directories exist
132
132
  fs.mkdirSync(path.join(projectPath, 'src', 'controllers'), { recursive: true });
133
133
  fs.mkdirSync(path.join(projectPath, 'src', 'middlewares'), { recursive: true });
@@ -147,13 +147,33 @@ async function init() {
147
147
  path.join(projectPath, 'src', 'routes', 'auth.routes.js')
148
148
  );
149
149
 
150
- // Append JWT secret to env example
151
- fs.appendFileSync(path.join(projectPath, '.env.example'), '\nJWT_SECRET=supersecretjwtkey123\n');
152
- fs.appendFileSync(path.join(projectPath, '.env'), '\nJWT_SECRET=supersecretjwtkey123\n');
150
+ // Append JWT secret and Salt Rounds to env example
151
+ fs.appendFileSync(path.join(projectPath, '.env.example'), '\nJWT_SECRET=supersecretjwtkey123\nBCRYPT_SALT=10\n');
152
+ fs.appendFileSync(path.join(projectPath, '.env'), '\nJWT_SECRET=supersecretjwtkey123\nBCRYPT_SALT=10\n');
153
+
154
+ const utilsPath = path.join(projectPath, 'src', 'utils');
155
+ if (!fs.existsSync(utilsPath)) {
156
+ fs.mkdirSync(utilsPath, { recursive: true });
157
+ }
158
+ fs.writeFileSync(
159
+ path.join(utilsPath, 'hash.util.js'),
160
+ `import bcrypt from "bcryptjs";
161
+
162
+ export const hashData = async (data, saltRounds = process.env.BCRYPT_SALT) => {
163
+ const salt = await bcrypt.genSalt(Number(saltRounds) || 10);
164
+ return await bcrypt.hash(data, salt);
165
+ };
166
+
167
+ export const compareData = async (data, hashedData) => {
168
+ return await bcrypt.compare(data, hashedData);
169
+ };
170
+ `
171
+ );
172
+
153
173
  }
154
174
 
155
175
  if (initTests) {
156
- console.log(`๐Ÿงช Adding Jest test templates...`);
176
+ console.log(` Adding Jest test templates...`);
157
177
  fs.mkdirSync(path.join(projectPath, 'tests'), { recursive: true });
158
178
  fs.copyFileSync(
159
179
  path.join(__dirname, '..', 'templates', 'tests', 'healthcheck.test.js'),
@@ -225,7 +245,7 @@ async function init() {
225
245
  }
226
246
 
227
247
  // 3. Create package.json
228
- console.log(`๐Ÿ“ฆ Setting up package.json...`);
248
+ console.log(` Setting up package.json...`);
229
249
  const packageJsonTemplate = {
230
250
  name: packageJsonName.trim(),
231
251
  version: "1.0.0",
@@ -279,7 +299,7 @@ async function init() {
279
299
 
280
300
  // Inject dependencies directly into package.json instead of doing them via raw arguments.
281
301
  // This perfectly bypasses PNPM / YARN / BUN specific registry caching bugs when downloading deeply nested trees.
282
- console.log(`\nโณ Configuring ${packageManager} and resolving dependency trees...`);
302
+ console.log(`\n Configuring ${packageManager} and resolving dependency trees...`);
283
303
  const finalPackageJsonPath = path.join(projectPath, 'package.json');
284
304
  const finalPackageJsonCode = JSON.parse(fs.readFileSync(finalPackageJsonPath, 'utf8'));
285
305
 
@@ -294,12 +314,12 @@ async function init() {
294
314
 
295
315
  fs.writeFileSync(finalPackageJsonPath, JSON.stringify(finalPackageJsonCode, null, 2));
296
316
 
297
- console.log(`\nโณ Running final installation via ${packageManager} (This might take a minute)...`);
317
+ console.log(`\n Running final installation via ${packageManager} (This might take a minute)...`);
298
318
  const installTriggerCmd = packageManager === 'npm' ? 'npm install' : `${packageManager} install`;
299
319
  execSync(installTriggerCmd, execConfig);
300
320
 
301
321
  if (initGit) {
302
- console.log(`\n๐ŸŒฑ Initializing Git repository...`);
322
+ console.log(`\n Initializing Git repository...`);
303
323
  execSync('git init', { cwd: projectPath, stdio: 'inherit' });
304
324
  // Create .gitignore
305
325
  const gitignoreContent = "node_modules\n.env\ndist\nbuild\ncoverage\n";
@@ -308,7 +328,7 @@ async function init() {
308
328
  execSync('git commit -m "initial commit"', { cwd: projectPath, stdio: 'inherit' });
309
329
  }
310
330
 
311
- console.log(`\nโœ… Success! Created "${projectName}" at ${projectPath}`);
331
+ console.log(`\n Success! Created "${projectName}" at ${projectPath}`);
312
332
  console.log('\nInside that directory, you can run several commands:');
313
333
  console.log(`\n ${packageManager === 'npm' ? 'npm run' : packageManager} dev`);
314
334
  console.log(' Starts the development server on localhost.');
@@ -318,11 +338,11 @@ async function init() {
318
338
  console.log(`\n cd ${projectName}`);
319
339
  console.log(` ${packageManager === 'npm' ? 'npm run' : packageManager} dev\n`);
320
340
  } catch (err) {
321
- console.error('\nโŒ Failed to install dependencies. You may need to install them manually inside the folder.', err);
341
+ console.error('\nFailed to install dependencies. You may need to install them manually inside the folder.', err);
322
342
  }
323
343
  }
324
344
 
325
345
  init().catch(err => {
326
- console.error('\nโŒ Unexpected error occurred:', err);
346
+ console.error('\nUnexpected error occurred:', err);
327
347
  process.exit(1);
328
348
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-express-kickstart",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Production-ready CLI starter for Express APIs",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -18,8 +18,15 @@
18
18
  "template",
19
19
  "boilerplate"
20
20
  ],
21
- "author": "Your Name",
21
+ "author": "aasifashraf",
22
22
  "license": "ISC",
23
23
  "type": "module",
24
- "dependencies": {}
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/aasifashraf/create-express-kickstart.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/aasifashraf/create-express-kickstart/issues"
30
+ },
31
+ "homepage": "https://github.com/aasifashraf/create-express-kickstart#readme"
25
32
  }