nstantpage-agent 0.8.12 → 0.8.13
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/start.js +79 -62
- package/dist/tunnel.d.ts +1 -0
- package/dist/tunnel.js +4 -4
- package/package.json +1 -1
package/dist/commands/start.js
CHANGED
|
@@ -579,11 +579,13 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
579
579
|
existing.tunnel.disconnect();
|
|
580
580
|
await existing.localServer.stop();
|
|
581
581
|
activeProjects.delete(pid);
|
|
582
|
-
// Wipe the project directory
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
582
|
+
// Wipe the project directory (only for non-LocalRepo)
|
|
583
|
+
if (!opts?.localFolderPath) {
|
|
584
|
+
const projectDir = resolveProjectDir('.', pid);
|
|
585
|
+
if (fs.existsSync(projectDir)) {
|
|
586
|
+
console.log(chalk.gray(` Wiping project directory: ${projectDir}`));
|
|
587
|
+
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
588
|
+
}
|
|
587
589
|
}
|
|
588
590
|
}
|
|
589
591
|
else if (activeProjects.has(pid)) {
|
|
@@ -592,6 +594,7 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
592
594
|
}
|
|
593
595
|
const result = await startAdditionalProject(pid, {
|
|
594
596
|
token, backendUrl, gatewayUrl: options.gateway, deviceId, noDev: options.noDev,
|
|
597
|
+
localFolderPath: opts?.localFolderPath,
|
|
595
598
|
onProgress: (phase, message) => {
|
|
596
599
|
standbyTunnel.sendSetupProgress(pid, phase, message);
|
|
597
600
|
},
|
|
@@ -678,6 +681,7 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
678
681
|
}
|
|
679
682
|
const result = await startAdditionalProject(projectId, {
|
|
680
683
|
token, backendUrl, gatewayUrl: options.gateway, deviceId, noDev: options.noDev,
|
|
684
|
+
localFolderPath: opts?.localFolderPath,
|
|
681
685
|
onProgress: (phase, message) => {
|
|
682
686
|
standbyTunnel.sendSetupProgress(projectId, phase, message);
|
|
683
687
|
},
|
|
@@ -736,29 +740,37 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
736
740
|
const progress = opts.onProgress || (() => { });
|
|
737
741
|
const timings = {};
|
|
738
742
|
const t0 = Date.now();
|
|
739
|
-
|
|
743
|
+
const isLocalRepo = !!opts.localFolderPath;
|
|
744
|
+
console.log(chalk.blue(`\n 📦 Starting project ${projectId}${isLocalRepo ? ' (LocalRepo)' : ''}...`));
|
|
740
745
|
try {
|
|
741
746
|
const allocated = allocatePortsForProject(projectId);
|
|
742
|
-
const projectDir = resolveProjectDir('.', projectId);
|
|
747
|
+
const projectDir = isLocalRepo ? opts.localFolderPath : resolveProjectDir('.', projectId);
|
|
743
748
|
if (!fs.existsSync(projectDir))
|
|
744
749
|
fs.mkdirSync(projectDir, { recursive: true });
|
|
745
750
|
// Ensure ports are clear for this project before starting
|
|
746
751
|
cleanupPreviousAgent(projectId, allocated.apiPort, allocated.devPort);
|
|
747
752
|
await new Promise(r => setTimeout(r, 50));
|
|
748
753
|
// ── Phase 1: API server + file fetch + tunnel connect (all parallel) ──
|
|
749
|
-
|
|
750
|
-
|
|
754
|
+
if (!isLocalRepo) {
|
|
755
|
+
progress('fetching-files', 'Fetching project files...');
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
progress('starting-server', 'Starting local server...');
|
|
759
|
+
}
|
|
760
|
+
// Provision database if PostgreSQL is available (skip for LocalRepo)
|
|
751
761
|
let databaseUrl = null;
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
762
|
+
if (!isLocalRepo) {
|
|
763
|
+
try {
|
|
764
|
+
const hasPg = await probeLocalPostgres();
|
|
765
|
+
if (hasPg) {
|
|
766
|
+
databaseUrl = await ensureLocalProjectDb(projectId);
|
|
767
|
+
if (databaseUrl) {
|
|
768
|
+
console.log(chalk.green(` ✓ Database ready: project_${projectId}`));
|
|
769
|
+
}
|
|
758
770
|
}
|
|
759
771
|
}
|
|
772
|
+
catch { }
|
|
760
773
|
}
|
|
761
|
-
catch { }
|
|
762
774
|
const serverEnv = {};
|
|
763
775
|
if (databaseUrl)
|
|
764
776
|
serverEnv['DATABASE_URL'] = databaseUrl;
|
|
@@ -799,17 +811,20 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
799
811
|
tunnel.startBackgroundReconnect();
|
|
800
812
|
}
|
|
801
813
|
})();
|
|
814
|
+
// Fetch project files from backend (skip for LocalRepo — files are on disk)
|
|
802
815
|
const fileStart = Date.now();
|
|
803
816
|
let fetchedVersionId;
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
817
|
+
if (!isLocalRepo) {
|
|
818
|
+
try {
|
|
819
|
+
const { versionId } = await fetchProjectFiles(opts.backendUrl, projectId, projectDir, opts.token);
|
|
820
|
+
fetchedVersionId = versionId;
|
|
821
|
+
timings['fetch-files'] = Date.now() - fileStart;
|
|
822
|
+
progress('fetching-files', `Files downloaded (${timings['fetch-files']}ms)`);
|
|
823
|
+
}
|
|
824
|
+
catch (err) {
|
|
825
|
+
console.log(chalk.yellow(` ⚠ Could not fetch files: ${err.message}`));
|
|
826
|
+
progress('fetching-files', `Warning: ${err.message}`);
|
|
827
|
+
}
|
|
813
828
|
}
|
|
814
829
|
// Write DATABASE_URL to .env AFTER file fetch (so it doesn't get overwritten)
|
|
815
830
|
if (databaseUrl) {
|
|
@@ -822,49 +837,51 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
822
837
|
if (fetchedVersionId) {
|
|
823
838
|
localServer.markSynced(fetchedVersionId);
|
|
824
839
|
}
|
|
825
|
-
// ── Phase 2: Install deps (if needed)
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
await installer.ensureDependencies();
|
|
834
|
-
timings['install'] = Date.now() - installStart;
|
|
835
|
-
console.log(chalk.green(` ✓ Dependencies installed (${timings['install']}ms)`));
|
|
836
|
-
progress('installing-deps', `Dependencies installed (${timings['install']}ms)`);
|
|
837
|
-
}
|
|
838
|
-
catch (err) {
|
|
839
|
-
timings['install'] = Date.now() - installStart;
|
|
840
|
-
console.log(chalk.red(` ✗ Install failed: ${err.message}`));
|
|
841
|
-
console.log(chalk.yellow(` ⚠ Dev server may fail — retrying install on first request`));
|
|
842
|
-
progress('installing-deps', `Install failed: ${err.message}`);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
else {
|
|
846
|
-
progress('installing-deps', 'Dependencies already installed (cached)');
|
|
847
|
-
}
|
|
848
|
-
// ── Phase 3: Start dev server ────────────────────────────────────
|
|
849
|
-
if (!opts.noDev) {
|
|
850
|
-
if (installer.areDependenciesInstalled()) {
|
|
851
|
-
progress('starting-dev', 'Starting dev server...');
|
|
840
|
+
// ── Phase 2: Install deps (if needed) — skip for LocalRepo ──
|
|
841
|
+
if (!isLocalRepo) {
|
|
842
|
+
const installer = new PackageInstaller({ projectDir });
|
|
843
|
+
const needsInstall = !installer.areDependenciesInstalled() && fs.existsSync(path.join(projectDir, 'package.json'));
|
|
844
|
+
if (needsInstall) {
|
|
845
|
+
const installStart = Date.now();
|
|
846
|
+
console.log(chalk.gray(` Installing dependencies...`));
|
|
847
|
+
progress('installing-deps', 'Installing npm dependencies...');
|
|
852
848
|
try {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
timings['
|
|
856
|
-
|
|
857
|
-
progress('starting-dev', `Dev server on port ${allocated.devPort}`);
|
|
849
|
+
await installer.ensureDependencies();
|
|
850
|
+
timings['install'] = Date.now() - installStart;
|
|
851
|
+
console.log(chalk.green(` ✓ Dependencies installed (${timings['install']}ms)`));
|
|
852
|
+
progress('installing-deps', `Dependencies installed (${timings['install']}ms)`);
|
|
858
853
|
}
|
|
859
854
|
catch (err) {
|
|
860
|
-
|
|
861
|
-
|
|
855
|
+
timings['install'] = Date.now() - installStart;
|
|
856
|
+
console.log(chalk.red(` ✗ Install failed: ${err.message}`));
|
|
857
|
+
console.log(chalk.yellow(` ⚠ Dev server may fail — retrying install on first request`));
|
|
858
|
+
progress('installing-deps', `Install failed: ${err.message}`);
|
|
862
859
|
}
|
|
863
860
|
}
|
|
864
861
|
else {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
862
|
+
progress('installing-deps', 'Dependencies already installed (cached)');
|
|
863
|
+
}
|
|
864
|
+
// ── Phase 3: Start dev server — skip for LocalRepo ──
|
|
865
|
+
if (!opts.noDev) {
|
|
866
|
+
if (installer.areDependenciesInstalled()) {
|
|
867
|
+
progress('starting-dev', 'Starting dev server...');
|
|
868
|
+
try {
|
|
869
|
+
const devStart = Date.now();
|
|
870
|
+
await localServer.getDevServer().start();
|
|
871
|
+
timings['dev-server'] = Date.now() - devStart;
|
|
872
|
+
console.log(chalk.green(` ✓ Dev server on port ${allocated.devPort} (${timings['dev-server']}ms)`));
|
|
873
|
+
progress('starting-dev', `Dev server on port ${allocated.devPort}`);
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
console.log(chalk.yellow(` ⚠ Dev server: ${err.message}`));
|
|
877
|
+
progress('starting-dev', `Warning: ${err.message}`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
console.log(chalk.yellow(` ⚠ Skipping dev server — dependencies not installed`));
|
|
882
|
+
console.log(chalk.gray(` Dev server will start when browser opens the project`));
|
|
883
|
+
progress('starting-dev', 'Skipped — dependencies not installed');
|
|
884
|
+
}
|
|
868
885
|
}
|
|
869
886
|
}
|
|
870
887
|
// Ensure tunnel is connected before declaring ready
|
package/dist/tunnel.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface TunnelClientOptions {
|
|
|
27
27
|
/** Callback when gateway requests starting a new project on this device */
|
|
28
28
|
onStartProject?: (projectId: string, options?: {
|
|
29
29
|
clean?: boolean;
|
|
30
|
+
localFolderPath?: string;
|
|
30
31
|
}) => Promise<void>;
|
|
31
32
|
/** Callback for setup progress — lets the standby tunnel relay phases to gateway */
|
|
32
33
|
onSetupProgress?: (projectId: string, phase: string, message: string) => void;
|
package/dist/tunnel.js
CHANGED
|
@@ -403,8 +403,8 @@ export class TunnelClient {
|
|
|
403
403
|
* Handle start-project: gateway wants this agent to start serving a new project.
|
|
404
404
|
* Called when user clicks "Connect" in the web editor's Cloud panel.
|
|
405
405
|
*/
|
|
406
|
-
async handleStartProject(projectId, clean) {
|
|
407
|
-
console.log(` [Tunnel] Received start-project command for ${projectId}${clean ? ' (clean)' : ''}`);
|
|
406
|
+
async handleStartProject(projectId, clean, localFolderPath) {
|
|
407
|
+
console.log(` [Tunnel] Received start-project command for ${projectId}${clean ? ' (clean)' : ''}${localFolderPath ? ` (local: ${localFolderPath})` : ''}`);
|
|
408
408
|
if (!projectId) {
|
|
409
409
|
this.send({ type: 'start-project-result', success: false, error: 'Missing projectId' });
|
|
410
410
|
return;
|
|
@@ -413,7 +413,7 @@ export class TunnelClient {
|
|
|
413
413
|
try {
|
|
414
414
|
// Send initial progress
|
|
415
415
|
this.sendSetupProgress(projectId, 'starting', 'Starting project setup...');
|
|
416
|
-
await this.options.onStartProject(projectId, clean ? { clean: true } :
|
|
416
|
+
await this.options.onStartProject(projectId, { ...(clean ? { clean: true } : {}), ...(localFolderPath ? { localFolderPath } : {}) });
|
|
417
417
|
this.sendSetupProgress(projectId, 'ready', 'Project is live!');
|
|
418
418
|
this.send({ type: 'start-project-result', projectId, success: true });
|
|
419
419
|
}
|
|
@@ -474,7 +474,7 @@ export class TunnelClient {
|
|
|
474
474
|
this.handleWsClose(msg.wsId);
|
|
475
475
|
break;
|
|
476
476
|
case 'start-project':
|
|
477
|
-
this.handleStartProject(msg.projectId, msg.clean);
|
|
477
|
+
this.handleStartProject(msg.projectId, msg.clean, msg.localFolderPath);
|
|
478
478
|
break;
|
|
479
479
|
case 'force-disconnect':
|
|
480
480
|
console.log(' [Tunnel] Received force-disconnect — will not reconnect');
|
package/package.json
CHANGED