@mindstudio-ai/local-model-tunnel 0.5.48 → 0.5.49

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.
@@ -274,6 +274,7 @@ var ApiError = class extends Error {
274
274
  this.statusCode = statusCode;
275
275
  this.name = "ApiError";
276
276
  }
277
+ statusCode;
277
278
  };
278
279
  var DevPollError = class extends Error {
279
280
  constructor(message, statusCode) {
@@ -281,6 +282,7 @@ var DevPollError = class extends Error {
281
282
  this.statusCode = statusCode;
282
283
  this.name = "DevPollError";
283
284
  }
285
+ statusCode;
284
286
  };
285
287
 
286
288
  // src/dev/logging/ndjson-log.ts
@@ -293,6 +295,10 @@ var NdjsonLog = class {
293
295
  this.keepLines = keepLines;
294
296
  this.maxBytes = maxBytes;
295
297
  }
298
+ filename;
299
+ maxLines;
300
+ keepLines;
301
+ maxBytes;
296
302
  fd = null;
297
303
  logPath = null;
298
304
  lineCount = 0;
@@ -701,6 +707,34 @@ console.error = (...args) => {
701
707
  // Track secret keys so we can clean up between requests
702
708
  let _activeSecretKeys = [];
703
709
 
710
+ // ---------------------------------------------------------------------------
711
+ // Single flush loop for all active requests
712
+ // ---------------------------------------------------------------------------
713
+ // One interval sweeps all tracked requests instead of one interval per
714
+ // request. This stays efficient even with thousands of concurrent requests.
715
+
716
+ const BACKGROUND_TIMEOUT = 30 * 60 * 1000; // 30 minutes after method returns
717
+
718
+ const activeRequests = new Map();
719
+
720
+ setInterval(() => {
721
+ const now = Date.now();
722
+ for (const [id, req] of activeRequests) {
723
+ if (req.stdout.length > req.flushed) {
724
+ const lines = req.stdout.slice(req.flushed);
725
+ req.flushed = req.stdout.length;
726
+ try {
727
+ process.send({ type: req.done ? 'background-stdout' : 'stdout', id, lines });
728
+ } catch {}
729
+ } else if (req.done && now - req.doneAt > BACKGROUND_TIMEOUT) {
730
+ activeRequests.delete(id);
731
+ try { process.send({ type: 'stdout-end', id }); } catch {}
732
+ }
733
+ }
734
+ }, 1000);
735
+
736
+ // ---------------------------------------------------------------------------
737
+
704
738
  process.on('message', async (msg) => {
705
739
  const { id, transpiledPath, methodExport, input, auth, databases, authorizationToken, apiBaseUrl, streamId, secrets } = msg;
706
740
 
@@ -717,36 +751,15 @@ process.on('message', async (msg) => {
717
751
  streamId: streamId ?? undefined,
718
752
  };
719
753
 
720
- const stdout = [];
721
- let flushed = 0;
722
- let done = false;
723
-
724
- // Flush new stdout lines every 1s while the method is running.
725
- // After the method returns, switches to background-stdout type.
726
- const flushInterval = setInterval(() => {
727
- if (stdout.length > flushed) {
728
- const lines = stdout.slice(flushed);
729
- flushed = stdout.length;
730
- try {
731
- process.send({ type: done ? 'background-stdout' : 'stdout', id, lines });
732
- } catch {}
733
- idleTicks = 0;
734
- } else if (done) {
735
- idleTicks++;
736
- if (idleTicks >= 2) {
737
- clearInterval(flushInterval);
738
- try { process.send({ type: 'stdout-end', id }); } catch {}
739
- }
740
- }
741
- }, 1000);
742
- let idleTicks = 0;
754
+ const req = { stdout: [], flushed: 0, done: false, doneAt: 0 };
755
+ activeRequests.set(id, req);
743
756
 
744
757
  process.send({ type: 'start', id });
745
758
 
746
759
  const startTime = Date.now();
747
760
 
748
761
  try {
749
- const returnValue = await consoleAls.run(stdout, () =>
762
+ const returnValue = await consoleAls.run(req.stdout, () =>
750
763
  runWithContext(ctx, async () => {
751
764
  const mod = await import(transpiledPath + '?t=' + Date.now());
752
765
  const fn = mod[methodExport];
@@ -759,22 +772,24 @@ process.on('message', async (msg) => {
759
772
  const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };
760
773
 
761
774
  // Final flush of any remaining lines before sending result
762
- if (stdout.length > flushed) {
763
- try { process.send({ type: 'stdout', id, lines: stdout.slice(flushed) }); } catch {}
764
- flushed = stdout.length;
775
+ if (req.stdout.length > req.flushed) {
776
+ try { process.send({ type: 'stdout', id, lines: req.stdout.slice(req.flushed) }); } catch {}
777
+ req.flushed = req.stdout.length;
765
778
  }
766
779
 
767
- done = true;
780
+ req.done = true;
781
+ req.doneAt = Date.now();
768
782
  process.send({ id, success: true, output: returnValue, stats });
769
783
  } catch (err) {
770
784
  const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };
771
785
 
772
- if (stdout.length > flushed) {
773
- try { process.send({ type: 'stdout', id, lines: stdout.slice(flushed) }); } catch {}
774
- flushed = stdout.length;
786
+ if (req.stdout.length > req.flushed) {
787
+ try { process.send({ type: 'stdout', id, lines: req.stdout.slice(req.flushed) }); } catch {}
788
+ req.flushed = req.stdout.length;
775
789
  }
776
790
 
777
- done = true;
791
+ req.done = true;
792
+ req.doneAt = Date.now();
778
793
  process.send({ id, success: false, error: serializeError(err), stats });
779
794
  }
780
795
  });
@@ -1502,6 +1517,9 @@ var DevRunner = class {
1502
1517
  this.projectRoot = projectRoot;
1503
1518
  this.startOpts = startOpts;
1504
1519
  }
1520
+ appId;
1521
+ projectRoot;
1522
+ startOpts;
1505
1523
  isRunning = false;
1506
1524
  session = null;
1507
1525
  transpiler = null;
@@ -2160,6 +2178,15 @@ var ClientRegistry = class {
2160
2178
  }
2161
2179
  };
2162
2180
 
2181
+ // src/dev/stdin-commands/types.ts
2182
+ var CommandError = class extends Error {
2183
+ constructor(message, code) {
2184
+ super(message);
2185
+ this.code = code;
2186
+ }
2187
+ code;
2188
+ };
2189
+
2163
2190
  // src/dev/proxy/proxy.ts
2164
2191
  var DevProxy = class _DevProxy {
2165
2192
  constructor(upstreamPort, clientContext, appId, bindAddress = "127.0.0.1", browserAgentUrl) {
@@ -2169,6 +2196,11 @@ var DevProxy = class _DevProxy {
2169
2196
  this.bindAddress = bindAddress;
2170
2197
  this.browserAgentUrl = browserAgentUrl;
2171
2198
  }
2199
+ upstreamPort;
2200
+ clientContext;
2201
+ appId;
2202
+ bindAddress;
2203
+ browserAgentUrl;
2172
2204
  server = null;
2173
2205
  proxyPort = null;
2174
2206
  wss = null;
@@ -2202,9 +2234,7 @@ var DevProxy = class _DevProxy {
2202
2234
  dispatchBrowserCommand(steps, timeoutMs = 12e4) {
2203
2235
  if (!this.clients.hasConnected()) {
2204
2236
  return Promise.reject(
2205
- new Error(
2206
- "No browser connected, please refresh the MindStudio preview"
2207
- )
2237
+ new CommandError("No browser connected", "NO_BROWSER")
2208
2238
  );
2209
2239
  }
2210
2240
  const id = randomBytes4(4).toString("hex");
@@ -2229,6 +2259,13 @@ var DevProxy = class _DevProxy {
2229
2259
  * Try to send the next queued command to an available client.
2230
2260
  */
2231
2261
  drainCommandQueue() {
2262
+ if (!this.clients.hasConnected() && this.commandQueue.length > 0) {
2263
+ const orphaned = this.commandQueue.splice(0);
2264
+ for (const cmd of orphaned) {
2265
+ cmd.reject(new CommandError("No browser connected", "NO_BROWSER"));
2266
+ }
2267
+ return;
2268
+ }
2232
2269
  while (this.commandQueue.length > 0) {
2233
2270
  const target = this.clients.getCommandTarget();
2234
2271
  if (!target) break;
@@ -2250,10 +2287,10 @@ var DevProxy = class _DevProxy {
2250
2287
  id,
2251
2288
  pendingCount: this.pendingResults.size
2252
2289
  });
2253
- reject(new Error("Browser command timed out"));
2290
+ reject(new CommandError("Browser command timed out", "BROWSER_TIMEOUT"));
2254
2291
  this.drainCommandQueue();
2255
2292
  }, timeoutMs);
2256
- this.pendingResults.set(id, { resolve: resolve3, timeout, clientId: target.id });
2293
+ this.pendingResults.set(id, { resolve: resolve3, reject, timeout, clientId: target.id });
2257
2294
  target.activeCommandId = id;
2258
2295
  try {
2259
2296
  target.ws.send(JSON.stringify({ type: "command", id, steps }));
@@ -2265,7 +2302,7 @@ var DevProxy = class _DevProxy {
2265
2302
  id,
2266
2303
  clientId: target.id
2267
2304
  });
2268
- reject(new Error("Failed to send command to browser"));
2305
+ reject(new CommandError("Failed to send command to browser", "BROWSER_SEND_FAILED"));
2269
2306
  }
2270
2307
  }
2271
2308
  }
@@ -2358,13 +2395,13 @@ var DevProxy = class _DevProxy {
2358
2395
  this.server = null;
2359
2396
  this.proxyPort = null;
2360
2397
  }
2361
- for (const [id, pending2] of this.pendingResults) {
2398
+ for (const [, pending2] of this.pendingResults) {
2362
2399
  clearTimeout(pending2.timeout);
2363
- pending2.resolve({ id, steps: [], error: "Proxy stopped" });
2400
+ pending2.reject(new CommandError("Proxy stopped", "INFRASTRUCTURE"));
2364
2401
  }
2365
2402
  this.pendingResults.clear();
2366
2403
  for (const queued of this.commandQueue) {
2367
- queued.reject(new Error("Proxy stopped"));
2404
+ queued.reject(new CommandError("Proxy stopped", "INFRASTRUCTURE"));
2368
2405
  }
2369
2406
  this.commandQueue.length = 0;
2370
2407
  }
@@ -2469,13 +2506,14 @@ var DevProxy = class _DevProxy {
2469
2506
  if (clientId) {
2470
2507
  const client = this.clients.remove(clientId);
2471
2508
  if (client?.activeCommandId) {
2472
- log.debug(
2473
- "proxy",
2474
- "Browser disconnected with active command, keeping pending",
2475
- {
2476
- commandId: client.activeCommandId
2509
+ const commandId = client.activeCommandId;
2510
+ log.debug("proxy", "Browser disconnected with active command", { commandId });
2511
+ setTimeout(() => {
2512
+ if (this.pendingResults.has(commandId) && !this.clients.findByCommandId(commandId)) {
2513
+ this.rejectPendingCommand(commandId, new CommandError("Browser disconnected", "BROWSER_DISCONNECTED"));
2514
+ this.drainCommandQueue();
2477
2515
  }
2478
- );
2516
+ }, 1e4);
2479
2517
  }
2480
2518
  }
2481
2519
  });
@@ -2509,13 +2547,13 @@ var DevProxy = class _DevProxy {
2509
2547
  );
2510
2548
  }
2511
2549
  }
2512
- rejectPendingCommand(commandId, reason) {
2550
+ rejectPendingCommand(commandId, error) {
2513
2551
  const pending2 = this.pendingResults.get(commandId);
2514
2552
  if (pending2) {
2515
2553
  clearTimeout(pending2.timeout);
2516
2554
  this.pendingResults.delete(commandId);
2517
- pending2.resolve({ id: commandId, steps: [], error: reason });
2518
- log.warn("proxy", "Pending command rejected", { id: commandId, reason });
2555
+ pending2.reject(error);
2556
+ log.warn("proxy", "Pending command rejected", { id: commandId, code: error.code, reason: error.message });
2519
2557
  this.drainCommandQueue();
2520
2558
  }
2521
2559
  }
@@ -2529,7 +2567,7 @@ var DevProxy = class _DevProxy {
2529
2567
  if (activeCommandId) {
2530
2568
  this.rejectPendingCommand(
2531
2569
  activeCommandId,
2532
- "Browser client timed out"
2570
+ new CommandError("Browser client timed out", "BROWSER_DISCONNECTED")
2533
2571
  );
2534
2572
  }
2535
2573
  }
@@ -3319,6 +3357,7 @@ export {
3319
3357
  DevRunner,
3320
3358
  initBrowserLog,
3321
3359
  closeBrowserLog,
3360
+ CommandError,
3322
3361
  DevProxy,
3323
3362
  detectAppConfig,
3324
3363
  getWebInterfaceConfig,
@@ -3330,4 +3369,4 @@ export {
3330
3369
  watchTableFiles,
3331
3370
  watchConfigFile
3332
3371
  };
3333
- //# sourceMappingURL=chunk-XGPRYHAD.js.map
3372
+ //# sourceMappingURL=chunk-UFGZOWZ6.js.map