genbox 1.0.80 → 1.0.82
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/dist/commands/forward.js +31 -10
- package/dist/commands/init.js +13 -5
- package/dist/commands/rebuild.js +58 -34
- package/dist/db-utils.js +10 -1
- package/dist/profile-resolver.js +11 -4
- package/package.json +1 -1
package/dist/commands/forward.js
CHANGED
|
@@ -93,22 +93,43 @@ exports.forwardCommand = new commander_1.Command('forward')
|
|
|
93
93
|
}
|
|
94
94
|
// 3. Build port mappings from config or defaults
|
|
95
95
|
const portMappings = [];
|
|
96
|
-
// Try to load config for service ports
|
|
96
|
+
// Try to load config for service ports from genbox.yaml
|
|
97
97
|
try {
|
|
98
98
|
const config = (0, config_1.loadConfig)();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
// Read ports from genbox.yaml apps config
|
|
100
|
+
if (config.apps) {
|
|
101
|
+
for (const [appName, appConfig] of Object.entries(config.apps)) {
|
|
102
|
+
const port = appConfig.port;
|
|
103
|
+
if (port && typeof port === 'number') {
|
|
104
|
+
portMappings.push({
|
|
105
|
+
name: appName,
|
|
106
|
+
localPort: port,
|
|
107
|
+
remotePort: port,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Also add infrastructure ports from provides
|
|
113
|
+
if (config.provides) {
|
|
114
|
+
for (const [infraName, infraConfig] of Object.entries(config.provides)) {
|
|
115
|
+
if (infraConfig.port) {
|
|
116
|
+
portMappings.push({
|
|
117
|
+
name: infraName,
|
|
118
|
+
localPort: infraConfig.port,
|
|
119
|
+
remotePort: infraConfig.port,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
124
|
}
|
|
109
125
|
catch {
|
|
110
|
-
// No config
|
|
111
|
-
|
|
126
|
+
// No config found - require genbox.yaml
|
|
127
|
+
console.error(chalk_1.default.red('No genbox.yaml found. Run "gb init" first to configure your project.'));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (portMappings.length === 0) {
|
|
131
|
+
console.error(chalk_1.default.yellow('No apps with ports found in genbox.yaml. Nothing to forward.'));
|
|
132
|
+
return;
|
|
112
133
|
}
|
|
113
134
|
// Add custom ports if specified
|
|
114
135
|
if (options.ports) {
|
package/dist/commands/init.js
CHANGED
|
@@ -762,8 +762,10 @@ async function setupEnvironmentsAndServiceUrls(detected, existingEnvValues) {
|
|
|
762
762
|
}
|
|
763
763
|
// Service URL detection and mapping
|
|
764
764
|
const serviceUrlMappings = await setupServiceUrls(detected, environments, existingEnvValues);
|
|
765
|
-
// Always add LOCAL_API_URL
|
|
766
|
-
|
|
765
|
+
// Always add LOCAL_API_URL - get port from detected api app
|
|
766
|
+
const apiApp = detected.apps?.['api'];
|
|
767
|
+
const apiPort = apiApp?.port || 3050;
|
|
768
|
+
envVars['LOCAL_API_URL'] = `http://localhost:${apiPort}`;
|
|
767
769
|
return {
|
|
768
770
|
environments: Object.keys(environments).length > 0 ? environments : undefined,
|
|
769
771
|
serviceUrlMappings,
|
|
@@ -817,9 +819,11 @@ async function setupServiceUrls(detected, environments, existingEnvValues) {
|
|
|
817
819
|
console.log(chalk_1.default.dim(`Mapping selected URLs to ${primaryEnv} environment:`));
|
|
818
820
|
for (const svc of selectedServices) {
|
|
819
821
|
const serviceInfo = getServiceInfoFromUrl(svc.base_url);
|
|
822
|
+
// Get API port from detected config for URL matching
|
|
823
|
+
const detectedApiPort = detected.apps?.['api']?.port;
|
|
820
824
|
// Auto-map API/gateway URLs
|
|
821
825
|
const isApiService = serviceInfo.name === 'gateway' ||
|
|
822
|
-
svc.base_url.includes(
|
|
826
|
+
(detectedApiPort && svc.base_url.includes(`:${detectedApiPort}`)) ||
|
|
823
827
|
svc.used_by.some(v => v.toLowerCase().includes('api'));
|
|
824
828
|
let remoteUrl = '';
|
|
825
829
|
if (isApiService && apiUrl) {
|
|
@@ -1799,13 +1803,17 @@ exports.initCommand = new commander_1.Command('init')
|
|
|
1799
1803
|
const yamlContent = yaml.dump(config, { lineWidth: 120, noRefs: true, quotingType: '"' });
|
|
1800
1804
|
fs_1.default.writeFileSync(configPath, yamlContent);
|
|
1801
1805
|
console.log(chalk_1.default.green(`\n✔ Configuration saved to ${CONFIG_FILENAME}`));
|
|
1802
|
-
|
|
1806
|
+
// Get API port from detected config
|
|
1807
|
+
const fastPathApiApp = detected.apps?.['api'];
|
|
1808
|
+
const fastPathApiPort = fastPathApiApp?.port || 3050;
|
|
1809
|
+
const fastPathLocalApiUrl = `http://localhost:${fastPathApiPort}`;
|
|
1810
|
+
const envContent = generateEnvFile(settings.projectName, detected, { ...gitEnvVars, LOCAL_API_URL: fastPathLocalApiUrl }, []);
|
|
1803
1811
|
fs_1.default.writeFileSync(path_1.default.join(rootDir, ENV_FILENAME), envContent);
|
|
1804
1812
|
console.log(chalk_1.default.green(`✔ Created ${ENV_FILENAME}`));
|
|
1805
1813
|
// Sync project to API if logged in
|
|
1806
1814
|
if (config_store_1.ConfigStore.getToken()) {
|
|
1807
1815
|
try {
|
|
1808
|
-
const payload = configToSyncPayload(config, { ...gitEnvVars, LOCAL_API_URL:
|
|
1816
|
+
const payload = configToSyncPayload(config, { ...gitEnvVars, LOCAL_API_URL: fastPathLocalApiUrl });
|
|
1809
1817
|
const result = await (0, api_1.syncProject)(payload);
|
|
1810
1818
|
saveProjectCache(rootDir, {
|
|
1811
1819
|
_id: result._id,
|
package/dist/commands/rebuild.js
CHANGED
|
@@ -261,21 +261,42 @@ async function runSoftRebuild(options) {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
// Step 6: Start Docker Compose services
|
|
264
|
+
// Step 6: Start Docker Compose services (only for apps with runner: docker + infrastructure)
|
|
265
265
|
onStep?.('Starting Docker services...');
|
|
266
266
|
for (const repo of resolved.repos) {
|
|
267
267
|
const hasDockerCompose = await sshExec(ip, keyPath, `test -f ${repo.path}/docker-compose.yml -o -f ${repo.path}/docker-compose.yaml -o -f ${repo.path}/compose.yaml && echo yes || echo no`, 10);
|
|
268
268
|
if (hasDockerCompose.output === 'yes') {
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
269
|
+
// Get list of services to start: apps with runner: docker + infrastructure (provides)
|
|
270
|
+
const dockerServices = [];
|
|
271
|
+
// Add apps with runner: docker
|
|
272
|
+
for (const app of resolved.apps) {
|
|
273
|
+
const appConfig = config.apps[app.name];
|
|
274
|
+
if (appConfig?.runner === 'docker') {
|
|
275
|
+
const serviceName = appConfig.docker?.service || app.name;
|
|
276
|
+
dockerServices.push(serviceName);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Add infrastructure services (provides: mongo, redis, etc.)
|
|
280
|
+
if (config.provides) {
|
|
281
|
+
for (const [name] of Object.entries(config.provides)) {
|
|
282
|
+
dockerServices.push(name);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (dockerServices.length === 0) {
|
|
286
|
+
log(`No Docker services to start in ${repo.name}`, 'dim');
|
|
276
287
|
}
|
|
277
288
|
else {
|
|
278
|
-
log(
|
|
289
|
+
log(`Starting Docker Compose in ${repo.name} (${dockerServices.join(', ')})...`, 'info');
|
|
290
|
+
const composeResult = await sshExecStream(ip, keyPath, `cd ${repo.path} && docker compose up -d ${dockerServices.join(' ')}`, {
|
|
291
|
+
onStdout: (line) => log(line, 'dim'),
|
|
292
|
+
timeoutSecs: 600, // 10 minutes for Docker builds with npm/pnpm install
|
|
293
|
+
});
|
|
294
|
+
if (!composeResult.success) {
|
|
295
|
+
log(`Warning: Docker Compose failed in ${repo.name}`, 'error');
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
log(`✓ Docker services started in ${repo.name}`, 'success');
|
|
299
|
+
}
|
|
279
300
|
}
|
|
280
301
|
}
|
|
281
302
|
}
|
|
@@ -348,6 +369,24 @@ async function runSoftRebuild(options) {
|
|
|
348
369
|
log(`Warning: Database restore failed: ${error.message}`, 'error');
|
|
349
370
|
}
|
|
350
371
|
}
|
|
372
|
+
// Step 7.5: Update localhost URLs in .env files to genbox URLs
|
|
373
|
+
{
|
|
374
|
+
const genboxName = genbox.name;
|
|
375
|
+
const workspace = genbox.workspace || resolved.project.name;
|
|
376
|
+
const baseDomain = 'genbox.dev';
|
|
377
|
+
log('Updating localhost URLs in .env files...', 'info');
|
|
378
|
+
// Replace localhost:{port} with genbox URL for each app based on its configured port
|
|
379
|
+
for (const app of resolved.apps) {
|
|
380
|
+
const appConfig = config.apps[app.name];
|
|
381
|
+
const port = appConfig?.port;
|
|
382
|
+
if (port) {
|
|
383
|
+
const genboxAppUrl = `https://${genboxName}.${app.name}.${workspace}.${baseDomain}`;
|
|
384
|
+
await sshExec(ip, keyPath, `find /home/dev -name ".env" -type f -exec sed -i 's|http://localhost:${port}|${genboxAppUrl}|g' {} \\;`, 30);
|
|
385
|
+
log(` localhost:${port} → ${genboxAppUrl}`, 'dim');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
log(`✓ localhost URLs updated`, 'success');
|
|
389
|
+
}
|
|
351
390
|
// Step 8: Start PM2 services (only for apps with runner: pm2 or unspecified)
|
|
352
391
|
onStep?.('Starting application services...');
|
|
353
392
|
for (const app of resolved.apps) {
|
|
@@ -378,12 +417,11 @@ async function runSoftRebuild(options) {
|
|
|
378
417
|
}
|
|
379
418
|
}
|
|
380
419
|
else {
|
|
381
|
-
//
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run ${devCommand}" --name ${app.name}`, {
|
|
420
|
+
// Check for dev script in package.json first (preferred), then start script
|
|
421
|
+
const hasDevScript = await sshExec(ip, keyPath, `grep -q '"dev"' ${repoPath}/package.json 2>/dev/null && echo yes || echo no`, 10);
|
|
422
|
+
if (hasDevScript.output === 'yes') {
|
|
423
|
+
log(`Starting ${app.name} with PM2 (pnpm dev)...`, 'info');
|
|
424
|
+
const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run dev" --name ${app.name}`, {
|
|
387
425
|
onStdout: (line) => log(line, 'dim'),
|
|
388
426
|
timeoutSecs: 60,
|
|
389
427
|
});
|
|
@@ -392,11 +430,11 @@ async function runSoftRebuild(options) {
|
|
|
392
430
|
}
|
|
393
431
|
}
|
|
394
432
|
else {
|
|
395
|
-
//
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
398
|
-
log(`Starting ${app.name} with PM2 (pnpm
|
|
399
|
-
const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run
|
|
433
|
+
// Fall back to start script
|
|
434
|
+
const hasStartScript = await sshExec(ip, keyPath, `grep -q '"start"' ${repoPath}/package.json 2>/dev/null && echo yes || echo no`, 10);
|
|
435
|
+
if (hasStartScript.output === 'yes') {
|
|
436
|
+
log(`Starting ${app.name} with PM2 (pnpm start)...`, 'info');
|
|
437
|
+
const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run start" --name ${app.name}`, {
|
|
400
438
|
onStdout: (line) => log(line, 'dim'),
|
|
401
439
|
timeoutSecs: 60,
|
|
402
440
|
});
|
|
@@ -404,20 +442,6 @@ async function runSoftRebuild(options) {
|
|
|
404
442
|
log(`✓ Started ${app.name}`, 'success');
|
|
405
443
|
}
|
|
406
444
|
}
|
|
407
|
-
else {
|
|
408
|
-
// Fall back to start script
|
|
409
|
-
const hasStartScript = await sshExec(ip, keyPath, `grep -q '"start"' ${repoPath}/package.json 2>/dev/null && echo yes || echo no`, 10);
|
|
410
|
-
if (hasStartScript.output === 'yes') {
|
|
411
|
-
log(`Starting ${app.name} with PM2 (pnpm start)...`, 'info');
|
|
412
|
-
const pm2Result = await sshExecStream(ip, keyPath, `cd ${repoPath} && source ~/.nvm/nvm.sh && pm2 start "pnpm run start" --name ${app.name}`, {
|
|
413
|
-
onStdout: (line) => log(line, 'dim'),
|
|
414
|
-
timeoutSecs: 60,
|
|
415
|
-
});
|
|
416
|
-
if (pm2Result.success) {
|
|
417
|
-
log(`✓ Started ${app.name}`, 'success');
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
445
|
}
|
|
422
446
|
}
|
|
423
447
|
}
|
package/dist/db-utils.js
CHANGED
|
@@ -117,11 +117,20 @@ function getMongoDumpInstallInstructions() {
|
|
|
117
117
|
async function runLocalMongoDump(sourceUrl, options = {}) {
|
|
118
118
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'genbox-dbdump-'));
|
|
119
119
|
const dumpPath = path.join(tempDir, 'dump.gz');
|
|
120
|
+
// Add timeout parameters to URI if not already present
|
|
121
|
+
// This prevents connection drops on large databases
|
|
122
|
+
let uriWithTimeout = sourceUrl;
|
|
123
|
+
const hasTimeout = sourceUrl.includes('socketTimeoutMS') || sourceUrl.includes('connectTimeoutMS');
|
|
124
|
+
if (!hasTimeout) {
|
|
125
|
+
const separator = sourceUrl.includes('?') ? '&' : '?';
|
|
126
|
+
uriWithTimeout = `${sourceUrl}${separator}socketTimeoutMS=300000&connectTimeoutMS=60000`;
|
|
127
|
+
}
|
|
120
128
|
return new Promise((resolve) => {
|
|
121
129
|
const args = [
|
|
122
|
-
`--uri=${
|
|
130
|
+
`--uri=${uriWithTimeout}`,
|
|
123
131
|
`--archive=${dumpPath}`,
|
|
124
132
|
'--gzip',
|
|
133
|
+
'--numParallelCollections=1', // Dump one collection at a time - more reliable for large DBs
|
|
125
134
|
];
|
|
126
135
|
// Add collection filters
|
|
127
136
|
if (options.collections && options.collections.length > 0) {
|
package/dist/profile-resolver.js
CHANGED
|
@@ -539,9 +539,13 @@ class ProfileResolver {
|
|
|
539
539
|
const apiDep = app.dependencies['api'];
|
|
540
540
|
if (apiDep) {
|
|
541
541
|
if (apiDep.mode === 'local') {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
542
|
+
// Get API port from config instead of hardcoding
|
|
543
|
+
const apiAppConfig = config.apps?.['api'];
|
|
544
|
+
const apiPort = (apiAppConfig?.port && typeof apiAppConfig.port === 'number') ? apiAppConfig.port : 3050;
|
|
545
|
+
const localApiUrl = `http://localhost:${apiPort}`;
|
|
546
|
+
env['API_URL'] = localApiUrl;
|
|
547
|
+
env['VITE_API_URL'] = localApiUrl;
|
|
548
|
+
env['NEXT_PUBLIC_API_URL'] = localApiUrl;
|
|
545
549
|
}
|
|
546
550
|
else if (apiDep.url) {
|
|
547
551
|
env['API_URL'] = apiDep.url;
|
|
@@ -555,7 +559,10 @@ class ProfileResolver {
|
|
|
555
559
|
if (hasBackendApps) {
|
|
556
560
|
// Add database URL
|
|
557
561
|
if (database.mode === 'local') {
|
|
558
|
-
|
|
562
|
+
// Get MongoDB port from provides config instead of hardcoding
|
|
563
|
+
const mongoConfig = config.provides?.['mongodb'];
|
|
564
|
+
const mongoPort = mongoConfig?.port || 27017;
|
|
565
|
+
env['MONGODB_URI'] = `mongodb://localhost:${mongoPort}/${config.project.name}`;
|
|
559
566
|
}
|
|
560
567
|
else if (database.url) {
|
|
561
568
|
env['MONGODB_URI'] = database.url;
|