@lark-apaas/devtool-kits 1.0.4 → 1.0.5-alpha.2

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/index.d.cts CHANGED
@@ -24,6 +24,12 @@ interface ProxyErrorOptions {
24
24
  maxErrorLogs?: number;
25
25
  /** 日志文件名(默认为 server.log) */
26
26
  logFileName?: string;
27
+ /** 等待服务重启的超时时间(毫秒),默认 5000ms */
28
+ retryTimeout?: number;
29
+ /** 轮询检查服务的间隔时间(毫秒),默认 500ms */
30
+ retryInterval?: number;
31
+ /** 目标服务器地址,用于检查服务是否恢复,格式:http://localhost:3000 */
32
+ target?: string;
27
33
  }
28
34
  /**
29
35
  * HTTP Proxy 错误处理器
@@ -53,7 +59,7 @@ interface ProxyErrorOptions {
53
59
  * });
54
60
  * ```
55
61
  */
56
- declare function handleDevProxyError(err: Error, _req: IncomingMessage, res: ServerResponse, options?: ProxyErrorOptions): void;
62
+ declare function handleDevProxyError(err: Error, req: IncomingMessage, res: ServerResponse, options?: ProxyErrorOptions): void;
57
63
 
58
64
  /**
59
65
  * Shared context passed to all middlewares
package/dist/index.d.ts CHANGED
@@ -24,6 +24,12 @@ interface ProxyErrorOptions {
24
24
  maxErrorLogs?: number;
25
25
  /** 日志文件名(默认为 server.log) */
26
26
  logFileName?: string;
27
+ /** 等待服务重启的超时时间(毫秒),默认 5000ms */
28
+ retryTimeout?: number;
29
+ /** 轮询检查服务的间隔时间(毫秒),默认 500ms */
30
+ retryInterval?: number;
31
+ /** 目标服务器地址,用于检查服务是否恢复,格式:http://localhost:3000 */
32
+ target?: string;
27
33
  }
28
34
  /**
29
35
  * HTTP Proxy 错误处理器
@@ -53,7 +59,7 @@ interface ProxyErrorOptions {
53
59
  * });
54
60
  * ```
55
61
  */
56
- declare function handleDevProxyError(err: Error, _req: IncomingMessage, res: ServerResponse, options?: ProxyErrorOptions): void;
62
+ declare function handleDevProxyError(err: Error, req: IncomingMessage, res: ServerResponse, options?: ProxyErrorOptions): void;
57
63
 
