fix: include actionable error details

This commit is contained in:
JetSprow
2026-04-29 15:03:00 +10:00
parent d7681240bb
commit df74723b52
28 changed files with 178 additions and 74 deletions

View File

@@ -6,7 +6,7 @@ import { spawn } from "child_process";
function getDatabaseUrl() {
const url = process.env.DATABASE_URL;
if (!url) {
throw new Error("DATABASE_URL 未配置");
throw new Error("数据库备份失败:DATABASE_URL 未配置,无法连接数据库");
}
return url;
}

View File

@@ -5,7 +5,7 @@ import { ThreeXUIAdapter } from "./three-x-ui";
export function createPanelAdapter(server: NodeServer): NodePanelAdapter {
const panelType = server.panelType ?? "3x-ui";
if (panelType !== "3x-ui") {
throw new Error(`Unsupported panel type: ${panelType}`);
throw new Error(`节点 ${server.name} 面板类型不支持:${panelType},当前仅支持 3x-ui`);
}
if (!server.panelUrl || !server.panelUsername || !server.panelPassword) {
throw new Error(`节点 ${server.name} 未配置 3x-ui 面板信息`);

View File

@@ -89,7 +89,7 @@ function errorMessage(error: unknown): string {
}
if (error.message) return error.message;
}
return "未知错误";
return "未知错误:没有收到面板或网络层返回的具体错误内容";
}
async function repairJBoardClientSubIds(

View File

@@ -114,7 +114,7 @@ export class ThreeXUIAdapter implements NodePanelAdapter {
if (!res.ok) {
throw new Error(data.msg || `3x-ui API HTTP ${res.status}`);
}
if (!data.success) throw new Error(data.msg || "3x-ui API error");
if (!data.success) throw new Error(data.msg || `3x-ui 接口返回失败但没有错误消息:${path}`);
return data.obj as T;
}
@@ -182,7 +182,7 @@ export class ThreeXUIAdapter implements NodePanelAdapter {
return false;
}
throw new Error(`登录失败:${lastMessage || "未知错误"}`);
throw new Error(`登录失败:${lastMessage || "面板没有返回具体错误内容,请检查地址、账号密码和面板状态"}`);
}
async getInbounds(): Promise<PanelInbound[]> {
@@ -223,7 +223,7 @@ export class ThreeXUIAdapter implements NodePanelAdapter {
enable: boolean,
): Promise<void> {
const inbound = await this.getInbound(inboundId);
if (!inbound) throw new Error("Inbound not found");
if (!inbound) throw new Error(`3x-ui 入站不存在:面板入站 ID ${inboundId} 未找到,请重新同步节点入站`);
const settings = parseInboundSettings(inbound.settings);
const client = settings.clients?.find((item) => {
@@ -232,7 +232,7 @@ export class ThreeXUIAdapter implements NodePanelAdapter {
|| item.auth === clientCredential
|| item.email === clientCredential;
});
if (!client) throw new Error("Client not found");
if (!client) throw new Error(`3x-ui 客户端不存在:${clientCredential},请重新同步流量或重置订阅访问`);
client.enable = enable;
await this.jsonRequest(`/panel/api/inbounds/updateClient/${encodeURIComponent(this.getClientPrimaryKey(inbound.protocol, client))}`, {
@@ -327,7 +327,7 @@ export class ThreeXUIAdapter implements NodePanelAdapter {
case "hysteria2":
return JSON.stringify({ clients: [{ ...base, auth: params.uuid }] });
default:
throw new Error(`Unsupported protocol: ${params.protocol}`);
throw new Error(`3x-ui 客户端配置失败:不支持的协议 ${params.protocol}`);
}
}
}

View File

@@ -42,7 +42,7 @@ export async function provisionSubscriptionWithDb(
return applyTrafficTopup(order, db);
}
throw new Error(`Unsupported order kind: ${String(order.kind)}`);
throw new Error(`开通订阅失败:不支持的订单类型 ${String(order.kind)}`);
}
async function getNewPurchaseItems(order: PaidOrder, db: DbClient): Promise<NewOrderItem[]> {
@@ -191,7 +191,7 @@ async function applyRenewal(order: PaidOrder, db: DbClient): Promise<string[]> {
throw new Error("续费目标订阅与订单不匹配");
}
if (subscription.status !== "ACTIVE" || subscription.endDate <= new Date()) {
throw new Error("续费失败:目标订阅已过期或不可用");
throw new Error(`续费失败:目标订阅状态为 ${subscription.status},到期时间为 ${subscription.endDate.toISOString()}`);
}
const now = new Date();