launchbase 1.0.5 → 1.0.6

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/launchbase.js +72 -10
  2. package/package.json +1 -1
package/bin/launchbase.js CHANGED
@@ -1,14 +1,46 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const path = require('path');
4
+ const net = require('net');
4
5
  const { Command } = require('commander');
5
6
  const crypto = require('crypto');
6
7
  const fs = require('fs-extra');
7
8
  const { execSync, spawn } = require('child_process');
8
9
 
9
- const VERSION = '1.0.5';
10
+ const VERSION = '1.0.6';
10
11
  const program = new Command();
11
12
 
13
+ function findAvailablePort(startPort = 5432, maxAttempts = 100) {
14
+ return new Promise((resolve, reject) => {
15
+ const tryPort = (port, attempts) => {
16
+ if (attempts >= maxAttempts) {
17
+ reject(new Error('Could not find available port'));
18
+ return;
19
+ }
20
+
21
+ const server = net.createServer();
22
+ server.once('error', () => {
23
+ tryPort(port + 1, attempts + 1);
24
+ });
25
+ server.once('listening', () => {
26
+ server.close();
27
+ resolve(port);
28
+ });
29
+ server.listen(port);
30
+ };
31
+
32
+ tryPort(startPort, 0);
33
+ });
34
+ }
35
+
36
+ function findAvailablePorts() {
37
+ return Promise.all([
38
+ findAvailablePort(5432, 100), // Database port
39
+ findAvailablePort(3000, 100), // API port
40
+ findAvailablePort(5173, 100), // Frontend port
41
+ ]);
42
+ }
43
+
12
44
  function replaceInFile(filePath, replacements) {
13
45
  let content = fs.readFileSync(filePath, 'utf8');
14
46
  for (const [from, to] of Object.entries(replacements)) {
@@ -331,6 +363,11 @@ program
331
363
  console.log('\nšŸš€ LaunchBase CLI v' + VERSION + '\n');
332
364
  console.log('šŸ“ Creating project:', appName);
333
365
 
366
+ // Find available ports first
367
+ console.log('šŸ” Finding available ports...');
368
+ const [dbPort, apiPort, frontendPort] = await findAvailablePorts();
369
+ console.log(` Database: ${dbPort}, API: ${apiPort}, Frontend: ${frontendPort}\n`);
370
+
334
371
  const templateDir = path.resolve(__dirname, '..', 'template');
335
372
  const targetDir = path.resolve(process.cwd(), appName);
336
373
 
@@ -380,13 +417,23 @@ program
380
417
  }
381
418
  });
382
419
 
383
- // Replace placeholders
420
+ // Replace placeholders with dynamic ports
384
421
  const replacements = {
385
422
  '__APP_NAME__': appName,
386
423
  '"name": "launchbase-template"': `"name": "${appName}"`,
424
+ '"PORT=3000"': `"PORT=${apiPort}"`,
425
+ 'PORT=3000': `PORT=${apiPort}`,
426
+ 'localhost:3000': `localhost:${apiPort}`,
427
+ 'localhost:5173': `localhost:${frontendPort}`,
428
+ 'localhost:5433': `localhost:${dbPort}`,
429
+ 'localhost:5432': `localhost:${dbPort}`,
430
+ '"5433:5432"': `"${dbPort}:5432"`,
431
+ '"5432:5432"': `"${dbPort}:5432"`,
432
+ '"3000:3000"': `"${apiPort}:3000"`,
387
433
  };
388
434
 
389
- const filesToReplace = ['package.json', '.env.example', 'README.md'];
435
+ // Update files with port replacements
436
+ const filesToReplace = ['package.json', '.env.example', 'README.md', 'docker-compose.yml', '.env'];
390
437
  for (const rel of filesToReplace) {
391
438
  const fp = path.join(targetDir, rel);
392
439
  if (await fs.pathExists(fp)) {
@@ -402,9 +449,21 @@ program
402
449
  let env = await fs.readFile(envExamplePath, 'utf8');
403
450
  env = env.replace('JWT_ACCESS_SECRET=__CHANGE_ME__', `JWT_ACCESS_SECRET=${randomSecret(32)}`);
404
451
  env = env.replace('JWT_REFRESH_SECRET=__CHANGE_ME__', `JWT_REFRESH_SECRET=${randomSecret(32)}`);
452
+ // Ensure ports are correct
453
+ env = env.replace(/PORT=\d+/, `PORT=${apiPort}`);
454
+ env = env.replace(/localhost:\d+.*__APP_NAME__/g, `localhost:${dbPort}/${appName}`);
405
455
  await fs.writeFile(envPath, env, 'utf8');
406
456
  }
407
457
 
458
+ // Update docker-compose.yml with correct ports
459
+ const dockerComposePath = path.join(targetDir, 'docker-compose.yml');
460
+ if (await fs.pathExists(dockerComposePath)) {
461
+ let compose = await fs.readFile(dockerComposePath, 'utf8');
462
+ compose = compose.replace(/"(\d+):5432"/, `"${dbPort}:5432"`);
463
+ compose = compose.replace(/"(\d+):3000"/, `"${apiPort}:3000"`);
464
+ await fs.writeFile(dockerComposePath, compose, 'utf8');
465
+ }
466
+
408
467
  console.log('āœ… Project files created\n');
409
468
 
410
469
  // Install dependencies
@@ -444,20 +503,22 @@ program
444
503
  // Start dev server
445
504
  console.log('\nšŸš€ Starting development server...\n');
446
505
  console.log('━'.repeat(50));
447
- console.log(' API: http://localhost:3000');
448
- console.log(' Docs: http://localhost:3000/docs');
449
- console.log(' Health: http://localhost:3000/health');
506
+ console.log(` API: http://localhost:${apiPort}`);
507
+ console.log(` Docs: http://localhost:${apiPort}/docs`);
508
+ console.log(` Health: http://localhost:${apiPort}/health`);
450
509
  if (options.template) {
451
- console.log(' Frontend: http://localhost:5173');
510
+ console.log(` Frontend: http://localhost:${frontendPort}`);
452
511
  }
512
+ console.log(` Database: localhost:${dbPort}`);
453
513
  console.log('━'.repeat(50));
454
514
  console.log('\nPress Ctrl+C to stop\n');
455
515
 
456
- // Start backend
516
+ // Start backend with correct port
457
517
  const backend = spawn('npm', ['run', 'start:dev'], {
458
518
  cwd: targetDir,
459
519
  stdio: 'inherit',
460
- shell: true
520
+ shell: true,
521
+ env: { ...process.env, PORT: apiPort.toString() }
461
522
  });
462
523
 
463
524
  // Start frontend after delay if included
@@ -468,7 +529,8 @@ program
468
529
  const frontend = spawn('npm', ['run', 'dev'], {
469
530
  cwd: frontendPath,
470
531
  stdio: 'inherit',
471
- shell: true
532
+ shell: true,
533
+ env: { ...process.env, VITE_API_URL: `http://localhost:${apiPort}`, PORT: frontendPort.toString() }
472
534
  });
473
535
  }, 5000);
474
536
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "launchbase",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Generate production-ready NestJS backends with authentication, multi-tenancy, billing, and deployment in minutes",
5
5
  "author": "LaunchBase",
6
6
  "keywords": [