@mindstudio-ai/local-model-tunnel 0.5.61 → 0.5.63
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/{chunk-45DC6K4V.js → chunk-7CY3GAYS.js} +151 -1
- package/dist/chunk-7CY3GAYS.js.map +1 -0
- package/dist/{chunk-I7V6U5FS.js → chunk-NZYY7XUW.js} +20 -6
- package/dist/chunk-NZYY7XUW.js.map +1 -0
- package/dist/{chunk-2SN73FAD.js → chunk-W5JMAUEP.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/headless.js +2 -2
- package/dist/index.js +3 -3
- package/dist/{tui-5DJ7XDDK.js → tui-K4QNJV4A.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-45DC6K4V.js.map +0 -1
- package/dist/chunk-I7V6U5FS.js.map +0 -1
- /package/dist/{chunk-2SN73FAD.js.map → chunk-W5JMAUEP.js.map} +0 -0
- /package/dist/{tui-5DJ7XDDK.js.map → tui-K4QNJV4A.js.map} +0 -0
|
@@ -2206,6 +2206,12 @@ var ClientRegistry = class {
|
|
|
2206
2206
|
hasConnected() {
|
|
2207
2207
|
return this.clients.size > 0;
|
|
2208
2208
|
}
|
|
2209
|
+
hasHeadless() {
|
|
2210
|
+
for (const client of this.clients.values()) {
|
|
2211
|
+
if (client.mode === "headless") return true;
|
|
2212
|
+
}
|
|
2213
|
+
return false;
|
|
2214
|
+
}
|
|
2209
2215
|
count() {
|
|
2210
2216
|
return this.clients.size;
|
|
2211
2217
|
}
|
|
@@ -2245,6 +2251,96 @@ var ClientRegistry = class {
|
|
|
2245
2251
|
}
|
|
2246
2252
|
};
|
|
2247
2253
|
|
|
2254
|
+
// src/dev/proxy/telemetry-mock.ts
|
|
2255
|
+
var MAX_BODY_BYTES = 1048576;
|
|
2256
|
+
var SSE_KEEPALIVE_MS = 25e3;
|
|
2257
|
+
function tryHandleTelemetry(req, res, sseConnections) {
|
|
2258
|
+
const url = req.url ?? "";
|
|
2259
|
+
if (!url.startsWith("/_/telemetry/")) return false;
|
|
2260
|
+
if (!req.headers.authorization) {
|
|
2261
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
2262
|
+
res.end(
|
|
2263
|
+
JSON.stringify({
|
|
2264
|
+
error: "missing_authorization",
|
|
2265
|
+
code: "missing_authorization"
|
|
2266
|
+
})
|
|
2267
|
+
);
|
|
2268
|
+
return true;
|
|
2269
|
+
}
|
|
2270
|
+
if (url === "/_/telemetry/errors" && req.method === "POST") {
|
|
2271
|
+
handleBatchPost(req, res);
|
|
2272
|
+
return true;
|
|
2273
|
+
}
|
|
2274
|
+
if (url === "/_/telemetry/events" && req.method === "POST") {
|
|
2275
|
+
handleBatchPost(req, res);
|
|
2276
|
+
return true;
|
|
2277
|
+
}
|
|
2278
|
+
if (url === "/_/telemetry/presence" && req.method === "GET") {
|
|
2279
|
+
handlePresence(req, res, sseConnections);
|
|
2280
|
+
return true;
|
|
2281
|
+
}
|
|
2282
|
+
return false;
|
|
2283
|
+
}
|
|
2284
|
+
function handleBatchPost(req, res) {
|
|
2285
|
+
let total = 0;
|
|
2286
|
+
const chunks = [];
|
|
2287
|
+
let aborted = false;
|
|
2288
|
+
req.on("data", (chunk) => {
|
|
2289
|
+
total += chunk.length;
|
|
2290
|
+
if (total > MAX_BODY_BYTES) {
|
|
2291
|
+
aborted = true;
|
|
2292
|
+
req.destroy();
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
chunks.push(chunk);
|
|
2296
|
+
});
|
|
2297
|
+
req.on("end", () => {
|
|
2298
|
+
if (aborted) {
|
|
2299
|
+
res.writeHead(413, { "Content-Type": "application/json" });
|
|
2300
|
+
res.end(JSON.stringify({ accepted: 0, rejected: 0 }));
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
let accepted = 0;
|
|
2304
|
+
try {
|
|
2305
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8"));
|
|
2306
|
+
if (Array.isArray(body?.events)) accepted = body.events.length;
|
|
2307
|
+
} catch {
|
|
2308
|
+
}
|
|
2309
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2310
|
+
res.end(JSON.stringify({ accepted, rejected: 0 }));
|
|
2311
|
+
});
|
|
2312
|
+
req.on("error", () => {
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
function handlePresence(req, res, sseConnections) {
|
|
2316
|
+
res.writeHead(200, {
|
|
2317
|
+
"Content-Type": "text/event-stream",
|
|
2318
|
+
"Cache-Control": "no-cache",
|
|
2319
|
+
Connection: "keep-alive",
|
|
2320
|
+
"X-Accel-Buffering": "no"
|
|
2321
|
+
});
|
|
2322
|
+
res.flushHeaders?.();
|
|
2323
|
+
sseConnections.add(res);
|
|
2324
|
+
const keepalive = setInterval(() => {
|
|
2325
|
+
try {
|
|
2326
|
+
res.write(": keepalive\n\n");
|
|
2327
|
+
} catch {
|
|
2328
|
+
}
|
|
2329
|
+
}, SSE_KEEPALIVE_MS);
|
|
2330
|
+
let cleaned = false;
|
|
2331
|
+
const cleanup = () => {
|
|
2332
|
+
if (cleaned) return;
|
|
2333
|
+
cleaned = true;
|
|
2334
|
+
clearInterval(keepalive);
|
|
2335
|
+
sseConnections.delete(res);
|
|
2336
|
+
log.debug("telemetry-mock", "SSE closed", { open: sseConnections.size });
|
|
2337
|
+
};
|
|
2338
|
+
req.on("close", cleanup);
|
|
2339
|
+
res.on("close", cleanup);
|
|
2340
|
+
res.on("error", cleanup);
|
|
2341
|
+
log.debug("telemetry-mock", "SSE opened", { open: sseConnections.size });
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2248
2344
|
// src/dev/stdin-commands/types.ts
|
|
2249
2345
|
var CommandError = class extends Error {
|
|
2250
2346
|
constructor(message, code) {
|
|
@@ -2276,6 +2372,12 @@ var DevProxy = class _DevProxy {
|
|
|
2276
2372
|
commandQueue = [];
|
|
2277
2373
|
/** Last mirror snapshot — sent to new mirror viewers so they don't wait for the next checkout. */
|
|
2278
2374
|
lastMirrorSnapshot = null;
|
|
2375
|
+
/** Open /_/telemetry/presence SSE responses, drained on stop(). */
|
|
2376
|
+
sseConnections = /* @__PURE__ */ new Set();
|
|
2377
|
+
/** Waiters resolved when a headless (sandbox-owned) client registers via WS.
|
|
2378
|
+
* Lets the supervisor block on the real readiness signal instead of a
|
|
2379
|
+
* network-idle predicate that gets defeated by long-lived SSE responses. */
|
|
2380
|
+
headlessReadyWaiters = /* @__PURE__ */ new Set();
|
|
2279
2381
|
/** Upstream dev server health tracking. */
|
|
2280
2382
|
upstreamUp = true;
|
|
2281
2383
|
healthCheckTimer = null;
|
|
@@ -2294,6 +2396,32 @@ var DevProxy = class _DevProxy {
|
|
|
2294
2396
|
isBrowserConnected() {
|
|
2295
2397
|
return this.clients.hasConnected();
|
|
2296
2398
|
}
|
|
2399
|
+
/**
|
|
2400
|
+
* Resolve when a sandbox-owned headless client has registered via WS hello.
|
|
2401
|
+
* If one is already connected, resolves immediately. Otherwise queues a
|
|
2402
|
+
* one-shot waiter with a timeout. Used by `BrowserSupervisor` so it doesn't
|
|
2403
|
+
* declare `running` until the browser-agent is actually reachable for
|
|
2404
|
+
* commands — replacing the prior `networkidle0`-based readiness check
|
|
2405
|
+
* which is defeated by long-lived SSE responses (e.g. /_/telemetry/presence).
|
|
2406
|
+
*/
|
|
2407
|
+
waitForHeadlessClient(timeoutMs = 15e3) {
|
|
2408
|
+
if (this.clients.hasHeadless()) return Promise.resolve();
|
|
2409
|
+
return new Promise((resolve3, reject) => {
|
|
2410
|
+
const waiter = {
|
|
2411
|
+
resolve: resolve3,
|
|
2412
|
+
reject,
|
|
2413
|
+
timer: setTimeout(() => {
|
|
2414
|
+
this.headlessReadyWaiters.delete(waiter);
|
|
2415
|
+
reject(
|
|
2416
|
+
new Error(
|
|
2417
|
+
`Sandbox browser-agent did not connect within ${timeoutMs}ms`
|
|
2418
|
+
)
|
|
2419
|
+
);
|
|
2420
|
+
}, timeoutMs)
|
|
2421
|
+
};
|
|
2422
|
+
this.headlessReadyWaiters.add(waiter);
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2297
2425
|
/**
|
|
2298
2426
|
* Dispatch a command to the preferred browser client and wait for the result.
|
|
2299
2427
|
* Commands are queued and executed one at a time per client (FIFO).
|
|
@@ -2473,6 +2601,18 @@ var DevProxy = class _DevProxy {
|
|
|
2473
2601
|
this.wss.close();
|
|
2474
2602
|
this.wss = null;
|
|
2475
2603
|
}
|
|
2604
|
+
for (const sseRes of this.sseConnections) {
|
|
2605
|
+
try {
|
|
2606
|
+
sseRes.end();
|
|
2607
|
+
} catch {
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
this.sseConnections.clear();
|
|
2611
|
+
for (const w of this.headlessReadyWaiters) {
|
|
2612
|
+
clearTimeout(w.timer);
|
|
2613
|
+
w.reject(new Error("Proxy stopped"));
|
|
2614
|
+
}
|
|
2615
|
+
this.headlessReadyWaiters.clear();
|
|
2476
2616
|
if (this.server) {
|
|
2477
2617
|
log.info("proxy", "Dev proxy stopping");
|
|
2478
2618
|
this.server.close();
|
|
@@ -2557,6 +2697,13 @@ var DevProxy = class _DevProxy {
|
|
|
2557
2697
|
viewport,
|
|
2558
2698
|
mirror: !!msg.mirror
|
|
2559
2699
|
});
|
|
2700
|
+
if (mode === "headless" && this.headlessReadyWaiters.size > 0) {
|
|
2701
|
+
for (const w of this.headlessReadyWaiters) {
|
|
2702
|
+
clearTimeout(w.timer);
|
|
2703
|
+
w.resolve();
|
|
2704
|
+
}
|
|
2705
|
+
this.headlessReadyWaiters.clear();
|
|
2706
|
+
}
|
|
2560
2707
|
ws.send(JSON.stringify({ type: "ack", clientId }));
|
|
2561
2708
|
if (mode === "mirror" && this.lastMirrorSnapshot) {
|
|
2562
2709
|
try {
|
|
@@ -2791,6 +2938,9 @@ var DevProxy = class _DevProxy {
|
|
|
2791
2938
|
clientRes.end();
|
|
2792
2939
|
return;
|
|
2793
2940
|
}
|
|
2941
|
+
if (tryHandleTelemetry(clientReq, clientRes, this.sseConnections)) {
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2794
2944
|
if (clientReq.url?.startsWith("/_/")) {
|
|
2795
2945
|
this.forwardToApi(clientReq, clientRes);
|
|
2796
2946
|
return;
|
|
@@ -3541,4 +3691,4 @@ export {
|
|
|
3541
3691
|
watchConfigFile,
|
|
3542
3692
|
watchManifestFiles
|
|
3543
3693
|
};
|
|
3544
|
-
//# sourceMappingURL=chunk-
|
|
3694
|
+
//# sourceMappingURL=chunk-7CY3GAYS.js.map
|