nstantpage-agent 0.8.13 → 0.8.15

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.
@@ -572,15 +572,16 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
572
572
  devPort: 0,
573
573
  onStartProject: async (pid, opts) => {
574
574
  const isClean = opts?.clean === true;
575
- // If clean reset requested and project is already running, stop it first
576
- if (isClean && activeProjects.has(pid)) {
577
- console.log(chalk.yellow(` Stopping existing project ${pid} for clean reset...`));
575
+ const isLocalRepo = !!opts?.localFolderPath;
576
+ // If clean reset or LocalRepo re-start requested and project is already running, stop it first
577
+ if ((isClean || isLocalRepo) && activeProjects.has(pid)) {
578
+ console.log(chalk.yellow(` Stopping existing project ${pid} for ${isClean ? 'clean reset' : 'LocalRepo restart'}...`));
578
579
  const existing = activeProjects.get(pid);
579
580
  existing.tunnel.disconnect();
580
581
  await existing.localServer.stop();
581
582
  activeProjects.delete(pid);
582
- // Wipe the project directory (only for non-LocalRepo)
583
- if (!opts?.localFolderPath) {
583
+ // Wipe the project directory (only for clean non-LocalRepo)
584
+ if (isClean && !isLocalRepo) {
584
585
  const projectDir = resolveProjectDir('.', pid);
585
586
  if (fs.existsSync(projectDir)) {
586
587
  console.log(chalk.gray(` Wiping project directory: ${projectDir}`));
@@ -775,7 +776,7 @@ async function startAdditionalProject(projectId, opts) {
775
776
  if (databaseUrl)
776
777
  serverEnv['DATABASE_URL'] = databaseUrl;
777
778
  // Note: tunnel is created after localServer but before start(),
778
- // so the onSyncDirty callback captures it via closure (late-binding).
779
+ // so the onSyncDirty/onSetDevPort callbacks capture it via closure (late-binding).
779
780
  let tunnel;
780
781
  const localServer = new LocalServer({
781
782
  projectDir, projectId,
@@ -787,6 +788,11 @@ async function startAdditionalProject(projectId, opts) {
787
788
  tunnel.sendSyncDirty(pid);
788
789
  }
789
790
  },
791
+ onSetDevPort: (port) => {
792
+ if (tunnel) {
793
+ tunnel.setDevPort(port);
794
+ }
795
+ },
790
796
  });
791
797
  tunnel = new TunnelClient({
792
798
  gatewayUrl: opts.gatewayUrl,
@@ -62,6 +62,8 @@ export interface LocalServerOptions {
62
62
  backendUrl?: string;
63
63
  /** Called when file watcher detects changes — should send sync-dirty via tunnel */
64
64
  onSyncDirty?: (projectId: string) => void;
65
+ /** Called when dev port is updated via /live/set-dev-port */
66
+ onSetDevPort?: (port: number) => void;
65
67
  }
66
68
  export declare class LocalServer {
67
69
  private server;
@@ -127,6 +129,7 @@ export declare class LocalServer {
127
129
  private handleTree;
128
130
  private handleFileContent;
129
131
  private handleSaveFile;
132
+ private handleSetDevPort;
130
133
  private handleHealth;
131
134
  /**
132
135
  * Get a pg Pool connected to this project's local database.
@@ -404,6 +404,7 @@ export class LocalServer {
404
404
  '/live/tree': this.handleTree,
405
405
  '/live/file-content': this.handleFileContent,
406
406
  '/live/save-file': this.handleSaveFile,
407
+ '/live/set-dev-port': this.handleSetDevPort,
407
408
  '/health': this.handleHealth,
408
409
  };
409
410
  if (handlers[path])
@@ -1225,6 +1226,23 @@ export class LocalServer {
1225
1226
  this.json(res, { error: error.message }, 500);
1226
1227
  }
1227
1228
  }
1229
+ // ─── /live/set-dev-port ─────────────────────────────────────
1230
+ async handleSetDevPort(_req, res, body) {
1231
+ try {
1232
+ const { port } = JSON.parse(body);
1233
+ if (!port || typeof port !== 'number' || port < 1 || port > 65535) {
1234
+ this.json(res, { error: 'Invalid port number' }, 400);
1235
+ return;
1236
+ }
1237
+ if (this.options.onSetDevPort) {
1238
+ this.options.onSetDevPort(port);
1239
+ }
1240
+ this.json(res, { success: true, port });
1241
+ }
1242
+ catch (error) {
1243
+ this.json(res, { error: error.message }, 500);
1244
+ }
1245
+ }
1228
1246
  // ─── /health ─────────────────────────────────────────────────
1229
1247
  async handleHealth(_req, res) {
1230
1248
  this.json(res, {
package/dist/tunnel.d.ts CHANGED
@@ -48,7 +48,13 @@ export declare class TunnelClient {
48
48
  private wsChannels;
49
49
  /** Listeners for status changes (used by tray app) */
50
50
  private statusListeners;
51
+ /** Override dev port (set dynamically for LocalRepo when user starts dev server) */
52
+ private _devPortOverride;
51
53
  constructor(options: TunnelClientOptions);
54
+ /** Get the effective dev server port (override or default) */
55
+ get devPort(): number;
56
+ /** Dynamically set dev port (e.g., when user starts dev server on a specific port) */
57
+ setDevPort(port: number): void;
52
58
  /**
53
59
  * Handle OS sleep/wake events.
54
60
  * When the machine wakes from sleep (or screen unlock), immediately attempt
package/dist/tunnel.js CHANGED
@@ -38,10 +38,21 @@ export class TunnelClient {
38
38
  wsChannels = new Map();
39
39
  /** Listeners for status changes (used by tray app) */
40
40
  statusListeners = new Set();
41
+ /** Override dev port (set dynamically for LocalRepo when user starts dev server) */
42
+ _devPortOverride = null;
41
43
  constructor(options) {
42
44
  this.options = options;
43
45
  this.setupSleepWakeHandlers();
44
46
  }
47
+ /** Get the effective dev server port (override or default) */
48
+ get devPort() {
49
+ return this._devPortOverride ?? this.options.devPort;
50
+ }
51
+ /** Dynamically set dev port (e.g., when user starts dev server on a specific port) */
52
+ setDevPort(port) {
53
+ console.log(` [Tunnel] Dev port set to ${port} (was ${this._devPortOverride ?? this.options.devPort})`);
54
+ this._devPortOverride = port;
55
+ }
45
56
  /**
46
57
  * Handle OS sleep/wake events.
47
58
  * When the machine wakes from sleep (or screen unlock), immediately attempt
@@ -350,7 +361,7 @@ export class TunnelClient {
350
361
  * This enables Vite HMR to work through the cloud preview URL.
351
362
  */
352
363
  handleWsOpenDevServer(wsId, url, protocol) {
353
- const devPort = this.options.devPort;
364
+ const devPort = this.devPort;
354
365
  const wsUrl = `ws://127.0.0.1:${devPort}${url}`;
355
366
  console.log(` [Tunnel] Opening HMR WS relay: ${wsId} → ${wsUrl}`);
356
367
  const wsOptions = {};
@@ -493,7 +504,7 @@ export class TunnelClient {
493
504
  handleHttpRequest(request) {
494
505
  const { url } = request;
495
506
  const isApiRequest = url.startsWith('/live/') || url === '/health';
496
- const targetPort = isApiRequest ? this.options.apiPort : this.options.devPort;
507
+ const targetPort = isApiRequest ? this.options.apiPort : this.devPort;
497
508
  this.forwardToLocal(request, targetPort);
498
509
  this.requestsForwarded++;
499
510
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstantpage-agent",
3
- "version": "0.8.13",
3
+ "version": "0.8.15",
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": {