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.
- package/bin/launchbase.js +72 -10
- 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.
|
|
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
|
-
|
|
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(
|
|
448
|
-
console.log(
|
|
449
|
-
console.log(
|
|
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(
|
|
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