launchbase 1.0.9 → 1.1.1
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 +29 -31
- package/package.json +1 -1
- package/template/.env.example +1 -1
- package/template/docker-compose.yml +1 -14
package/bin/launchbase.js
CHANGED
|
@@ -7,7 +7,7 @@ const crypto = require('crypto');
|
|
|
7
7
|
const fs = require('fs-extra');
|
|
8
8
|
const { execSync, spawn } = require('child_process');
|
|
9
9
|
|
|
10
|
-
const VERSION = '1.
|
|
10
|
+
const VERSION = '1.1.1';
|
|
11
11
|
const program = new Command();
|
|
12
12
|
|
|
13
13
|
function findAvailablePort(startPort = 5432, maxAttempts = 100) {
|
|
@@ -381,22 +381,26 @@ program
|
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
// Copy template files with filtering
|
|
384
|
+
console.log('📂 Copying template files...');
|
|
385
|
+
console.log(` Include frontend: ${options.template ? 'yes' : 'no'}`);
|
|
386
|
+
|
|
384
387
|
await fs.copy(templateDir, targetDir, {
|
|
385
388
|
filter: (src) => {
|
|
386
|
-
|
|
389
|
+
// Normalize path separators for cross-platform compatibility
|
|
390
|
+
const relativePath = path.relative(templateDir, src).replace(/\\/g, '/');
|
|
387
391
|
|
|
388
392
|
// Skip node_modules, dist, etc.
|
|
389
393
|
if (relativePath.includes('node_modules') || relativePath.includes('dist') || relativePath.includes('.next')) {
|
|
390
394
|
return false;
|
|
391
395
|
}
|
|
392
396
|
|
|
393
|
-
// Skip frontend if not requested
|
|
394
|
-
if (relativePath.startsWith('frontend') && !options.template) {
|
|
397
|
+
// Skip frontend if not requested (check with trailing slash to avoid partial matches)
|
|
398
|
+
if ((relativePath.startsWith('frontend/') || relativePath === 'frontend') && !options.template) {
|
|
395
399
|
return false;
|
|
396
400
|
}
|
|
397
401
|
|
|
398
402
|
// Skip SDK if not requested
|
|
399
|
-
if (relativePath.startsWith('sdk') && !options.sdk) {
|
|
403
|
+
if ((relativePath.startsWith('sdk/') || relativePath === 'sdk') && !options.sdk) {
|
|
400
404
|
return false;
|
|
401
405
|
}
|
|
402
406
|
|
|
@@ -422,20 +426,12 @@ program
|
|
|
422
426
|
// Replace placeholders with dynamic ports
|
|
423
427
|
const replacements = {
|
|
424
428
|
'__APP_NAME__': appName,
|
|
429
|
+
'__DB_PORT__': dbPort.toString(),
|
|
425
430
|
'"name": "launchbase-template"': `"name": "${appName}"`,
|
|
426
|
-
'"PORT=3000"': `"PORT=${apiPort}"`,
|
|
427
|
-
'PORT=3000': `PORT=${apiPort}`,
|
|
428
|
-
'localhost:3000': `localhost:${apiPort}`,
|
|
429
|
-
'localhost:5173': `localhost:${frontendPort}`,
|
|
430
|
-
'localhost:5433': `localhost:${dbPort}`,
|
|
431
|
-
'localhost:5432': `localhost:${dbPort}`,
|
|
432
|
-
'"5433:5432"': `"${dbPort}:5432"`,
|
|
433
|
-
'"5432:5432"': `"${dbPort}:5432"`,
|
|
434
|
-
'"3000:3000"': `"${apiPort}:3000"`,
|
|
435
431
|
};
|
|
436
432
|
|
|
437
433
|
// Update files with port replacements
|
|
438
|
-
const filesToReplace = ['package.json', '.env.example', 'README.md', 'docker-compose.yml'
|
|
434
|
+
const filesToReplace = ['package.json', '.env.example', 'README.md', 'docker-compose.yml'];
|
|
439
435
|
for (const rel of filesToReplace) {
|
|
440
436
|
const fp = path.join(targetDir, rel);
|
|
441
437
|
if (await fs.pathExists(fp)) {
|
|
@@ -443,30 +439,31 @@ program
|
|
|
443
439
|
}
|
|
444
440
|
}
|
|
445
441
|
|
|
446
|
-
// Generate .env with secrets
|
|
442
|
+
// Generate .env with secrets and correct ports
|
|
447
443
|
const envExamplePath = path.join(targetDir, '.env.example');
|
|
448
444
|
const envPath = path.join(targetDir, '.env');
|
|
449
445
|
|
|
450
446
|
if (await fs.pathExists(envExamplePath)) {
|
|
451
447
|
let env = await fs.readFile(envExamplePath, 'utf8');
|
|
448
|
+
// Replace app name
|
|
449
|
+
env = env.replace(/__APP_NAME__/g, appName);
|
|
450
|
+
// Replace secrets
|
|
452
451
|
env = env.replace('JWT_ACCESS_SECRET=__CHANGE_ME__', `JWT_ACCESS_SECRET=${randomSecret(32)}`);
|
|
453
452
|
env = env.replace('JWT_REFRESH_SECRET=__CHANGE_ME__', `JWT_REFRESH_SECRET=${randomSecret(32)}`);
|
|
454
|
-
//
|
|
453
|
+
// Replace ports
|
|
455
454
|
env = env.replace(/PORT=\d+/, `PORT=${apiPort}`);
|
|
456
|
-
env = env.replace(/localhost:\d
|
|
455
|
+
env = env.replace(/localhost:\d+\/__APP_NAME__/g, `localhost:${dbPort}/${appName}`);
|
|
456
|
+
env = env.replace(/localhost:5433/g, `localhost:${dbPort}`);
|
|
457
|
+
env = env.replace(/localhost:5432/g, `localhost:${dbPort}`);
|
|
458
|
+
env = env.replace(/localhost:3000/g, `localhost:${apiPort}`);
|
|
459
|
+
env = env.replace(/localhost:5173/g, `localhost:${frontendPort}`);
|
|
457
460
|
await fs.writeFile(envPath, env, 'utf8');
|
|
458
461
|
}
|
|
459
462
|
|
|
460
|
-
// Update docker-compose.yml with correct ports
|
|
461
|
-
const dockerComposePath = path.join(targetDir, 'docker-compose.yml');
|
|
462
|
-
if (await fs.pathExists(dockerComposePath)) {
|
|
463
|
-
let compose = await fs.readFile(dockerComposePath, 'utf8');
|
|
464
|
-
compose = compose.replace(/"(\d+):5432"/, `"${dbPort}:5432"`);
|
|
465
|
-
compose = compose.replace(/"(\d+):3000"/, `"${apiPort}:3000"`);
|
|
466
|
-
await fs.writeFile(dockerComposePath, compose, 'utf8');
|
|
467
|
-
}
|
|
468
|
-
|
|
469
463
|
console.log('✅ Project files created\n');
|
|
464
|
+
console.log(` Database port: ${dbPort}`);
|
|
465
|
+
console.log(` API port: ${apiPort}`);
|
|
466
|
+
console.log(` Frontend port: ${frontendPort}\n`);
|
|
470
467
|
|
|
471
468
|
// Install dependencies
|
|
472
469
|
console.log('📦 Installing dependencies...\n');
|
|
@@ -590,20 +587,21 @@ program
|
|
|
590
587
|
// Copy template files with filtering
|
|
591
588
|
await fs.copy(templateDir, targetDir, {
|
|
592
589
|
filter: (src) => {
|
|
593
|
-
|
|
590
|
+
// Normalize path separators for cross-platform compatibility
|
|
591
|
+
const relativePath = path.relative(templateDir, src).replace(/\\/g, '/');
|
|
594
592
|
|
|
595
593
|
// Skip node_modules, dist, etc.
|
|
596
594
|
if (relativePath.includes('node_modules') || relativePath.includes('dist') || relativePath.includes('.next')) {
|
|
597
595
|
return false;
|
|
598
596
|
}
|
|
599
597
|
|
|
600
|
-
// Skip frontend if not requested
|
|
601
|
-
if (relativePath.startsWith('frontend') && !options.template) {
|
|
598
|
+
// Skip frontend if not requested (check with trailing slash to avoid partial matches)
|
|
599
|
+
if ((relativePath.startsWith('frontend/') || relativePath === 'frontend') && !options.template) {
|
|
602
600
|
return false;
|
|
603
601
|
}
|
|
604
602
|
|
|
605
603
|
// Skip SDK if not requested
|
|
606
|
-
if (relativePath.startsWith('sdk') && !options.sdk) {
|
|
604
|
+
if ((relativePath.startsWith('sdk/') || relativePath === 'sdk') && !options.sdk) {
|
|
607
605
|
return false;
|
|
608
606
|
}
|
|
609
607
|
|
package/package.json
CHANGED
package/template/.env.example
CHANGED
|
@@ -15,7 +15,7 @@ FRONTEND_URL=http://localhost:5173
|
|
|
15
15
|
# Database
|
|
16
16
|
# ===========================================
|
|
17
17
|
# Local PostgreSQL (with Docker)
|
|
18
|
-
DATABASE_URL=postgresql://postgres:postgres@localhost:
|
|
18
|
+
DATABASE_URL=postgresql://postgres:postgres@localhost:__DB_PORT__/__APP_NAME__?schema=public
|
|
19
19
|
# SQLite (for simple local dev)
|
|
20
20
|
# DATABASE_URL="file:./dev.db"
|
|
21
21
|
|
|
@@ -7,7 +7,7 @@ services:
|
|
|
7
7
|
POSTGRES_PASSWORD: postgres
|
|
8
8
|
POSTGRES_DB: launchbase
|
|
9
9
|
ports:
|
|
10
|
-
- "
|
|
10
|
+
- "__DB_PORT__:5432"
|
|
11
11
|
volumes:
|
|
12
12
|
- db_data:/var/lib/postgresql/data
|
|
13
13
|
healthcheck:
|
|
@@ -16,18 +16,5 @@ services:
|
|
|
16
16
|
timeout: 5s
|
|
17
17
|
retries: 5
|
|
18
18
|
|
|
19
|
-
api:
|
|
20
|
-
build: .
|
|
21
|
-
restart: unless-stopped
|
|
22
|
-
env_file:
|
|
23
|
-
- .env
|
|
24
|
-
environment:
|
|
25
|
-
DATABASE_URL: ${DATABASE_URL}
|
|
26
|
-
ports:
|
|
27
|
-
- "3000:3000"
|
|
28
|
-
depends_on:
|
|
29
|
-
db:
|
|
30
|
-
condition: service_healthy
|
|
31
|
-
|
|
32
19
|
volumes:
|
|
33
20
|
db_data:
|