nstantpage-agent 0.2.0
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/README.md +207 -0
- package/dist/checker.d.ts +35 -0
- package/dist/checker.js +151 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +67 -0
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.js +62 -0
- package/dist/commands/start.d.ts +23 -0
- package/dist/commands/start.js +140 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.js +53 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +23 -0
- package/dist/devServer.d.ts +65 -0
- package/dist/devServer.js +308 -0
- package/dist/errorStore.d.ts +51 -0
- package/dist/errorStore.js +167 -0
- package/dist/fileManager.d.ts +44 -0
- package/dist/fileManager.js +129 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/localServer.d.ts +70 -0
- package/dist/localServer.js +555 -0
- package/dist/packageInstaller.d.ts +29 -0
- package/dist/packageInstaller.js +111 -0
- package/dist/tunnel.d.ts +71 -0
- package/dist/tunnel.js +247 -0
- package/package.json +62 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package Installer — handles npm/pnpm package installation locally.
|
|
3
|
+
* Replaces the container-based /live/install endpoint.
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
export class PackageInstaller {
|
|
9
|
+
projectDir;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.projectDir = options.projectDir;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Install packages into the project.
|
|
15
|
+
*/
|
|
16
|
+
async install(packages, dev = false) {
|
|
17
|
+
const pm = this.detectPackageManager();
|
|
18
|
+
const args = this.buildInstallArgs(pm, packages, dev);
|
|
19
|
+
console.log(` [Installer] ${pm} ${args.join(' ')}`);
|
|
20
|
+
try {
|
|
21
|
+
const output = await this.runCommand(pm, args, 60_000);
|
|
22
|
+
return {
|
|
23
|
+
success: true,
|
|
24
|
+
output,
|
|
25
|
+
installedPackages: packages,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
output: err.message || 'Installation failed',
|
|
32
|
+
installedPackages: [],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Ensure all project dependencies are installed.
|
|
38
|
+
*/
|
|
39
|
+
async ensureDependencies() {
|
|
40
|
+
const nodeModules = path.join(this.projectDir, 'node_modules');
|
|
41
|
+
if (existsSync(nodeModules))
|
|
42
|
+
return;
|
|
43
|
+
console.log(` [Installer] Installing project dependencies...`);
|
|
44
|
+
const pm = this.detectPackageManager();
|
|
45
|
+
const args = pm === 'pnpm' ? ['install'] : ['install'];
|
|
46
|
+
await this.runCommand(pm, args, 120_000);
|
|
47
|
+
console.log(` [Installer] Dependencies installed`);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Detect which package manager is used (pnpm, yarn, npm).
|
|
51
|
+
*/
|
|
52
|
+
detectPackageManager() {
|
|
53
|
+
if (existsSync(path.join(this.projectDir, 'pnpm-lock.yaml')))
|
|
54
|
+
return 'pnpm';
|
|
55
|
+
if (existsSync(path.join(this.projectDir, 'yarn.lock')))
|
|
56
|
+
return 'yarn';
|
|
57
|
+
return 'npm';
|
|
58
|
+
}
|
|
59
|
+
buildInstallArgs(pm, packages, dev) {
|
|
60
|
+
const devFlag = dev
|
|
61
|
+
? (pm === 'npm' ? '--save-dev' : '-D')
|
|
62
|
+
: '';
|
|
63
|
+
switch (pm) {
|
|
64
|
+
case 'pnpm':
|
|
65
|
+
return ['add', ...packages, ...(devFlag ? [devFlag] : [])];
|
|
66
|
+
case 'yarn':
|
|
67
|
+
return ['add', ...packages, ...(devFlag ? [devFlag] : [])];
|
|
68
|
+
default:
|
|
69
|
+
return ['install', ...packages, ...(devFlag ? [devFlag] : [])];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
runCommand(cmd, args, timeoutMs) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const proc = spawn(cmd, args, {
|
|
75
|
+
cwd: this.projectDir,
|
|
76
|
+
env: process.env,
|
|
77
|
+
shell: true,
|
|
78
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
79
|
+
});
|
|
80
|
+
let stdout = '';
|
|
81
|
+
let stderr = '';
|
|
82
|
+
proc.stdout?.on('data', (d) => {
|
|
83
|
+
stdout += d.toString();
|
|
84
|
+
process.stdout.write(` ${d.toString().trimEnd()}\n`);
|
|
85
|
+
});
|
|
86
|
+
proc.stderr?.on('data', (d) => {
|
|
87
|
+
stderr += d.toString();
|
|
88
|
+
// Only show actual errors, not progress bars
|
|
89
|
+
const line = d.toString().trim();
|
|
90
|
+
if (line && !line.includes('progress') && !line.startsWith('⸩')) {
|
|
91
|
+
process.stderr.write(` ${line}\n`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
proc.on('close', (code) => {
|
|
95
|
+
if (code === 0)
|
|
96
|
+
resolve(stdout);
|
|
97
|
+
else
|
|
98
|
+
reject(new Error(stderr || stdout || `${cmd} exited with code ${code}`));
|
|
99
|
+
});
|
|
100
|
+
proc.on('error', reject);
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
try {
|
|
103
|
+
proc.kill();
|
|
104
|
+
}
|
|
105
|
+
catch { }
|
|
106
|
+
reject(new Error(`${cmd} timed out after ${timeoutMs / 1000}s`));
|
|
107
|
+
}, timeoutMs);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=packageInstaller.js.map
|
package/dist/tunnel.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel Client v2 — WebSocket connection to gateway
|
|
3
|
+
*
|
|
4
|
+
* Enhanced to route requests to the correct local handler:
|
|
5
|
+
* - /live/* API requests → Local API server (handles file sync, checks, etc.)
|
|
6
|
+
* - Everything else → Local dev server (Vite, Next.js, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Protocol (JSON messages over WebSocket):
|
|
9
|
+
* Gateway → Agent:
|
|
10
|
+
* { type: "http-request", id, method, url, headers, body? }
|
|
11
|
+
* { type: "ping" }
|
|
12
|
+
* Agent → Gateway:
|
|
13
|
+
* { type: "http-response", id, statusCode, headers, body? }
|
|
14
|
+
* { type: "pong" }
|
|
15
|
+
* { type: "agent-info", version, hostname, platform, capabilities }
|
|
16
|
+
* { type: "error-update", errors }
|
|
17
|
+
*/
|
|
18
|
+
interface TunnelClientOptions {
|
|
19
|
+
gatewayUrl: string;
|
|
20
|
+
token: string;
|
|
21
|
+
projectId: string;
|
|
22
|
+
/** Port where the local API server (/live/* handlers) runs */
|
|
23
|
+
apiPort: number;
|
|
24
|
+
/** Port where the dev server (Vite/Next.js) runs */
|
|
25
|
+
devPort: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class TunnelClient {
|
|
28
|
+
private ws;
|
|
29
|
+
private options;
|
|
30
|
+
private reconnectTimer;
|
|
31
|
+
private shouldReconnect;
|
|
32
|
+
private reconnectAttempts;
|
|
33
|
+
private maxReconnectAttempts;
|
|
34
|
+
private pingInterval;
|
|
35
|
+
private requestsForwarded;
|
|
36
|
+
private connectedAt;
|
|
37
|
+
constructor(options: TunnelClientOptions);
|
|
38
|
+
get isConnected(): boolean;
|
|
39
|
+
get stats(): {
|
|
40
|
+
requestsForwarded: number;
|
|
41
|
+
connectedAt: number;
|
|
42
|
+
uptime: number;
|
|
43
|
+
};
|
|
44
|
+
connect(): Promise<void>;
|
|
45
|
+
disconnect(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Push an error update to the gateway (for WebSocket error notifications).
|
|
48
|
+
*/
|
|
49
|
+
pushErrorUpdate(errors: {
|
|
50
|
+
buildErrors: string[];
|
|
51
|
+
typeErrors: string[];
|
|
52
|
+
lintErrors: string[];
|
|
53
|
+
runtimeErrors: string[];
|
|
54
|
+
}): void;
|
|
55
|
+
private send;
|
|
56
|
+
private handleMessage;
|
|
57
|
+
/**
|
|
58
|
+
* Route incoming HTTP requests to the correct local server:
|
|
59
|
+
* - /live/* paths → Local API server (file sync, checks, etc.)
|
|
60
|
+
* - /health → Local API server
|
|
61
|
+
* - Everything else → Dev server (Vite HMR, page loads, etc.)
|
|
62
|
+
*/
|
|
63
|
+
private handleHttpRequest;
|
|
64
|
+
/**
|
|
65
|
+
* Forward an HTTP request to a local server port and return the response.
|
|
66
|
+
*/
|
|
67
|
+
private forwardToLocal;
|
|
68
|
+
private cleanup;
|
|
69
|
+
private scheduleReconnect;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
package/dist/tunnel.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel Client v2 — WebSocket connection to gateway
|
|
3
|
+
*
|
|
4
|
+
* Enhanced to route requests to the correct local handler:
|
|
5
|
+
* - /live/* API requests → Local API server (handles file sync, checks, etc.)
|
|
6
|
+
* - Everything else → Local dev server (Vite, Next.js, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Protocol (JSON messages over WebSocket):
|
|
9
|
+
* Gateway → Agent:
|
|
10
|
+
* { type: "http-request", id, method, url, headers, body? }
|
|
11
|
+
* { type: "ping" }
|
|
12
|
+
* Agent → Gateway:
|
|
13
|
+
* { type: "http-response", id, statusCode, headers, body? }
|
|
14
|
+
* { type: "pong" }
|
|
15
|
+
* { type: "agent-info", version, hostname, platform, capabilities }
|
|
16
|
+
* { type: "error-update", errors }
|
|
17
|
+
*/
|
|
18
|
+
import WebSocket from 'ws';
|
|
19
|
+
import http from 'http';
|
|
20
|
+
import os from 'os';
|
|
21
|
+
export class TunnelClient {
|
|
22
|
+
ws = null;
|
|
23
|
+
options;
|
|
24
|
+
reconnectTimer = null;
|
|
25
|
+
shouldReconnect = true;
|
|
26
|
+
reconnectAttempts = 0;
|
|
27
|
+
maxReconnectAttempts = 50;
|
|
28
|
+
pingInterval = null;
|
|
29
|
+
requestsForwarded = 0;
|
|
30
|
+
connectedAt = 0;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
get isConnected() {
|
|
35
|
+
return this.ws?.readyState === WebSocket.OPEN;
|
|
36
|
+
}
|
|
37
|
+
get stats() {
|
|
38
|
+
return {
|
|
39
|
+
requestsForwarded: this.requestsForwarded,
|
|
40
|
+
connectedAt: this.connectedAt,
|
|
41
|
+
uptime: this.connectedAt ? Date.now() - this.connectedAt : 0,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async connect() {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const url = `${this.options.gatewayUrl}/tunnel/connect?token=${encodeURIComponent(this.options.token)}&projectId=${encodeURIComponent(this.options.projectId)}`;
|
|
47
|
+
this.ws = new WebSocket(url);
|
|
48
|
+
const connectTimeout = setTimeout(() => {
|
|
49
|
+
if (this.ws?.readyState !== WebSocket.OPEN) {
|
|
50
|
+
this.ws?.terminate();
|
|
51
|
+
reject(new Error('Connection timed out'));
|
|
52
|
+
}
|
|
53
|
+
}, 15_000);
|
|
54
|
+
this.ws.on('open', () => {
|
|
55
|
+
clearTimeout(connectTimeout);
|
|
56
|
+
this.reconnectAttempts = 0;
|
|
57
|
+
this.connectedAt = Date.now();
|
|
58
|
+
// Send enhanced agent info with capabilities
|
|
59
|
+
this.send({
|
|
60
|
+
type: 'agent-info',
|
|
61
|
+
version: '0.2.0',
|
|
62
|
+
hostname: os.hostname(),
|
|
63
|
+
platform: `${os.platform()} ${os.arch()}`,
|
|
64
|
+
capabilities: [
|
|
65
|
+
'file-sync',
|
|
66
|
+
'type-check',
|
|
67
|
+
'install',
|
|
68
|
+
'terminal',
|
|
69
|
+
'dev-server',
|
|
70
|
+
'hard-patterns',
|
|
71
|
+
'normalize',
|
|
72
|
+
'full-api',
|
|
73
|
+
],
|
|
74
|
+
apiPort: this.options.apiPort,
|
|
75
|
+
devPort: this.options.devPort,
|
|
76
|
+
});
|
|
77
|
+
// Start keepalive ping
|
|
78
|
+
this.pingInterval = setInterval(() => {
|
|
79
|
+
this.send({ type: 'pong' });
|
|
80
|
+
}, 30_000);
|
|
81
|
+
resolve();
|
|
82
|
+
});
|
|
83
|
+
this.ws.on('message', (data) => {
|
|
84
|
+
try {
|
|
85
|
+
const msg = JSON.parse(data.toString());
|
|
86
|
+
this.handleMessage(msg);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
console.error(' [Tunnel] Invalid message:', err);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
this.ws.on('close', (code, reason) => {
|
|
93
|
+
console.log(` [Tunnel] Disconnected (${code}: ${reason || 'no reason'})`);
|
|
94
|
+
this.cleanup();
|
|
95
|
+
this.scheduleReconnect();
|
|
96
|
+
});
|
|
97
|
+
this.ws.on('error', (err) => {
|
|
98
|
+
clearTimeout(connectTimeout);
|
|
99
|
+
if (this.reconnectAttempts === 0) {
|
|
100
|
+
reject(err);
|
|
101
|
+
}
|
|
102
|
+
console.error(` [Tunnel] Error: ${err.message}`);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
disconnect() {
|
|
107
|
+
this.shouldReconnect = false;
|
|
108
|
+
this.cleanup();
|
|
109
|
+
if (this.ws) {
|
|
110
|
+
this.ws.close(1000, 'Agent shutting down');
|
|
111
|
+
this.ws = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Push an error update to the gateway (for WebSocket error notifications).
|
|
116
|
+
*/
|
|
117
|
+
pushErrorUpdate(errors) {
|
|
118
|
+
this.send({
|
|
119
|
+
type: 'error-update',
|
|
120
|
+
projectId: this.options.projectId,
|
|
121
|
+
errors,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
send(msg) {
|
|
125
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
126
|
+
this.ws.send(JSON.stringify(msg));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
handleMessage(msg) {
|
|
130
|
+
switch (msg.type) {
|
|
131
|
+
case 'ping':
|
|
132
|
+
this.send({ type: 'pong' });
|
|
133
|
+
break;
|
|
134
|
+
case 'http-request':
|
|
135
|
+
this.handleHttpRequest(msg);
|
|
136
|
+
break;
|
|
137
|
+
default:
|
|
138
|
+
console.warn(` [Tunnel] Unknown message type: ${msg.type}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Route incoming HTTP requests to the correct local server:
|
|
143
|
+
* - /live/* paths → Local API server (file sync, checks, etc.)
|
|
144
|
+
* - /health → Local API server
|
|
145
|
+
* - Everything else → Dev server (Vite HMR, page loads, etc.)
|
|
146
|
+
*/
|
|
147
|
+
handleHttpRequest(request) {
|
|
148
|
+
const { url } = request;
|
|
149
|
+
const isApiRequest = url.startsWith('/live/') || url === '/health';
|
|
150
|
+
const targetPort = isApiRequest ? this.options.apiPort : this.options.devPort;
|
|
151
|
+
this.forwardToLocal(request, targetPort);
|
|
152
|
+
this.requestsForwarded++;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Forward an HTTP request to a local server port and return the response.
|
|
156
|
+
*/
|
|
157
|
+
forwardToLocal(request, port) {
|
|
158
|
+
const { id, method, url, headers, body } = request;
|
|
159
|
+
const reqOptions = {
|
|
160
|
+
hostname: '127.0.0.1',
|
|
161
|
+
port,
|
|
162
|
+
path: url,
|
|
163
|
+
method,
|
|
164
|
+
headers: {
|
|
165
|
+
...headers,
|
|
166
|
+
host: `127.0.0.1:${port}`,
|
|
167
|
+
'x-forwarded-host': headers.host || '',
|
|
168
|
+
'x-tunnel-request-id': id,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
const proxyReq = http.request(reqOptions, (proxyRes) => {
|
|
172
|
+
const chunks = [];
|
|
173
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
174
|
+
proxyRes.on('end', () => {
|
|
175
|
+
const responseBody = Buffer.concat(chunks);
|
|
176
|
+
this.send({
|
|
177
|
+
type: 'http-response',
|
|
178
|
+
id,
|
|
179
|
+
statusCode: proxyRes.statusCode || 200,
|
|
180
|
+
headers: proxyRes.headers,
|
|
181
|
+
body: responseBody.length > 0 ? responseBody.toString('base64') : undefined,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
proxyReq.on('error', (err) => {
|
|
186
|
+
console.error(` [Tunnel] Local proxy error for ${method} ${url} (port ${port}): ${err.message}`);
|
|
187
|
+
this.send({
|
|
188
|
+
type: 'http-response',
|
|
189
|
+
id,
|
|
190
|
+
statusCode: 502,
|
|
191
|
+
headers: { 'content-type': 'application/json' },
|
|
192
|
+
body: Buffer.from(JSON.stringify({
|
|
193
|
+
error: `Local server error: ${err.message}`,
|
|
194
|
+
agentMode: true,
|
|
195
|
+
})).toString('base64'),
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
proxyReq.setTimeout(60_000, () => {
|
|
199
|
+
proxyReq.destroy();
|
|
200
|
+
this.send({
|
|
201
|
+
type: 'http-response',
|
|
202
|
+
id,
|
|
203
|
+
statusCode: 504,
|
|
204
|
+
headers: { 'content-type': 'application/json' },
|
|
205
|
+
body: Buffer.from(JSON.stringify({
|
|
206
|
+
error: 'Local server timeout',
|
|
207
|
+
agentMode: true,
|
|
208
|
+
})).toString('base64'),
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
if (body) {
|
|
212
|
+
proxyReq.write(Buffer.from(body, 'base64'));
|
|
213
|
+
}
|
|
214
|
+
proxyReq.end();
|
|
215
|
+
}
|
|
216
|
+
cleanup() {
|
|
217
|
+
if (this.reconnectTimer) {
|
|
218
|
+
clearTimeout(this.reconnectTimer);
|
|
219
|
+
this.reconnectTimer = null;
|
|
220
|
+
}
|
|
221
|
+
if (this.pingInterval) {
|
|
222
|
+
clearInterval(this.pingInterval);
|
|
223
|
+
this.pingInterval = null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
scheduleReconnect() {
|
|
227
|
+
if (!this.shouldReconnect)
|
|
228
|
+
return;
|
|
229
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
230
|
+
console.error(' [Tunnel] Max reconnect attempts reached. Giving up.');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30_000);
|
|
234
|
+
this.reconnectAttempts++;
|
|
235
|
+
console.log(` [Tunnel] Reconnecting in ${delay / 1000}s (attempt ${this.reconnectAttempts})...`);
|
|
236
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
237
|
+
try {
|
|
238
|
+
await this.connect();
|
|
239
|
+
console.log(' [Tunnel] Reconnected!');
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Will retry via close handler
|
|
243
|
+
}
|
|
244
|
+
}, delay);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=tunnel.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nstantpage-agent",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Local development agent for nstantpage.com — run your projects locally, preview in the cloud. Replaces cloud containers for faster builds.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"nstantpage": "./dist/cli.js",
|
|
8
|
+
"nstantpage-agent": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/**/*.js",
|
|
13
|
+
"dist/**/*.d.ts",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsx src/cli.ts",
|
|
19
|
+
"start": "node dist/cli.js",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18.0.0"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/nstantpage/nstantpage-agent"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://nstantpage.com",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/nstantpage/nstantpage-agent/issues"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"nstantpage",
|
|
35
|
+
"preview",
|
|
36
|
+
"development",
|
|
37
|
+
"agent",
|
|
38
|
+
"tunnel",
|
|
39
|
+
"local-dev",
|
|
40
|
+
"dev-server",
|
|
41
|
+
"vite",
|
|
42
|
+
"nextjs"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"chalk": "^5.3.0",
|
|
47
|
+
"commander": "^12.1.0",
|
|
48
|
+
"conf": "^13.0.1",
|
|
49
|
+
"express": "^4.21.0",
|
|
50
|
+
"http-proxy": "^1.18.1",
|
|
51
|
+
"open": "^10.1.0",
|
|
52
|
+
"ws": "^8.18.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/express": "^4.17.21",
|
|
56
|
+
"@types/http-proxy": "^1.17.14",
|
|
57
|
+
"@types/node": "^20.14.0",
|
|
58
|
+
"@types/ws": "^8.5.10",
|
|
59
|
+
"tsx": "^4.19.0",
|
|
60
|
+
"typescript": "^5.5.0"
|
|
61
|
+
}
|
|
62
|
+
}
|