@linkshell/gateway 0.4.25 → 0.4.28
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/gateway/src/embedded.js +20 -0
- package/dist/gateway/src/embedded.js.map +1 -1
- package/dist/gateway/src/index.js +9 -1
- package/dist/gateway/src/index.js.map +1 -1
- package/dist/gateway/tsconfig.tsbuildinfo +1 -1
- package/dist/shared-protocol/src/index.d.ts +438 -438
- package/package.json +1 -1
- package/src/embedded.ts +19 -0
- package/src/index.ts +9 -1
package/package.json
CHANGED
package/src/embedded.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
handleTunnelWsUpgrade,
|
|
26
26
|
cleanupSessionTunnels,
|
|
27
27
|
} from "./tunnel.js";
|
|
28
|
+
import { serveWeb, serveWebAsset, webEnabled, webDistPath } from "./static-web.js";
|
|
28
29
|
|
|
29
30
|
export interface EmbeddedGatewayOptions {
|
|
30
31
|
port?: number;
|
|
@@ -252,6 +253,11 @@ export function startEmbeddedGateway(
|
|
|
252
253
|
return;
|
|
253
254
|
}
|
|
254
255
|
|
|
256
|
+
// Serve the gateway's OWN built web assets (no SPA fallback) before the
|
|
257
|
+
// tunnel cookie fallback, so a real asset like /assets/index-xxx.js is
|
|
258
|
+
// served locally instead of being proxied via a stale tunnel cookie.
|
|
259
|
+
if (await serveWebAsset(req, res)) return;
|
|
260
|
+
|
|
255
261
|
// Tunnel fallback: cookie-based routing for sub-resources (e.g. /_next/static/...)
|
|
256
262
|
const tunnelCookie = parseTunnelCookie(req);
|
|
257
263
|
if (tunnelCookie && shouldUseTunnelCookieFallback(req, url.pathname, (pathname) =>
|
|
@@ -272,6 +278,11 @@ export function startEmbeddedGateway(
|
|
|
272
278
|
return;
|
|
273
279
|
}
|
|
274
280
|
|
|
281
|
+
// Web SPA: last GET fallback, after every API route, so it never shadows
|
|
282
|
+
// them. Serves index.html for "/" and client-side routes; a no-op (false)
|
|
283
|
+
// when no web dist is bundled (e.g. an API-only embedded gateway).
|
|
284
|
+
if (await serveWeb(req, res)) return;
|
|
285
|
+
|
|
275
286
|
json(res, 404, { error: "not_found" });
|
|
276
287
|
} catch (err) {
|
|
277
288
|
if (err instanceof ZodError) {
|
|
@@ -479,6 +490,14 @@ export function startEmbeddedGateway(
|
|
|
479
490
|
const actualPort =
|
|
480
491
|
typeof addr === "object" && addr ? addr.port : targetPort;
|
|
481
492
|
log("info", `embedded gateway on port ${actualPort}`);
|
|
493
|
+
// Surface whether the bundled web SPA was found — the in-app WebView loads
|
|
494
|
+
// this gateway's "/", so a missing dist means a blank screen. Makes the
|
|
495
|
+
// LAN/self-hosted "WebView is blank" failure mode diagnosable from logs.
|
|
496
|
+
if (webEnabled()) {
|
|
497
|
+
log("info", `web UI served from ${webDistPath()}`);
|
|
498
|
+
} else {
|
|
499
|
+
log("warn", `web UI not bundled (WEB_DIST=${webDistPath()} has no index.html) — in-app agent console will be blank`);
|
|
500
|
+
}
|
|
482
501
|
resolve({
|
|
483
502
|
port: actualPort,
|
|
484
503
|
httpUrl: `http://127.0.0.1:${actualPort}`,
|
package/src/index.ts
CHANGED
|
@@ -774,7 +774,13 @@ wss.on(
|
|
|
774
774
|
}
|
|
775
775
|
|
|
776
776
|
// Ping/pong for liveness — terminate connections that stop responding
|
|
777
|
-
//
|
|
777
|
+
// (dead/half-open sockets) instead of leaking them. Liveness is proven by
|
|
778
|
+
// EITHER a WS pong OR any inbound message: React Native's WebSocket does
|
|
779
|
+
// not reliably auto-reply to server ping control frames, so a perfectly
|
|
780
|
+
// healthy native client (terminal) would otherwise be terminated every
|
|
781
|
+
// ~40s, silently dropping its keystrokes into the reconnect queue. Active
|
|
782
|
+
// clients send a heartbeat every 15s (< PING_INTERVAL), so they always
|
|
783
|
+
// refresh isAlive; only a genuinely silent socket gets reaped.
|
|
778
784
|
const liveSocket = socket as WebSocket & { isAlive?: boolean };
|
|
779
785
|
liveSocket.isAlive = true;
|
|
780
786
|
socket.on("pong", () => {
|
|
@@ -791,6 +797,8 @@ wss.on(
|
|
|
791
797
|
}, PING_INTERVAL);
|
|
792
798
|
|
|
793
799
|
socket.on("message", (data: WebSocket.RawData) => {
|
|
800
|
+
// Any inbound traffic counts as proof of life (see ping/pong note above).
|
|
801
|
+
liveSocket.isAlive = true;
|
|
794
802
|
try {
|
|
795
803
|
handleSocketMessage(
|
|
796
804
|
socket,
|