nstantpage-agent 0.5.23 → 0.5.24

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/tunnel.d.ts CHANGED
@@ -42,7 +42,7 @@ export declare class TunnelClient {
42
42
  private requestsForwarded;
43
43
  private connectedAt;
44
44
  private lastPongReceived;
45
- /** Active WebSocket channels (terminal WS relay through tunnel) */
45
+ /** Active WebSocket channels (terminal WS + HMR WS relay through tunnel) */
46
46
  private wsChannels;
47
47
  /** Listeners for status changes (used by tray app) */
48
48
  private statusListeners;
@@ -87,14 +87,20 @@ export declare class TunnelClient {
87
87
  */
88
88
  private handleWsOpen;
89
89
  /**
90
- * Handle ws-data: frontend sent a message through the terminal WebSocket.
91
- * Parse it and route to the terminal session.
90
+ * Handle ws-data: frontend sent a message through a WebSocket channel.
91
+ * Routes to either terminal session or dev-server WebSocket.
92
92
  */
93
93
  private handleWsData;
94
94
  /**
95
- * Handle ws-close: frontend disconnected the terminal WebSocket.
95
+ * Handle ws-close: frontend disconnected the terminal WebSocket or HMR WebSocket.
96
96
  */
97
97
  private handleWsClose;
98
+ /**
99
+ * Handle ws-open for dev-server target: open a WebSocket to the local
100
+ * Vite dev server and relay data bidirectionally through the tunnel.
101
+ * This enables Vite HMR to work through the cloud preview URL.
102
+ */
103
+ private handleWsOpenDevServer;
98
104
  /**
99
105
  * Handle start-project: gateway wants this agent to start serving a new project.
100
106
  * Called when user clicks "Connect" in the web editor's Cloud panel.
package/dist/tunnel.js CHANGED
@@ -32,7 +32,7 @@ export class TunnelClient {
32
32
  requestsForwarded = 0;
33
33
  connectedAt = 0;
34
34
  lastPongReceived = 0;
35
- /** Active WebSocket channels (terminal WS relay through tunnel) */
35
+ /** Active WebSocket channels (terminal WS + HMR WS relay through tunnel) */
36
36
  wsChannels = new Map();
37
37
  /** Listeners for status changes (used by tray app) */
38
38
  statusListeners = new Set();
@@ -267,13 +267,31 @@ export class TunnelClient {
267
267
  });
268
268
  }
269
269
  /**
270
- * Handle ws-data: frontend sent a message through the terminal WebSocket.
271
- * Parse it and route to the terminal session.
270
+ * Handle ws-data: frontend sent a message through a WebSocket channel.
271
+ * Routes to either terminal session or dev-server WebSocket.
272
272
  */
