nstantpage-agent 0.5.15 → 0.5.17
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 +22 -4
- package/dist/devServer.js +30 -0
- package/dist/tunnel.d.ts +3 -1
- package/dist/tunnel.js +4 -4
- package/package.json +1 -1
package/dist/commands/start.js
CHANGED
|
@@ -25,7 +25,7 @@ import { TunnelClient } from '../tunnel.js';
|
|
|
25
25
|
import { LocalServer } from '../localServer.js';
|
|
26
26
|
import { PackageInstaller } from '../packageInstaller.js';
|
|
27
27
|
import { probeLocalPostgres, ensureLocalProjectDb, closeAdminPool, writeDatabaseUrlToEnv } from '../projectDb.js';
|
|
28
|
-
const VERSION = '0.5.
|
|
28
|
+
const VERSION = '0.5.17';
|
|
29
29
|
/**
|
|
30
30
|
* Resolve the backend API base URL.
|
|
31
31
|
* - If --backend is passed, use it
|
|
@@ -499,8 +499,23 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
499
499
|
projectId: '_standby_',
|
|
500
500
|
apiPort: 0,
|
|
501
501
|
devPort: 0,
|
|
502
|
-
onStartProject: async (pid) => {
|
|
503
|
-
|
|
502
|
+
onStartProject: async (pid, opts) => {
|
|
503
|
+
const isClean = opts?.clean === true;
|
|
504
|
+
// If clean reset requested and project is already running, stop it first
|
|
505
|
+
if (isClean && activeProjects.has(pid)) {
|
|
506
|
+
console.log(chalk.yellow(` Stopping existing project ${pid} for clean reset...`));
|
|
507
|
+
const existing = activeProjects.get(pid);
|
|
508
|
+
existing.tunnel.disconnect();
|
|
509
|
+
await existing.localServer.stop();
|
|
510
|
+
activeProjects.delete(pid);
|
|
511
|
+
// Wipe the project directory
|
|
512
|
+
const projectDir = resolveProjectDir('.', pid);
|
|
513
|
+
if (fs.existsSync(projectDir)) {
|
|
514
|
+
console.log(chalk.gray(` Wiping project directory: ${projectDir}`));
|
|
515
|
+
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
else if (activeProjects.has(pid)) {
|
|
504
519
|
console.log(chalk.yellow(` Project ${pid} is already running`));
|
|
505
520
|
return;
|
|
506
521
|
}
|
|
@@ -616,7 +631,6 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
616
631
|
databaseUrl = await ensureLocalProjectDb(projectId);
|
|
617
632
|
if (databaseUrl) {
|
|
618
633
|
console.log(chalk.green(` ✓ Database ready: project_${projectId}`));
|
|
619
|
-
writeDatabaseUrlToEnv(projectDir, databaseUrl);
|
|
620
634
|
}
|
|
621
635
|
}
|
|
622
636
|
}
|
|
@@ -662,6 +676,10 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
662
676
|
console.log(chalk.yellow(` ⚠ Could not fetch files: ${err.message}`));
|
|
663
677
|
progress('fetching-files', `Warning: ${err.message}`);
|
|
664
678
|
}
|
|
679
|
+
// Write DATABASE_URL to .env AFTER file fetch (so it doesn't get overwritten)
|
|
680
|
+
if (databaseUrl) {
|
|
681
|
+
writeDatabaseUrlToEnv(projectDir, databaseUrl);
|
|
682
|
+
}
|
|
665
683
|
// Wait for API server before proceeding (tunnel can keep connecting in background)
|
|
666
684
|
await apiServerPromise;
|
|
667
685
|
progress('starting-server', `API server ready`);
|
package/dist/devServer.js
CHANGED
|
@@ -9,6 +9,32 @@ import path from 'path';
|
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
import http from 'http';
|
|
11
11
|
import os from 'os';
|
|
12
|
+
/**
|
|
13
|
+
* Parse a .env file into a key-value map.
|
|
14
|
+
* Handles KEY=VALUE, KEY="VALUE", KEY='VALUE', comments (#), and empty lines.
|
|
15
|
+
*/
|
|
16
|
+
function parseDotenv(filePath) {
|
|
17
|
+
if (!fs.existsSync(filePath))
|
|
18
|
+
return {};
|
|
19
|
+
const result = {};
|
|
20
|
+
const lines = fs.readFileSync(filePath, 'utf-8').split('\n');
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
24
|
+
continue;
|
|
25
|
+
const eqIdx = trimmed.indexOf('=');
|
|
26
|
+
if (eqIdx === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
29
|
+
let val = trimmed.slice(eqIdx + 1).trim();
|
|
30
|
+
// Strip surrounding quotes
|
|
31
|
+
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
|
32
|
+
val = val.slice(1, -1);
|
|
33
|
+
}
|
|
34
|
+
result[key] = val;
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
12
38
|
export class DevServer {
|
|
13
39
|
options;
|
|
14
40
|
process = null;
|
|
@@ -39,6 +65,8 @@ export class DevServer {
|
|
|
39
65
|
}
|
|
40
66
|
const { projectDir, port } = this.options;
|
|
41
67
|
const extraEnv = this.options.env || {};
|
|
68
|
+
// Load .env file from project root (lower priority than explicit env vars)
|
|
69
|
+
const dotenvVars = parseDotenv(path.join(projectDir, '.env'));
|
|
42
70
|
// Detect project type
|
|
43
71
|
const pkgPath = path.join(projectDir, 'package.json');
|
|
44
72
|
if (!fs.existsSync(pkgPath)) {
|
|
@@ -63,6 +91,7 @@ export class DevServer {
|
|
|
63
91
|
cwd: projectDir,
|
|
64
92
|
env: {
|
|
65
93
|
...process.env,
|
|
94
|
+
...dotenvVars,
|
|
66
95
|
...extraEnv,
|
|
67
96
|
PORT: String(backendPort),
|
|
68
97
|
SERVER_PORT: String(backendPort),
|
|
@@ -97,6 +126,7 @@ export class DevServer {
|
|
|
97
126
|
}
|
|
98
127
|
const frontendEnv = {
|
|
99
128
|
...process.env,
|
|
129
|
+
...dotenvVars,
|
|
100
130
|
...extraEnv,
|
|
101
131
|
PORT: String(port),
|
|
102
132
|
};
|
package/dist/tunnel.d.ts
CHANGED
|
@@ -24,7 +24,9 @@ interface TunnelClientOptions {
|
|
|
24
24
|
/** Port where the dev server (Vite/Next.js) runs */
|
|
25
25
|
devPort: number;
|
|
26
26
|
/** Callback when gateway requests starting a new project on this device */
|
|
27
|
-
onStartProject?: (projectId: string
|
|
27
|
+
onStartProject?: (projectId: string, options?: {
|
|
28
|
+
clean?: boolean;
|
|
29
|
+
}) => Promise<void>;
|
|
28
30
|
/** Callback for setup progress — lets the standby tunnel relay phases to gateway */
|
|
29
31
|
onSetupProgress?: (projectId: string, phase: string, message: string) => void;
|
|
30
32
|
}
|
package/dist/tunnel.js
CHANGED
|
@@ -246,8 +246,8 @@ export class TunnelClient {
|
|
|
246
246
|
* Handle start-project: gateway wants this agent to start serving a new project.
|
|
247
247
|
* Called when user clicks "Connect" in the web editor's Cloud panel.
|
|
248
248
|
*/
|
|
249
|
-
async handleStartProject(projectId) {
|
|
250
|
-
console.log(` [Tunnel] Received start-project command for ${projectId}`);
|
|
249
|
+
async handleStartProject(projectId, clean) {
|
|
250
|
+
console.log(` [Tunnel] Received start-project command for ${projectId}${clean ? ' (clean)' : ''}`);
|
|
251
251
|
if (!projectId) {
|
|
252
252
|
this.send({ type: 'start-project-result', success: false, error: 'Missing projectId' });
|
|
253
253
|
return;
|
|
@@ -256,7 +256,7 @@ export class TunnelClient {
|
|
|
256
256
|
try {
|
|
257
257
|
// Send initial progress
|
|
258
258
|
this.sendSetupProgress(projectId, 'starting', 'Starting project setup...');
|
|
259
|
-
await this.options.onStartProject(projectId);
|
|
259
|
+
await this.options.onStartProject(projectId, clean ? { clean: true } : undefined);
|
|
260
260
|
this.sendSetupProgress(projectId, 'ready', 'Project is live!');
|
|
261
261
|
this.send({ type: 'start-project-result', projectId, success: true });
|
|
262
262
|
}
|
|
@@ -300,7 +300,7 @@ export class TunnelClient {
|
|
|
300
300
|
this.handleWsClose(msg.wsId);
|
|
301
301
|
break;
|
|
302
302
|
case 'start-project':
|
|
303
|
-
this.handleStartProject(msg.projectId);
|
|
303
|
+
this.handleStartProject(msg.projectId, msg.clean);
|
|
304
304
|
break;
|
|
305
305
|
default:
|
|
306
306
|
console.warn(` [Tunnel] Unknown message type: ${msg.type}`);
|
package/package.json
CHANGED