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.
@@ -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
- const projectDir = resolveProjectDir('.', pid);
584
- if (fs.existsSync(projectDir)) {
585
- console.log(chalk.gray(` Wiping project directory: ${projectDir}`));
586
- fs.rmSync(projectDir, { recursive: true, force: true });
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
- console.log(chalk.blue(`\n 📦 Starting project ${projectId}...`));
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
- progress('fetching-files', 'Fetching project files...');
750
- // Provision database if PostgreSQL is available
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
- try {
753
- const hasPg = await probeLocalPostgres();
754
- if (hasPg) {
755
- databaseUrl = await ensureLocalProjectDb(projectId);
756
- if (databaseUrl) {
757
- console.log(chalk.green(` ✓ Database ready: project_${projectId}`));
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
- try {
805
- const { versionId } = await fetchProjectFiles(opts.backendUrl, projectId, projectDir, opts.token);
806
- fetchedVersionId = versionId;
807
- timings['fetch-files'] = Date.now() - fileStart;
808
- progress('fetching-files', `Files downloaded (${timings['fetch-files']}ms)`);
809
- }
810
- catch (err) {
811
- console.log(chalk.yellow(` ⚠ Could not fetch files: ${err.message}`));
812
- progress('fetching-files', `Warning: ${err.message}`);
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
- const installer = new PackageInstaller({ projectDir });
827
- const needsInstall = !installer.areDependenciesInstalled() && fs.existsSync(path.join(projectDir, 'package.json'));
828
- if (needsInstall) {
829
- const installStart = Date.now();
830
- console.log(chalk.gray(` Installing dependencies...`));
831
- progress('installing-deps', 'Installing npm dependencies...');
832
- try {
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
- const devStart = Date.now();
854
- await localServer.getDevServer().start();
855
- timings['dev-server'] = Date.now() - devStart;
856
- console.log(chalk.green(` Dev server on port ${allocated.devPort} (${timings['dev-server']}ms)`));
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
- console.log(chalk.yellow(` ⚠ Dev server: ${err.message}`));
861
- progress('starting-dev', `Warning: ${err.message}`);
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
- console.log(chalk.yellow(` ⚠ Skipping dev server — dependencies not installed`));
866
- console.log(chalk.gray(` Dev server will start when browser opens the project`));
867
- progress('starting-dev', 'Skippeddependencies not installed');
862
+ progress('installing-deps', 'Dependencies already installed (cached)');
863
+ }
864
+ // ── Phase 3: Start dev serverskip 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 } : undefined);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstantpage-agent",
3
- "version": "0.8.12",
3
+ "version": "0.8.13",
4
4
  "description": "Local development agent for nstantpage.com — run your projects locally, preview in the cloud. Replaces cloud containers for faster builds.",
5
5
  "type": "module",
6
6
  "bin": {