@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/error.html +85 -10
- package/dist/index.cjs +99 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +99 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,
|
|
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,
|
|
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
|
-
|
|
28466
|
-
|
|
28467
|
-
|
|
28468
|
-
|
|
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,
|
|
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
|
|
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
|
|
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";
|