create-express-kickstart 1.2.1 → 1.2.3

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
@@ -14,14 +14,16 @@ You do not need to clone this repository, install dependencies manually, or writ
14
14
 
15
15
  ### 1. Initialize a New Project
16
16
 
17
+ We highly recommend using the `@latest` tag to ensure you are always downloading the most recent version of our CLI tool dynamically, bypassing any local caching issues!
18
+
17
19
  Run the following command anywhere in your terminal:
18
20
  ```bash
19
- npx create-express-kickstart <your-project-name>
21
+ npx create-express-kickstart@latest <your-project-name>
20
22
  ```
21
23
 
22
24
  **Example:**
23
25
  ```bash
24
- npx create-express-kickstart my-awesome-api
26
+ npx create-express-kickstart@latest my-awesome-api
25
27
  ```
26
28
 
27
29
  ### 2. What happens under the hood?
package/bin/cli.js CHANGED
@@ -73,7 +73,6 @@ async function init() {
73
73
  const initGit = (await question('\nšŸ‘‰ Initialize a git repository? [Y/n] ')).toLowerCase() !== 'n';
74
74
  const initDocker = (await question('šŸ‘‰ Include Dockerfile & docker-compose.yml? [Y/n] ')).toLowerCase() !== 'n';
75
75
  const initAuth = (await question('šŸ‘‰ Include basic JWT Auth boilerplate? [Y/n] ')).toLowerCase() !== 'n';
76
- const useESM = (await question('šŸ‘‰ Use ECMAScript Modules (ESM) over CommonJS? [Y/n] ')).toLowerCase() !== 'n';
77
76
  const initTests = (await question('šŸ‘‰ Include Jest setup and boilerplate tests? [Y/n] ')).toLowerCase() !== 'n';
78
77
 
79
78
  rl.close();
@@ -162,6 +161,69 @@ async function init() {
162
161
  );
163
162
  }
164
163
 
164
+ // Rewrite app.js and server.js based on selections
165
+ let appJsPath = path.join(projectPath, 'src', 'app.js');
166
+ if (fs.existsSync(appJsPath)) {
167
+ let appJsCode = fs.readFileSync(appJsPath, 'utf8');
168
+
169
+ if (initAuth) {
170
+ appJsCode = appJsCode.replace(
171
+ '// Import routers',
172
+ '// Import routers\nimport authRouter from "#routes/auth.routes.js";'
173
+ );
174
+ appJsCode = appJsCode.replace(
175
+ '// Mount routers',
176
+ '// Mount routers\napp.use("/api/v1/auth", authRouter);'
177
+ );
178
+ }
179
+ if (!deps.cors) {
180
+ appJsCode = appJsCode.replace(/import cors from "cors";\r?\n/, '');
181
+ appJsCode = appJsCode.replace(/\/\/ CORS setup[\s\S]*?\n\);\r?\n/, '');
182
+ }
183
+ if (!deps.helmet) {
184
+ appJsCode = appJsCode.replace(/import helmet from "helmet";\r?\n/, '');
185
+ appJsCode = appJsCode.replace(/\/\/ Security HTTP headers\r?\napp\.use\(helmet\(\)\);\r?\n/, '');
186
+ }
187
+ if (!deps['cookie-parser']) {
188
+ appJsCode = appJsCode.replace(/import cookieParser from "cookie-parser";\r?\n/, '');
189
+ appJsCode = appJsCode.replace(/app\.use\(cookieParser\(\)\);\r?\n/, '');
190
+ }
191
+ if (!deps['pino-http']) {
192
+ appJsCode = appJsCode.replace(/import pinoHttp from "pino-http";\r?\n/, '');
193
+ appJsCode = appJsCode.replace(/\/\/ Logging[\s\S]*?\}\)\(\) \? : undefined\n\}\)\);\r?\n/g, ''); // Fallback block
194
+ appJsCode = appJsCode.replace(/\/\/ Logging[\s\S]*?\}\)\(\) : undefined\r?\n\}\)\);\r?\n/g, '');
195
+ }
196
+ if (!deps['express-rate-limit']) {
197
+ appJsCode = appJsCode.replace(/import rateLimit from "express-rate-limit";\r?\n/, '');
198
+ appJsCode = appJsCode.replace(/\/\/ Rate Limiting[\s\S]*?app\.use\("\/api", limiter\);[^\n]*\n/g, '');
199
+ }
200
+
201
+ fs.writeFileSync(appJsPath, appJsCode);
202
+ }
203
+
204
+ let serverJsPath = path.join(projectPath, 'src', 'server.js');
205
+ if (fs.existsSync(serverJsPath)) {
206
+ let serverJsCode = fs.readFileSync(serverJsPath, 'utf8');
207
+
208
+ if (!deps.mongoose) {
209
+ serverJsCode = serverJsCode.replace(/import connectDB from "#db\/index\.js";\r?\n/, '');
210
+ serverJsCode = serverJsCode.replace(/connectDB\(\)\r?\n \.then\(\(\) => \{\r?\n/, '');
211
+ serverJsCode = serverJsCode.replace(/ \}\)\r?\n \.catch\(\(err\) => \{\r?\n console\.log\("MONGO db connection failed !!! ", err\);\r?\n \}\);\r?\n/, '');
212
+ // Fix indentation for app.listen
213
+ serverJsCode = serverJsCode.replace(/ app\.listen\(PORT, \(\) => \{\r?\n console\.log\(`Server is running at port : \$\{PORT\}`\);\r?\n \}\);\r?\n/, 'app.listen(PORT, () => {\n console.log(`Server is running at port : ${PORT}`);\n});\n');
214
+
215
+ const dbDir = path.join(projectPath, 'src', 'db');
216
+ if (fs.existsSync(dbDir)) fs.rmSync(dbDir, { recursive: true, force: true });
217
+ }
218
+
219
+ if (!deps.dotenv) {
220
+ serverJsCode = serverJsCode.replace(/import dotenv from "dotenv";\r?\n/, '');
221
+ serverJsCode = serverJsCode.replace(/\/\/ Load environment variables[\s\S]*?\}\);\r?\n/, '');
222
+ }
223
+
224
+ fs.writeFileSync(serverJsPath, serverJsCode);
225
+ }
226
+
165
227
  // 3. Create package.json
