genbox 1.0.82 → 1.0.84
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/create.js +120 -35
- package/package.json +1 -1
package/dist/commands/create.js
CHANGED
|
@@ -406,6 +406,8 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
406
406
|
let snapshotId;
|
|
407
407
|
let snapshotS3Key;
|
|
408
408
|
let localDumpPath;
|
|
409
|
+
let localSetupStartTime;
|
|
410
|
+
let localSetupDuration; // in seconds
|
|
409
411
|
const projectCache = loadProjectCache(process.cwd());
|
|
410
412
|
const needsLocalDbCopy = resolved.database.mode === 'copy' &&
|
|
411
413
|
resolved.database.url &&
|
|
@@ -500,6 +502,8 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
500
502
|
console.log(chalk_1.default.dim(` Source: ${resolved.database.source}`));
|
|
501
503
|
}
|
|
502
504
|
console.log(chalk_1.default.dim(` URL: ${dbUrl.replace(/\/\/[^:]+:[^@]+@/, '//***:***@')}`));
|
|
505
|
+
// Start timing for local setup (dump + upload)
|
|
506
|
+
localSetupStartTime = Date.now();
|
|
503
507
|
const dumpSpinner = (0, ora_1.default)('Creating database dump...').start();
|
|
504
508
|
const dumpResult = await (0, db_utils_1.runLocalMongoDump)(dbUrl, {
|
|
505
509
|
onProgress: (msg) => dumpSpinner.text = msg,
|
|
@@ -528,6 +532,10 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
528
532
|
uploadSpinner.succeed(chalk_1.default.green('Database snapshot uploaded'));
|
|
529
533
|
snapshotId = snapshotResult.snapshotId;
|
|
530
534
|
snapshotS3Key = snapshotResult.s3Key;
|
|
535
|
+
// Calculate local setup duration (dump + upload time)
|
|
536
|
+
if (localSetupStartTime) {
|
|
537
|
+
localSetupDuration = Math.round((Date.now() - localSetupStartTime) / 1000);
|
|
538
|
+
}
|
|
531
539
|
// Cleanup local dump since it's now in S3
|
|
532
540
|
if (localDumpPath)
|
|
533
541
|
(0, db_utils_1.cleanupDump)(localDumpPath);
|
|
@@ -570,6 +578,10 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
570
578
|
};
|
|
571
579
|
}
|
|
572
580
|
const payload = buildPayload(payloadResolved, config, publicKey, privateKeyContent, configLoader);
|
|
581
|
+
// Add local setup duration if we did a local dump+upload
|
|
582
|
+
if (localSetupDuration) {
|
|
583
|
+
payload.localSetupDuration = localSetupDuration;
|
|
584
|
+
}
|
|
573
585
|
// Create genbox
|
|
574
586
|
const spinner = (0, ora_1.default)(`Creating Genbox '${name}'...`).start();
|
|
575
587
|
try {
|
|
@@ -716,7 +728,9 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
|
|
|
716
728
|
const files = [];
|
|
717
729
|
// Track env files to move in setup script (staging approach to avoid blocking git clone)
|
|
718
730
|
const envFilesToMove = [];
|
|
719
|
-
// Send .env.genbox content to server for
|
|
731
|
+
// Send .env.genbox content to server for processing
|
|
732
|
+
// OPTIMIZATION: Instead of duplicating GLOBAL section for each app,
|
|
733
|
+
// send ONE .env.genbox file and let server extract app-specific content
|
|
720
734
|
const envGenboxPath = path.join(process.cwd(), '.env.genbox');
|
|
721
735
|
if (fs.existsSync(envGenboxPath)) {
|
|
722
736
|
const rawEnvContent = fs.readFileSync(envGenboxPath, 'utf-8');
|
|
@@ -739,42 +753,77 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
|
|
|
739
753
|
if (connectTo && Object.keys(serviceUrlMap).length > 0) {
|
|
740
754
|
console.log(chalk_1.default.dim(` Using ${connectTo} URLs for variable expansion`));
|
|
741
755
|
}
|
|
742
|
-
//
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
756
|
+
// For projects with many apps, send ONE processed .env file to avoid duplicating GLOBAL
|
|
757
|
+
// This significantly reduces cloud-init size (Hetzner has 32KB limit)
|
|
758
|
+
if (resolved.apps.length > 3) {
|
|
759
|
+
// Send single .env.genbox with expansions applied, let server split into app files
|
|
760
|
+
let expandedEnvContent = rawEnvContent;
|
|
761
|
+
for (const [varName, value] of Object.entries(serviceUrlMap)) {
|
|
762
|
+
const pattern = new RegExp(`\\$\\{${varName}\\}`, 'g');
|
|
763
|
+
expandedEnvContent = expandedEnvContent.replace(pattern, value);
|
|
764
|
+
}
|
|
765
|
+
files.push({
|
|
766
|
+
path: '/home/dev/.env.genbox',
|
|
767
|
+
content: expandedEnvContent,
|
|
768
|
+
permissions: '0644',
|
|
769
|
+
});
|
|
770
|
+
// Track which apps need .env files (server will process)
|
|
771
|
+
for (const app of resolved.apps) {
|
|
772
|
+
const appPath = config.apps[app.name]?.path || app.name;
|
|
773
|
+
const repoPath = resolved.repos.find(r => r.name === app.name)?.path ||
|
|
774
|
+
(resolved.repos[0]?.path ? `${resolved.repos[0].path}/${appPath}` : `/home/dev/${config.project.name}/${appPath}`);
|
|
775
|
+
const servicesSections = Array.from(sections.keys()).filter(s => s.startsWith(`${app.name}/`));
|
|
776
|
+
if (servicesSections.length > 0) {
|
|
777
|
+
for (const serviceSectionName of servicesSections) {
|
|
778
|
+
const serviceName = serviceSectionName.split('/')[1];
|
|
779
|
+
envFilesToMove.push({
|
|
780
|
+
stagingName: serviceSectionName, // e.g., "api/gateway" - server will parse
|
|
781
|
+
targetPath: `${repoPath}/apps/${serviceName}/.env`,
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
envFilesToMove.push({
|
|
787
|
+
stagingName: app.name,
|
|
788
|
+
targetPath: `${repoPath}/.env`,
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
// For small projects, use the original per-app approach (simpler)
|
|
795
|
+
for (const app of resolved.apps) {
|
|
796
|
+
const appPath = config.apps[app.name]?.path || app.name;
|
|
797
|
+
const repoPath = resolved.repos.find(r => r.name === app.name)?.path ||
|
|
798
|
+
(resolved.repos[0]?.path ? `${resolved.repos[0].path}/${appPath}` : `/home/dev/${config.project.name}/${appPath}`);
|
|
799
|
+
const servicesSections = Array.from(sections.keys()).filter(s => s.startsWith(`${app.name}/`));
|
|
800
|
+
if (servicesSections.length > 0) {
|
|
801
|
+
for (const serviceSectionName of servicesSections) {
|
|
802
|
+
const serviceName = serviceSectionName.split('/')[1];
|
|
803
|
+
const serviceEnvContent = (0, utils_1.buildAppEnvContent)(sections, serviceSectionName, serviceUrlMap);
|
|
804
|
+
const stagingName = `${app.name}-${serviceName}.env`;
|
|
805
|
+
const targetPath = `${repoPath}/apps/${serviceName}/.env`;
|
|
806
|
+
files.push({
|
|
807
|
+
path: `/home/dev/.env-staging/${stagingName}`,
|
|
808
|
+
content: serviceEnvContent,
|
|
809
|
+
permissions: '0644',
|
|
810
|
+
});
|
|
811
|
+
envFilesToMove.push({ stagingName, targetPath });
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
const appEnvContent = (0, utils_1.buildAppEnvContent)(sections, app.name, serviceUrlMap);
|
|
757
816
|
files.push({
|
|
758
|
-
path: `/home/dev/.env-staging/${
|
|
759
|
-
content:
|
|
817
|
+
path: `/home/dev/.env-staging/${app.name}.env`,
|
|
818
|
+
content: appEnvContent,
|
|
760
819
|
permissions: '0644',
|
|
761
820
|
});
|
|
762
|
-
envFilesToMove.push({
|
|
821
|
+
envFilesToMove.push({
|
|
822
|
+
stagingName: `${app.name}.env`,
|
|
823
|
+
targetPath: `${repoPath}/.env`,
|
|
824
|
+
});
|
|
763
825
|
}
|
|
764
826
|
}
|
|
765
|
-
else {
|
|
766
|
-
// Regular app - build app-specific env content (GLOBAL + app section)
|
|
767
|
-
const appEnvContent = (0, utils_1.buildAppEnvContent)(sections, app.name, serviceUrlMap);
|
|
768
|
-
files.push({
|
|
769
|
-
path: `/home/dev/.env-staging/${app.name}.env`,
|
|
770
|
-
content: appEnvContent,
|
|
771
|
-
permissions: '0644',
|
|
772
|
-
});
|
|
773
|
-
envFilesToMove.push({
|
|
774
|
-
stagingName: `${app.name}.env`,
|
|
775
|
-
targetPath: `${repoPath}/.env`,
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
827
|
}
|
|
779
828
|
}
|
|
780
829
|
// Add setup script if generated
|
|
@@ -858,9 +907,45 @@ function generateSetupScript(resolved, config, envFilesToMove = []) {
|
|
|
858
907
|
'set -e',
|
|
859
908
|
'',
|
|
860
909
|
];
|
|
861
|
-
//
|
|
862
|
-
//
|
|
863
|
-
|
|
910
|
+
// Check if we're using the optimized single-file approach (for projects with many apps)
|
|
911
|
+
// or the legacy per-app staging approach
|
|
912
|
+
const useOptimizedEnv = resolved.apps.length > 3;
|
|
913
|
+
if (useOptimizedEnv && envFilesToMove.length > 0) {
|
|
914
|
+
// OPTIMIZED: Parse single .env.genbox and create app-specific .env files
|
|
915
|
+
lines.push('# Process .env.genbox and create app-specific .env files');
|
|
916
|
+
lines.push('if [ -f "/home/dev/.env.genbox" ]; then');
|
|
917
|
+
lines.push(' echo "Processing .env.genbox for app-specific .env files..."');
|
|
918
|
+
lines.push('');
|
|
919
|
+
lines.push(' # Function to extract section content');
|
|
920
|
+
lines.push(' extract_section() {');
|
|
921
|
+
lines.push(' local section="$1"');
|
|
922
|
+
lines.push(' local file="$2"');
|
|
923
|
+
lines.push(' awk -v section="$section" \'');
|
|
924
|
+
lines.push(' BEGIN { in_global=0; in_section=0; }');
|
|
925
|
+
lines.push(' /^# === GLOBAL ===/ { in_global=1; next }');
|
|
926
|
+
lines.push(' /^# === [^=]+ ===/ {');
|
|
927
|
+
lines.push(' in_global=0;');
|
|
928
|
+
lines.push(' if ($0 ~ "# === "section" ===") { in_section=1 }');
|
|
929
|
+
lines.push(' else { in_section=0 }');
|
|
930
|
+
lines.push(' next');
|
|
931
|
+
lines.push(' }');
|
|
932
|
+
lines.push(' in_global || in_section { print }');
|
|
933
|
+
lines.push(' \' "$file" | grep -v "^$" | head -n -1');
|
|
934
|
+
lines.push(' }');
|
|
935
|
+
lines.push('');
|
|
936
|
+
for (const { stagingName, targetPath } of envFilesToMove) {
|
|
937
|
+
lines.push(` # Create .env for ${stagingName}`);
|
|
938
|
+
lines.push(` mkdir -p "$(dirname "${targetPath}")"`);
|
|
939
|
+
lines.push(` extract_section "${stagingName}" /home/dev/.env.genbox > "${targetPath}"`);
|
|
940
|
+
lines.push(` echo " Created ${targetPath}"`);
|
|
941
|
+
}
|
|
942
|
+
lines.push('');
|
|
943
|
+
lines.push(' rm -f /home/dev/.env.genbox');
|
|
944
|
+
lines.push('fi');
|
|
945
|
+
lines.push('');
|
|
946
|
+
}
|
|
947
|
+
else if (envFilesToMove.length > 0) {
|
|
948
|
+
// LEGACY: Move pre-staged .env files
|
|
864
949
|
lines.push('# Move .env files from staging to app directories');
|
|
865
950
|
for (const { stagingName, targetPath } of envFilesToMove) {
|
|
866
951
|
lines.push(`if [ -f "/home/dev/.env-staging/${stagingName}" ]; then`);
|