273
- handleWsData(wsId, data) {
273
+ handleWsData(wsId, data, binary) {
274
274
  const channel = this.wsChannels.get(wsId);
275
275
  if (!channel)
276
276
  return;
277
+ // If this channel has a dev-server WebSocket, forward data directly
278
+ if (channel.devServerWs) {
279
+ try {
280
+ if (channel.devServerWs.readyState === WebSocket.OPEN) {
281
+ if (binary) {
282
+ channel.devServerWs.send(Buffer.from(data, 'base64'));
283
+ }
284
+ else {
285
+ channel.devServerWs.send(data);
286
+ }
287
+ }
288
+ }
289
+ catch (err) {
290
+ console.warn(` [Tunnel] Failed to forward HMR data to dev server:`, err.message);
291
+ }
292
+ return;
293
+ }
294
+ // Terminal session handling
277
295
  try {
278
296
  const msg = JSON.parse(data);
279
297
  const session = getTerminalSession(channel.sessionId);
@@ -298,16 +316,79 @@ export class TunnelClient {
298
316
  }
299
317
  }
300
318
  /**
301
- * Handle ws-close: frontend disconnected the terminal WebSocket.
319
+ * Handle ws-close: frontend disconnected the terminal WebSocket or HMR WebSocket.
302
320
  */
303
321
  handleWsClose(wsId) {
304
322
  const channel = this.wsChannels.get(wsId);
305
323
  if (channel) {
306
324
  if (channel.cleanup)
307
325
  channel.cleanup();
326
+ // Close dev-server WebSocket if this was an HMR relay
327
+ if (channel.devServerWs) {
328
+ try {
329
+ channel.devServerWs.close();
330
+ }
331
+ catch { }
332
+ }
308
333
  this.wsChannels.delete(wsId);
309
334
  }
310
335
  }
336
+ // ─── Dev Server WebSocket Relay (Vite HMR through tunnel) ──
337
+ /**
338
+ * Handle ws-open for dev-server target: open a WebSocket to the local
339
+ * Vite dev server and relay data bidirectionally through the tunnel.
340
+ * This enables Vite HMR to work through the cloud preview URL.
341
+ */
342
+ handleWsOpenDevServer(wsId, url, protocol) {
343
+ const devPort = this.options.devPort;
344
+ const wsUrl = `ws://127.0.0.1:${devPort}${url}`;
345
+ console.log(` [Tunnel] Opening HMR WS relay: ${wsId} → ${wsUrl}`);
346
+ const wsOptions = {};
347
+ const protocols = protocol ? protocol.split(',').map(p => p.trim()) : undefined;
348
+ const devWs = new WebSocket(wsUrl, protocols, wsOptions);
349
+ devWs.on('open', () => {
350
+ console.log(` [Tunnel] HMR WS connected: ${wsId} → ${wsUrl}`);
351
+ });
352
+ devWs.on('message', (data, isBinary) => {
353
+ // Relay dev server messages back to browser through tunnel
354
+ if (isBinary) {
355
+ const buf = data instanceof Buffer ? data : Buffer.from(data);
356
+ this.send({
357
+ type: 'ws-data',
358
+ wsId,
359
+ data: buf.toString('base64'),
360
+ binary: true,
361
+ });
362
+ }
363
+ else {
364
+ this.send({
365
+ type: 'ws-data',
366
+ wsId,
367
+ data: data.toString(),
368
+ });
369
+ }
370
+ });
371
+ devWs.on('close', () => {
372
+ console.log(` [Tunnel] HMR WS closed: ${wsId}`);
373
+ this.send({ type: 'ws-close', wsId });
374
+ this.wsChannels.delete(wsId);
375
+ });
376
+ devWs.on('error', (err) => {
377
+ console.warn(` [Tunnel] HMR WS error: ${wsId}:`, err.message);
378
+ this.send({ type: 'ws-close', wsId });
379
+ this.wsChannels.delete(wsId);
380
+ });
381
+ this.wsChannels.set(wsId, {
382
+ sessionId: `hmr-${wsId}`,
383
+ cleanup: () => {
384
+ try {
385
+ devWs.close();
386
+ }
387
+ catch { }
388
+ },
389
+ devServerWs: devWs,
390
+ });
391
+ }
311
392
  /**
312
393
  * Handle start-project: gateway wants this agent to start serving a new project.
313
394
  * Called when user clicks "Connect" in the web editor's Cloud panel.
@@ -369,10 +450,15 @@ export class TunnelClient {
369
450
  this.handleHttpRequest(msg);
370
451
  break;
371
452
  case 'ws-open':
372
- this.handleWsOpen(msg.wsId, msg.sessionId, msg.projectId);
453
+ if (msg.target === 'dev-server') {
454
+ this.handleWsOpenDevServer(msg.wsId, msg.url || '/', msg.protocol);
455
+ }
456
+ else {
457
+ this.handleWsOpen(msg.wsId, msg.sessionId, msg.projectId);
458
+ }
373
459
  break;
374
460
  case 'ws-data':
375
- this.handleWsData(msg.wsId, msg.data);
461
+ this.handleWsData(msg.wsId, msg.data, msg.binary);
376
462
  break;
377
463
  case 'ws-close':
378
464
  this.handleWsClose(msg.wsId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstantpage-agent",
3
- "version": "0.5.23",
3
+ "version": "0.5.24",
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": {