@mindstudio-ai/local-model-tunnel 0.5.47 → 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;
@@ -1530,6 +1548,7 @@ var DevRunner = class {
1530
1548
  }
1531
1549
  log.info("runner", "Dev session starting", { appId: this.appId, branch: this.startOpts.branch });
1532
1550
  const session = await startDevSession(this.appId, this.startOpts);
1551
+ session.auth = { userId: null, roleAssignments: [] };
1533
1552
  this.session = session;
1534
1553
  this.transpiler = new Transpiler(this.projectRoot);
1535
1554
  this.isRunning = true;
@@ -2159,6 +2178,15 @@ var ClientRegistry = class {
2159
2178
  }
2160
2179
  };
2161
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
+
2162
2190
  // src/dev/proxy/proxy.ts
2163
2191
  var DevProxy = class _DevProxy {
2164
2192
  constructor(upstreamPort, clientContext, appId, bindAddress = "127.0.0.1", browserAgentUrl) {
@@ -2168,6 +2196,11 @@ var DevProxy = class _DevProxy {
2168
2196
  this.bindAddress = bindAddress;
2169
2197
  this.browserAgentUrl = browserAgentUrl;
2170
2198
  }
2199
+ upstreamPort;
2200
+ clientContext;
2201
+ appId;
2202
+ bindAddress;
2203
+ browserAgentUrl;
2171
2204
  server = null;
2172
2205
  proxyPort = null;
2173
2206
  wss = null;
@@ -2201,9 +2234,7 @@ var DevProxy = class _DevProxy {
2201
2234
  dispatchBrowserCommand(steps, timeoutMs = 12e4) {
2202
2235
  if (!this.clients.hasConnected()) {
2203
2236
  return Promise.reject(
2204
- new Error(
2205
- "No browser connected, please refresh the MindStudio preview"
2206
- )
2237
+ new CommandError("No browser connected", "NO_BROWSER")
2207
2238
  );
2208
2239
  }
2209
2240
  const id = randomBytes4(4).toString("hex");
@@ -2228,6 +2259,13 @@ var DevProxy = class _DevProxy {
2228
2259
  * Try to send the next queued command to an available client.
2229
2260
  */
2230
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
+ }
2231
2269
  while (this.commandQueue.length > 0) {
2232
2270
  const target = this.clients.getCommandTarget();
2233
2271
  if (!target) break;
@@ -2249,10 +2287,10 @@ var DevProxy = class _DevProxy {
2249
2287
  id,
2250
2288
  pendingCount: this.pendingResults.size
2251
2289
  });
2252
- reject(new Error("Browser command timed out"));
2290
+ reject(new CommandError("Browser command timed out", "BROWSER_TIMEOUT"));
2253
2291
  this.drainCommandQueue();
2254
2292
  }, timeoutMs);
2255
- this.pendingResults.set(id, { resolve: resolve3, timeout, clientId: target.id });
2293
+ this.pendingResults.set(id, { resolve: resolve3, reject, timeout, clientId: target.id });
2256
2294
  target.activeCommandId = id;
2257
2295
  try {
2258
2296
  target.ws.send(JSON.stringify({ type: "command", id, steps }));
@@ -2264,7 +2302,7 @@ var DevProxy = class _DevProxy {
2264
2302
  id,
2265
2303
  clientId: target.id
2266
2304
  });
2267
- reject(new Error("Failed to send command to browser"));
2305
+ reject(new CommandError("Failed to send command to browser", "BROWSER_SEND_FAILED"));
2268
2306
  }
2269
2307
  }
2270
2308
  }
@@ -2357,13 +2395,13 @@ var DevProxy = class _DevProxy {
2357
2395
  this.server = null;
2358
2396
  this.proxyPort = null;
2359
2397
  }
2360
- for (const [id, pending2] of this.pendingResults) {
2398
+ for (const [, pending2] of this.pendingResults) {
2361
2399
  clearTimeout(pending2.timeout);
2362
- pending2.resolve({ id, steps: [], error: "Proxy stopped" });
2400
+ pending2.reject(new CommandError("Proxy stopped", "INFRASTRUCTURE"));
2363
2401
  }
2364
2402
  this.pendingResults.clear();
2365
2403
  for (const queued of this.commandQueue) {
2366
- queued.reject(new Error("Proxy stopped"));
2404
+ queued.reject(new CommandError("Proxy stopped", "INFRASTRUCTURE"));
2367
2405
  }
2368
2406
  this.commandQueue.length = 0;
2369
2407
  }
@@ -2468,13 +2506,14 @@ var DevProxy = class _DevProxy {
2468
2506
  if (clientId) {
2469
2507
  const client = this.clients.remove(clientId);
2470
2508
  if (client?.activeCommandId) {
2471
- log.debug(
2472
- "proxy",
2473
- "Browser disconnected with active command, keeping pending",
2474
- {
2475
- 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();
2476
2515
  }
2477
- );
2516
+ }, 1e4);
2478
2517
  }
2479
2518
  }
2480
2519
  });
@@ -2508,13 +2547,13 @@ var DevProxy = class _DevProxy {
2508
2547
  );
2509
2548
  }
2510
2549
  }
2511
- rejectPendingCommand(commandId, reason) {
2550
+ rejectPendingCommand(commandId, error) {
2512
2551
  const pending2 = this.pendingResults.get(commandId);
2513
2552
  if (pending2) {
2514
2553
  clearTimeout(pending2.timeout);
2515
2554
  this.pendingResults.delete(commandId);
2516
- pending2.resolve({ id: commandId, steps: [], error: reason });
2517
- 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 });
2518
2557
  this.drainCommandQueue();
2519
2558
  }
2520
2559
  }
@@ -2528,7 +2567,7 @@ var DevProxy = class _DevProxy {
2528
2567
  if (activeCommandId) {
2529
2568
  this.rejectPendingCommand(
2530
2569
  activeCommandId,
2531
- "Browser client timed out"
2570
+ new CommandError("Browser client timed out", "BROWSER_DISCONNECTED")
2532
2571
  );
2533
2572
  }
2534
2573
  }
@@ -3318,6 +3357,7 @@ export {
3318
3357
  DevRunner,
3319
3358
  initBrowserLog,
3320
3359
  closeBrowserLog,
3360
+ CommandError,
3321
3361
  DevProxy,
3322
3362
  detectAppConfig,
3323
3363
  getWebInterfaceConfig,
@@ -3329,4 +3369,4 @@ export {
3329
3369
  watchTableFiles,
3330
3370
  watchConfigFile
3331
3371
  };
3332
- //# sourceMappingURL=chunk-UT7QCCAJ.js.map
3372
+ //# sourceMappingURL=chunk-UFGZOWZ6.js.map