58
64
  /**
59
65
  * Shared context passed to all middlewares
package/dist/index.js CHANGED
@@ -28394,7 +28394,52 @@ import fs2 from "fs";
28394
28394
  import path2 from "path";
28395
28395
  import { createReadStream } from "fs";
28396
28396
  import { createInterface } from "readline";
28397
+ import { connect } from "net";
28397
28398
  var errorHtmlTemplate = null;
28399
+ function isConnectionError(err) {
28400
+ const code = err.code;
28401
+ const connectionErrorCodes = [
28402
+ "ECONNREFUSED",
28403
+ "ECONNRESET",
28404
+ "ETIMEDOUT",
28405
+ "ENOTFOUND",
28406
+ "ENETUNREACH"
28407
+ ];
28408
+ return connectionErrorCodes.includes(code || "");
28409
+ }
28410
+ __name(isConnectionError, "isConnectionError");
28411
+ function checkServiceAvailable(host, port, timeout = 1e3) {
28412
+ return new Promise((resolve) => {
28413
+ const socket = connect(port, host);
28414
+ const timer = setTimeout(() => {
28415
+ socket.destroy();
28416
+ resolve(false);
28417
+ }, timeout);
28418
+ socket.on("connect", () => {
28419
+ clearTimeout(timer);
28420
+ socket.destroy();
28421
+ resolve(true);
28422
+ });
28423
+ socket.on("error", () => {
28424
+ clearTimeout(timer);
28425
+ socket.destroy();
28426
+ resolve(false);
28427
+ });
28428
+ });
28429
+ }
28430
+ __name(checkServiceAvailable, "checkServiceAvailable");
28431
+ async function waitForServiceRecovery(host, port, timeout, interval) {
28432
+ const startTime = Date.now();
28433
+ while (Date.now() - startTime < timeout) {
28434
+ const isAvailable = await checkServiceAvailable(host, port);
28435
+ if (isAvailable) {
28436
+ return true;
28437
+ }
28438
+ await new Promise((resolve) => setTimeout(resolve, interval));
28439
+ }
28440
+ return false;
28441
+ }
28442
+ __name(waitForServiceRecovery, "waitForServiceRecovery");
28398
28443
  function getDirname() {
28399
28444
  return __dirname;
28400
28445
  }
@@ -28423,7 +28468,10 @@ async function readRecentErrorLogs(logDir, maxLogs, fileName) {
28423
28468
  try {
28424
28469
  await fs2.promises.access(logFilePath);
28425
28470
  } catch {
28426
- return [];
28471
+ return {
28472
+ logs: [],
28473
+ hasCompileError: false
28474
+ };
28427
28475
  }
28428
28476
  const allLines = [];
28429
28477
  const stream = createReadStream(logFilePath, {
@@ -28452,20 +28500,26 @@ async function readRecentErrorLogs(logDir, maxLogs, fileName) {
28452
28500
  }
28453
28501
  }
28454
28502
  if (startIndex === -1) {
28455
- return [];
28503
+ return {
28504
+ logs: [],
28505
+ hasCompileError: false
28506
+ };
28456
28507
  }
28457
28508
  let endIndex = allLines.length;
28509
+ let hasCompileError = false;
28458
28510
  for (let i = startIndex; i < allLines.length; i++) {
28459
28511
  if (/Found \d+ errors?\./.test(allLines[i])) {
28460
28512
  endIndex = i + 1;
28513
+ hasCompileError = true;
28461
28514
  break;
28462
28515
  }
28463
28516
  }
28464
28517
  const errorSection = allLines.slice(startIndex, endIndex);
28465
- if (errorSection.length > maxLogs) {
28466
- return errorSection.slice(-maxLogs);
28467
- }
28468
- return errorSection;
28518
+ const logs = errorSection.length > maxLogs ? errorSection.slice(-maxLogs) : errorSection;
28519
+ return {
28520
+ logs,
28521
+ hasCompileError
28522
+ };
28469
28523
  }
28470
28524
  __name(readRecentErrorLogs, "readRecentErrorLogs");
28471
28525
  function injectErrorData(template, errorLogs) {
@@ -28479,8 +28533,8 @@ function injectErrorData(template, errorLogs) {
28479
28533
  ${JSON.stringify(logsText)}`);
28480
28534
  }
28481
28535
  __name(injectErrorData, "injectErrorData");
28482
- function handleDevProxyError(err, _req, res, options) {
28483
- const { logDir = path2.join(process.cwd(), "logs"), maxErrorLogs = 100, logFileName = "server.log" } = options || {};
28536
+ function handleDevProxyError(err, req, res, options) {
28537
+ const { logDir = path2.join(process.cwd(), "logs"), maxErrorLogs = 100, logFileName = "server.log", retryTimeout = 5e3, retryInterval = 500, target } = options || {};
28484
28538
  console.error("[Proxy Error]:", err.message);
28485
28539
  if (res.headersSent) {
28486
28540
  console.error("[Proxy Error]: Headers already sent, cannot send error page");
@@ -28488,7 +28542,31 @@ function handleDevProxyError(err, _req, res, options) {
28488
28542
  }
28489
28543
  (async () => {
28490
28544
  try {
28491
- const errorLogs = await readRecentErrorLogs(logDir, maxErrorLogs, logFileName);
28545
+ const isConnError = isConnectionError(err);
28546
+ const { logs: errorLogs, hasCompileError } = await readRecentErrorLogs(logDir, maxErrorLogs, logFileName);
28547
+ if (isConnError && !hasCompileError && target) {
28548
+ console.log("[Proxy Error]: Connection error without compile errors, possibly server restarting...");
28549
+ let targetUrl = null;
28550
+ try {
28551
+ targetUrl = new URL(target);
28552
+ } catch (e) {
28553
+ console.error("[Proxy Error]: Invalid target URL:", target);
28554
+ }
28555
+ if (targetUrl) {
28556
+ const host = targetUrl.hostname;
28557
+ const port = targetUrl.port ? parseInt(targetUrl.port) : targetUrl.protocol === "https:" ? 443 : 80;
28558
+ console.log(`[Proxy Error]: Waiting for service recovery at ${host}:${port} (timeout: ${retryTimeout}ms)...`);
28559
+ const recovered = await waitForServiceRecovery(host, port, retryTimeout, retryInterval);
28560
+ if (recovered) {
28561
+ console.log("[Proxy Error]: Service recovered, sending redirect");
28562
+ sendSimpleRedirect(req, res);
28563
+ return;
28564
+ }
28565
+ console.log("[Proxy Error]: Service did not recover within timeout, showing error page");
28566
+ }
28567
+ console.log("[Proxy Error]: Falling back to scenario 2 (detailed error page with probe)");
28568
+ }
28569
+ console.log("[Proxy Error]: Compile error or non-connection error, showing error page");
28492
28570
  const template = getErrorHtmlTemplate();
28493
28571
  const html = injectErrorData(template, errorLogs);
28494
28572
  res.writeHead(502, {
@@ -28497,7 +28575,7 @@ function handleDevProxyError(err, _req, res, options) {
28497
28575
  });
28498
28576
  res.end(html);
28499
28577
  } catch (error) {
28500
- console.error("[Proxy Error]: Failed to send error page:", error);
28578
+ console.error("[Proxy Error]: Failed to handle error:", error);
28501
28579
  if (!res.headersSent) {
28502
28580
  res.writeHead(502, {
28503
28581
  "Content-Type": "text/plain; charset=utf-8"
@@ -28508,6 +28586,17 @@ function handleDevProxyError(err, _req, res, options) {
28508
28586
  })();
28509
28587
  }
28510
28588
  __name(handleDevProxyError, "handleDevProxyError");
28589
+ function sendSimpleRedirect(req, res) {
28590
+ if (res.headersSent) return;
28591
+ const originalUrl = req.url || "/";
28592
+ console.log("[Proxy Error]: Sending 302 redirect to", originalUrl);
28593
+ res.writeHead(302, {
28594
+ "Location": originalUrl,
28595
+ "Cache-Control": "no-cache, no-store, must-revalidate"
28596
+ });
28597
+ res.end();
28598
+ }
28599
+ __name(sendSimpleRedirect, "sendSimpleRedirect");
28511
28600
 
28512
28601
  // src/middlewares/index.ts
28513
28602
  import path5 from "path";