166
228
  console.log(`šŸ“¦ Setting up package.json...`);
167
229
  const packageJsonTemplate = {
@@ -169,7 +231,7 @@ async function init() {
169
231
  version: "1.0.0",
170
232
  description: description || "A production-ready Node.js Express API",
171
233
  main: "src/server.js",
172
- type: useESM ? "module" : "commonjs",
234
+ type: "module",
173
235
  scripts: {
174
236
  "start": "node src/server.js",
175
237
  "dev": "nodemon src/server.js"
@@ -187,9 +249,7 @@ async function init() {
187
249
  }
188
250
 
189
251
  if (initTests) {
190
- packageJsonTemplate.scripts.test = useESM
191
- ? "node --experimental-vm-modules node_modules/jest/bin/jest.js"
192
- : "jest";
252
+ packageJsonTemplate.scripts.test = "node --experimental-vm-modules node_modules/jest/bin/jest.js";
193
253
  }
194
254
 
195
255
  // Write package.json
@@ -206,7 +266,6 @@ async function init() {
206
266
  if (initAuth) {
207
267
  dependenciesToInstall.push('jsonwebtoken', 'bcryptjs'); // Add bcryptjs too since it's standard with JWT
208
268
  }
209
- const depString = dependenciesToInstall.join(' ');
210
269
 
211
270
  const devDependenciesToInstall = ['nodemon'];
212
271
  if (deps.prettier) devDependenciesToInstall.push('prettier');
@@ -214,32 +273,30 @@ async function init() {
214
273
  if (initTests) {
215
274
  devDependenciesToInstall.push('jest', 'supertest');
216
275
  }
217
- const devDepString = devDependenciesToInstall.join(' ');
218
276
 
219
- console.log(`\nā³ Installing selected core dependencies (${dependenciesToInstall.join(', ')}). This might take a minute...`);
220
277
  try {
221
- let installCmd = packageManager === 'yarn' ? 'yarn add'
222
- : packageManager === 'pnpm' ? 'pnpm add'
223
- : packageManager === 'bun' ? 'bun add'
224
- : 'npm install';
225
-
226
- let installDevCmd = packageManager === 'yarn' ? 'yarn add -D'
227
- : packageManager === 'pnpm' ? 'pnpm add -D'
228
- : packageManager === 'bun' ? 'bun add -d'
229
- : 'npm install --save-dev';
230
-
231
- if (depString) {
232
- execSync(`${installCmd} ${depString}`, {
233
- cwd: projectPath,
234
- stdio: 'inherit'
235
- });
236
- }
278
+ const execConfig = { cwd: projectPath, stdio: 'inherit' };
279
+
280
+ // Inject dependencies directly into package.json instead of doing them via raw arguments.
281
+ // 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...`);
283
+ const finalPackageJsonPath = path.join(projectPath, 'package.json');
284
+ const finalPackageJsonCode = JSON.parse(fs.readFileSync(finalPackageJsonPath, 'utf8'));
237
285
 
238
- console.log(`\nā³ Installing latest dev dependencies (${devDepString})...`);
239
- execSync(`${installDevCmd} ${devDepString}`, {
240
- cwd: projectPath,
241
- stdio: 'inherit'
242
- });
286
+ // We add them dynamically so package managers can evaluate them holistically at once
287
+ const latestDeps = {};
288
+ dependenciesToInstall.forEach(d => latestDeps[d] = 'latest');
289
+ finalPackageJsonCode.dependencies = latestDeps;
290
+
291
+ const latestDevDeps = {};
292
+ devDependenciesToInstall.forEach(d => latestDevDeps[d] = 'latest');
293
+ finalPackageJsonCode.devDependencies = latestDevDeps;
294
+
295
+ fs.writeFileSync(finalPackageJsonPath, JSON.stringify(finalPackageJsonCode, null, 2));
296
+
297
+ console.log(`\nā³ Running final installation via ${packageManager} (This might take a minute)...`);
298
+ const installTriggerCmd = packageManager === 'npm' ? 'npm install' : `${packageManager} install`;
299
+ execSync(installTriggerCmd, execConfig);
243
300
 
244
301
  if (initGit) {
245
302
  console.log(`\n🌱 Initializing Git repository...`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-express-kickstart",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Production-ready CLI starter for Express APIs",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  import { Router } from 'express';
2
- import { authController } from '../controllers/auth.controller.js';
3
- import { authMiddleware } from '../middlewares/auth.middleware.js';
2
+ import { authController } from '#controllers/auth.controller.js';
3
+ import { authMiddleware } from '#middlewares/auth.middleware.js';
4
4
 
5
5
  const router = Router();
6
6
 
@@ -7,6 +7,6 @@ describe('Healthcheck API', () => {
7
7
 
8
8
  expect(response.status).toBe(200);
9
9
  expect(response.body.success).toBe(true);
10
- expect(response.body.message).toBe('Api is runing properly');
10
+ expect(response.body.message).toBe('App is running smoothly');
11
11
  });
12
12
  });