fix: surface actionable channel message errors

This commit is contained in:
xmanrui 2026-08-25 14:54:50 +08:00
parent b42fc411c2
commit 7cbed3aefb
59 changed files with 2405 additions and 607 deletions

View file

@ -415,6 +415,9 @@ var EN = Object.freeze({
"\u6D88\u606F\u901A\u9053": "Message channel",
"\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E": "View message channel details",
"\u6700\u8FD1\u68C0\u67E5": "Last checked",
"\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25": "Latest message failed",
"\u9519\u8BEF\u7801": "Code",
"\u53C2\u8003\u53F7": "Reference",
"\u5F53\u524D\u5DE5\u4F5C\u533A": "Current workspace",
"\u9009\u62E9\u76EE\u5F55": "Choose folder",
"\u9009\u62E9\u673A\u5668\u4EBA\u5DE5\u4F5C\u533A\u76EE\u5F55": "Select bot workspace folder",
@ -873,72 +876,72 @@ function isEnglish() {
function channelName(value) {
return localizeText(value);
}
function translateDynamic(text5) {
let match = /^(\d+) \/ (\d+) 在线$/.exec(text5);
function translateDynamic(text6) {
let match = /^(\d+) \/ (\d+) 在线$/.exec(text6);
if (match) return `${match[1]}/${match[2]} online`;
match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text5);
match = /^已接入 (\d+) 个机器人,其中 (\d+) 个在线$/.exec(text6);
if (match) return `${match[2]} of ${match[1]} bots online`;
match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text5);
match = /^正在读取\s*(.+?)\s*机器人状态…$/.exec(text6);
if (match) return `Loading ${channelName(match[1])} bot status\u2026`;
match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text5);
match = /^无法读取\s*(.+?)\s*机器人状态$/.exec(text6);
if (match) return `Could not load ${channelName(match[1])} bot status`;
match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text5);
match = /^尚未接入\s*(.+?)\s*机器人$/.exec(text6);
if (match) return `No ${channelName(match[1])} bot connected yet`;
match = /^已接入的\s*(.+?)\s*机器人$/.exec(text5);
match = /^已接入的\s*(.+?)\s*机器人$/.exec(text6);
if (match) return `Connected ${channelName(match[1])} bots`;
match = /^手动接入(.+)机器人$/.exec(text5);
match = /^手动接入(.+)机器人$/.exec(text6);
if (match) return `Connect ${channelName(match[1])} bot manually`;
match = /^(.+) 设置$/.exec(text5);
match = /^(.+) 设置$/.exec(text6);
if (match) return `${channelName(match[1])} settings`;
match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text5);
match = /^从 DeepSeek Harness 移除“(.+)”?$/.exec(text6);
if (match) return `Remove \u201C${match[1]}\u201D from DeepSeek Harness?`;
match = /^从 DeepSeek Harness 移除(.+)$/.exec(text5);
match = /^从 DeepSeek Harness 移除(.+)$/.exec(text6);
if (match) return `Remove ${match[1]} from DeepSeek Harness`;
match = /^(.+)的飞书授权流程$/.exec(text5);
match = /^(.+)的飞书授权流程$/.exec(text6);
if (match) return `Feishu authorization flow for ${match[1]}`;
match = /^用于为(.+)补全权限与回调的一次性授权二维码$/.exec(text5);
match = /^用于为(.+)补全权限与回调的一次性授权二维码$/.exec(text6);
if (match) return `One-time QR code for completing permissions and the callback for ${match[1]}`;
match = /^用于为(.+)开通群消息权限的一次性授权二维码$/.exec(text5);
match = /^用于为(.+)开通群消息权限的一次性授权二维码$/.exec(text6);
if (match) return `One-time QR code for granting group-message permission to ${match[1]}`;
match = /^正在为「(.+)」补全权限与回调$/.exec(text5);
match = /^正在为「(.+)」补全权限与回调$/.exec(text6);
if (match) return `Completing permissions and the callback for \u201C${match[1]}\u201D`;
match = /^正在为「(.+)」开通群消息权限$/.exec(text5);
match = /^正在为「(.+)」开通群消息权限$/.exec(text6);
if (match) return `Granting group-message permission to \u201C${match[1]}\u201D`;
match = /^为(.+)补全权限与回调$/.exec(text5);
match = /^为(.+)补全权限与回调$/.exec(text6);
if (match) return `Complete permissions and the callback for ${match[1]}`;
match = /^(.+)的权限补全二维码已生成,请使用飞书扫码。$/.exec(text5);
match = /^(.+)的权限补全二维码已生成,请使用飞书扫码。$/.exec(text6);
if (match) return `Permission-completion QR code generated for ${match[1]}. Scan it with Feishu.`;
match = /^(.+)的群消息权限二维码已生成,请使用飞书确认。$/.exec(text5);
match = /^(.+)的群消息权限二维码已生成,请使用飞书确认。$/.exec(text6);
if (match) return `Group-message permission QR code generated for ${match[1]}. Confirm it with Feishu.`;
match = /^(.+)的权限与回调已补全。$/.exec(text5);
match = /^(.+)的权限与回调已补全。$/.exec(text6);
if (match) return `Permissions and the callback completed for ${match[1]}.`;
match = /^(.+)已开通群消息权限,并启用“响应所有群消息”。$/.exec(text5);
match = /^(.+)已开通群消息权限,并启用“响应所有群消息”。$/.exec(text6);
if (match) return `${match[1]} now has group-message permission and \u201CRespond to all group messages\u201D is enabled.`;
match = /^(检查连接|重试连接)(.+)$/.exec(text5);
match = /^(检查连接|重试连接)(.+)$/.exec(text6);
if (match) return `${localizeText(match[1])} ${match[2]}`;
match = /^移除(.+)$/.exec(text5);
match = /^移除(.+)$/.exec(text6);
if (match) return `Remove ${match[1]}`;
match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text5);
match = /^这会停止消息连接,并删除本机保存的 (.+)、机器人配置及会话映射。(.+)中的机器人不会被自动删除。$/.exec(text6);
if (match) {
return `This stops the message connection and removes the locally stored ${localizeText(match[1])}, bot configuration, and session mappings. The bot in ${localizeText(match[2])} is not deleted.`;
}
match = /^二维码剩余 (.+)$/.exec(text5);
match = /^二维码剩余 (.+)$/.exec(text6);
if (match) return `QR code expires in ${match[1]}`;
match = /^最近一条消息处理失败:(.+)$/.exec(text5);
match = /^最近一条消息处理失败:(.+)$/.exec(text6);
if (match) return `Latest message failed: ${localizeText(match[1])}`;
match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text5);
match = /^图片下载失败(HTTP (.+)),请重新发送后再试。$/.exec(text6);
if (match) return `The image download failed (HTTP ${match[1]}). Send it again.`;
match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text5);
match = /^一次最多只能处理 (\d+) 张图片。$/.exec(text6);
if (match) return `A message can contain at most ${match[1]} images.`;
match = /^状态刷新失败:(.+)$/.exec(text5);
match = /^状态刷新失败:(.+)$/.exec(text6);
if (match) return `Status refresh failed: ${match[1]}`;
match = /^状态自动刷新失败:(.+)$/.exec(text5);
match = /^状态自动刷新失败:(.+)$/.exec(text6);
if (match) return `Automatic status refresh failed: ${match[1]}`;
match = /^操作失败:(.+)$/.exec(text5);
match = /^操作失败:(.+)$/.exec(text6);
if (match) return `Operation failed: ${match[1]}`;
match = /^连接检查失败:(.+)$/.exec(text5);
match = /^连接检查失败:(.+)$/.exec(text6);
if (match) return `Connection check failed: ${match[1]}`;
match = /^移除失败:(.+)$/.exec(text5);
match = /^移除失败:(.+)$/.exec(text6);
if (match) return `Removal failed: ${match[1]}`;
const phrases = [
["\u4F01\u4E1A\u5FAE\u4FE1", "WeCom"],
@ -975,7 +978,7 @@ function translateDynamic(text5) {
["\u8FDE\u63A5\u72B6\u6001", "connection status"],
["\u4E8C\u7EF4\u7801", "QR code"]
];
let output = text5;
let output = text6;
for (const [source, target] of phrases) output = output.replaceAll(source, target);
return output;
}
@ -1123,6 +1126,22 @@ function AgentPresetEditor({ agentPreset = "", disabled = false, onSave }) {
);
}
// plugin-src/client/last-message-error.js
function text(value, maxLength) {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed ? trimmed.slice(0, maxLength) : null;
}
function normalizeLastMessageError(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
const code = text(value.code, 64);
const reason = text(value.reason, 64);
const message = text(value.message, 500);
const referenceId = text(value.referenceId, 40);
const at = Number.isFinite(value.at) ? value.at : null;
return code && reason && message && referenceId && at !== null ? { code, reason, message, referenceId, at } : null;
}
// plugin-src/client/channels/dingtalk/api.js
var DINGTALK_RPC_CHANNEL = "/dingtalk";
var DINGTALK_ENDPOINTS = Object.freeze({
@ -1277,6 +1296,7 @@ function normalizeBot(value) {
messagesReceived: nonNegativeInteger(stats.messagesReceived),
messagesReplied: nonNegativeInteger(stats.messagesReplied)
},
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: normalizeError(value.error, "DINGTALK_ACCOUNT_ERROR", "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA") ?? null
};
}
@ -1822,6 +1842,19 @@ function useWorkspaceSnapshotFence() {
// plugin-src/client/channel-card-meta.js
var React8 = __toESM(require("react"), 1);
function messageErrorTime(value) {
try {
return new Intl.DateTimeFormat(isEnglish() ? "en-US" : "zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit"
}).format(new Date(value));
} catch {
return null;
}
}
function ChannelListHeading({ className = "", id: id5, title, connectionLabel }) {
const helpId = React8.useId();
return h2(
@ -1886,6 +1919,32 @@ function BotStatusMeta({
)
);
}
function LastMessageErrorSummary({ className = "", error }) {
if (!error) return null;
const occurredAt = messageErrorTime(error.at);
return h2(
"div",
{
className: `${className} dim-cardSummary`.trim(),
role: "status"
},
h2("strong", null, "\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25"),
"\uFF1A",
h2("span", null, error.message),
"\uFF08",
h2("span", null, "\u9519\u8BEF\u7801"),
` ${error.code} \xB7 `,
h2("span", null, "\u53C2\u8003\u53F7"),
` ${error.referenceId}`,
occurredAt ? h2(
React8.Fragment,
null,
" \xB7 ",
h2("time", { dateTime: new Date(error.at).toISOString() }, occurredAt)
) : null,
"\uFF09"
);
}
// plugin-src/client/channels/dingtalk/styles.js
var DINGTALK_STYLE_ID = "xmanrui-dsh-dingtalk-settings";
@ -2360,6 +2419,10 @@ function AccountCard({
)
),
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
account.lastMessageError ? h2(LastMessageErrorSummary, {
className: "ddt-summary",
error: account.lastMessageError
}) : null,
feedback ? h2("div", {
className: "ddt-summary dim-cardFeedback",
role: "status"
@ -2940,11 +3003,11 @@ var ACCOUNT_STATES2 = /* @__PURE__ */ new Set(["connected", "connecting", "offli
function isRecord2(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function text(value, fallback, max = 240) {
function text2(value, fallback, max = 240) {
return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
}
function id(value) {
const result = text(value, "", 128);
const result = text2(value, "", 128);
return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
}
function timestamp2(value) {
@ -2968,8 +3031,8 @@ function createTokenChannelApi(channel4, connectionSummary, {
throw new Error(`${channel4} \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94`);
}
if (!result.ok) {
const error = new Error(text(result.error?.message, `${channel4} \u64CD\u4F5C\u5931\u8D25`));
error.code = text(result.error?.code, `${channel4.toUpperCase()}_RPC_ERROR`, 80);
const error = new Error(text2(result.error?.message, `${channel4} \u64CD\u4F5C\u5931\u8D25`));
error.code = text2(result.error?.code, `${channel4.toUpperCase()}_RPC_ERROR`, 80);
throw error;
}
return result.value;
@ -2983,23 +3046,24 @@ function createTokenChannelApi(channel4, connectionSummary, {
botId: id(value.botId),
connected,
state: connected ? "connected" : state,
workspace: text(value.workspace, "", 4096),
workspace: text2(value.workspace, "", 4096),
agentPreset: normalizeAgentPresetId(value.agentPreset),
bot: {
name: text(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
username: text(value.bot?.username, "", 100),
idMasked: text(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
name: text2(value.bot?.name, `${channel4}\u673A\u5668\u4EBA`, 100),
username: text2(value.bot?.username, "", 100),
idMasked: text2(value.bot?.idMasked, "\u673A\u5668\u4EBA\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
},
health: {
summary: text(
summary: text2(
value.health?.summary,
connected ? `${channel4}${connectionSummary}\u8FD0\u884C\u6B63\u5E38` : `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`
),
lastCheckedAt: timestamp2(value.health?.lastCheckedAt)
},
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: isRecord2(value.error) ? {
code: text(value.error.code, `${channel4.toUpperCase()}_ACCOUNT_ERROR`, 80),
message: text(value.error.message, `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
code: text2(value.error.code, `${channel4.toUpperCase()}_ACCOUNT_ERROR`, 80),
message: text2(value.error.message, `${channel4}\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA`)
} : null,
...isRecord2(extension) ? extension : {}
};
@ -3018,8 +3082,8 @@ function createTokenChannelApi(channel4, connectionSummary, {
};
};
const presentError10 = (error) => ({
code: text(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
message: text(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
code: text2(error?.code, `${channel4.toUpperCase()}_ERROR`, 80),
message: text2(error?.message, `${channel4}\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`)
});
return Object.freeze({ unwrapRpcResult: unwrapRpcResult10, normalizeSnapshot: normalizeSnapshot9, presentError: presentError10 });
}
@ -3162,6 +3226,10 @@ function createTokenChannelSettings(definition) {
}, "\u79FB\u9664\u63A5\u5165")
),
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
account.lastMessageError ? h2(LastMessageErrorSummary, {
className: "ddt-summary",
error: account.lastMessageError
}) : null,
testNotice ? h2("div", {
className: "ddt-summary dim-cardFeedback",
role: "status"
@ -3693,6 +3761,7 @@ function normalizeBotConnection(value, fallbackBotId) {
groupMessagePermissionGranted: value.groupMessagePermissionGranted === true,
bot: normalizeBot2(value.bot),
health: normalizeHealth(value.health, connected),
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: normalizeError2(value.error)
};
}
@ -3707,6 +3776,7 @@ function normalizeBotsSnapshot(value) {
configured: true,
bot: value.bot,
health: value.health,
lastMessageError: value.lastMessageError,
error: value.error
}];
}
@ -5062,6 +5132,10 @@ function BotCard({
{ className: "bxf-healthSummary dim-cardSummary", "data-error": actionError || connection.error ? "true" : void 0 },
summary
) : null,
connection.lastMessageError ? h2(LastMessageErrorSummary, {
className: "bxf-healthSummary",
error: connection.lastMessageError
}) : null,
testNotice ? h2("div", {
className: "bxf-healthSummary dim-cardFeedback",
role: "status"
@ -5869,11 +5943,11 @@ var QR_DATA_URL2 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
function isRecord4(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function text2(value, fallback, max = 240) {
function text3(value, fallback, max = 240) {
return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
}
function id2(value) {
const result = text2(value, "", 128);
const result = text3(value, "", 128);
return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
}
function timestamp3(value) {
@ -5884,8 +5958,8 @@ function timestamp3(value) {
function unwrapRpcResult4(result) {
if (!isRecord4(result) || typeof result.ok !== "boolean") throw new Error("QQ \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
if (!result.ok) {
const error = new Error(text2(result.error?.message, "QQ \u64CD\u4F5C\u5931\u8D25"));
error.code = text2(result.error?.code, "QQ_RPC_ERROR", 80);
const error = new Error(text3(result.error?.message, "QQ \u64CD\u4F5C\u5931\u8D25"));
error.code = text3(result.error?.code, "QQ_RPC_ERROR", 80);
throw error;
}
return result.value;
@ -5898,7 +5972,7 @@ function normalizeProvisioning3(value, now = Date.now()) {
if (!isRecord4(source)) throw new Error("QQ \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
const attemptId = id2(source.attemptId);
if (!attemptId) throw new Error("QQ \u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
const reported = text2(source.status, "failed", 32);
const reported = text3(source.status, "failed", 32);
const result = {
attemptId,
status: PROVISION_STATES2.has(reported) ? reported : "failed",
@ -5910,8 +5984,8 @@ function normalizeProvisioning3(value, now = Date.now()) {
if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
if (id2(source.botId)) result.botId = id2(source.botId);
if (isRecord4(source.error)) result.error = {
code: text2(source.error.code, "QQ_PROVISION_FAILED", 80),
message: text2(source.error.message, "QQ \u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
code: text3(source.error.code, "QQ_PROVISION_FAILED", 80),
message: text3(source.error.message, "QQ \u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
};
return result;
}
@ -5923,26 +5997,27 @@ function normalizeBot3(value) {
botId: id2(value.botId),
connected,
state: connected ? "connected" : state,
workspace: text2(value.workspace, "", 4096),
workspace: text3(value.workspace, "", 4096),
agentPreset: normalizeAgentPresetId(value.agentPreset),
bot: {
name: text2(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
appIdMasked: text2(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
name: text3(value.bot?.name, "QQ\u673A\u5668\u4EBA", 100),
appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
},
health: {
summary: text2(value.health?.summary, connected ? "QQ WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
summary: text3(value.health?.summary, connected ? "QQ WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
lastCheckedAt: timestamp3(value.health?.lastCheckedAt)
},
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: isRecord4(value.error) ? {
code: text2(value.error.code, "QQ_ACCOUNT_ERROR", 80),
message: text2(value.error.message, "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
code: text3(value.error.code, "QQ_ACCOUNT_ERROR", 80),
message: text3(value.error.message, "QQ \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
} : null
};
}
function normalizeTestMessage2(value) {
if (!isRecord4(value) || typeof value.sent !== "boolean") return void 0;
if (value.sent) return { sent: true };
const code = text2(value.code, "test-message-failed", 80);
const code = text3(value.code, "test-message-failed", 80);
return {
sent: false,
code: TEST_MESSAGE_CODES.has(code) ? code : "test-message-failed"
@ -5971,8 +6046,8 @@ function connectionTestFeedback2(result) {
}
function presentError4(error) {
return {
code: text2(error?.code, "QQ_ERROR", 80),
message: text2(error?.message, "QQ \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
code: text3(error?.code, "QQ_ERROR", 80),
message: text3(error?.message, "QQ \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
};
}
function formatRemaining3(milliseconds) {
@ -6280,6 +6355,10 @@ function AccountCard2({
h2(Button7, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
),
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
account.lastMessageError ? h2(LastMessageErrorSummary, {
className: "ddt-summary",
error: account.lastMessageError
}) : null,
feedback ? h2("div", {
className: "ddt-summary dim-cardFeedback",
role: "status",
@ -7419,11 +7498,11 @@ var QR_DATA_URL3 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
function isRecord5(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function text3(value, fallback, max = 240) {
function text4(value, fallback, max = 240) {
return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
}
function id3(value) {
const result = text3(value, "", 128);
const result = text4(value, "", 128);
return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
}
function timestamp4(value) {
@ -7441,8 +7520,8 @@ function normalizeTestMessage3(value) {
function unwrapRpcResult7(result) {
if (!isRecord5(result) || typeof result.ok !== "boolean") throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
if (!result.ok) {
const error = new Error(text3(result.error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
error.code = text3(result.error?.code, "WECOM_RPC_ERROR", 80);
const error = new Error(text4(result.error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25"));
error.code = text4(result.error?.code, "WECOM_RPC_ERROR", 80);
throw error;
}
return result.value;
@ -7455,7 +7534,7 @@ function normalizeProvisioning4(value, now = Date.now()) {
if (!isRecord5(source)) throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6");
const attemptId = id3(source.attemptId);
if (!attemptId) throw new Error("\u4F01\u4E1A\u5FAE\u4FE1\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1");
const reported = text3(source.status, "failed", 32);
const reported = text4(source.status, "failed", 32);
const result = {
attemptId,
status: PROVISION_STATES3.has(reported) ? reported : "failed",
@ -7467,8 +7546,8 @@ function normalizeProvisioning4(value, now = Date.now()) {
if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
if (id3(source.botId)) result.botId = id3(source.botId);
if (isRecord5(source.error)) result.error = {
code: text3(source.error.code, "WECOM_PROVISION_FAILED", 80),
message: text3(source.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
code: text4(source.error.code, "WECOM_PROVISION_FAILED", 80),
message: text4(source.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
};
return result;
}
@ -7480,19 +7559,20 @@ function normalizeBot4(value) {
botId: id3(value.botId),
connected,
state: connected ? "connected" : state,
workspace: text3(value.workspace, "", 4096),
workspace: text4(value.workspace, "", 4096),
agentPreset: normalizeAgentPresetId(value.agentPreset),
bot: {
name: text3(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
appIdMasked: text3(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
name: text4(value.bot?.name, "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA", 100),
appIdMasked: text4(value.bot?.appIdMasked, "\u5E94\u7528\u6807\u8BC6\u5DF2\u5B89\u5168\u4FDD\u5B58", 140)
},
health: {
summary: text3(value.health?.summary, connected ? "\u4F01\u4E1A\u5FAE\u4FE1 WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
summary: text4(value.health?.summary, connected ? "\u4F01\u4E1A\u5FAE\u4FE1 WebSocket \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
lastCheckedAt: timestamp4(value.health?.lastCheckedAt)
},
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: isRecord5(value.error) ? {
code: text3(value.error.code, "WECOM_ACCOUNT_ERROR", 80),
message: text3(value.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
code: text4(value.error.code, "WECOM_ACCOUNT_ERROR", 80),
message: text4(value.error.message, "\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
} : null
};
}
@ -7511,8 +7591,8 @@ function normalizeSnapshot6(value) {
}
function presentError7(error) {
return {
code: text3(error?.code, "WECOM_ERROR", 80),
message: text3(error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
code: text4(error?.code, "WECOM_ERROR", 80),
message: text4(error?.message, "\u4F01\u4E1A\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
};
}
function formatRemaining4(milliseconds) {
@ -7820,6 +7900,10 @@ function AccountCard3({
h2(Button10, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
),
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
account.lastMessageError ? h2(LastMessageErrorSummary, {
className: "ddt-summary",
error: account.lastMessageError
}) : null,
feedback ? h2("div", {
className: "ddt-summary dim-cardFeedback",
role: "status",
@ -8221,14 +8305,6 @@ function normalizeTestMessage4(value) {
const code = value.code === "test-target-unavailable" ? "test-target-unavailable" : "test-message-failed";
return { sent: false, code };
}
function normalizeMessageError(value) {
if (!isRecord6(value)) return null;
const code = string(value.code).slice(0, 64);
const reason = string(value.reason).slice(0, 128);
const message = string(value.message).slice(0, 500);
const at = timestamp5(value.at);
return code && reason && message && at !== null ? { code, reason, message, at } : null;
}
function unwrapRpcResult8(result) {
if (!isRecord6(result) || typeof result.ok !== "boolean") {
throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
@ -8303,7 +8379,7 @@ function normalizeBot5(value) {
messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0),
messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0)
},
lastMessageError: normalizeMessageError(value.lastMessageError),
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: isRecord6(value.error) ? {
code: string(value.error.code, "WEIXIN_ACCOUNT_ERROR"),
message: string(value.error.message, "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA")
@ -8764,10 +8840,10 @@ function AccountCard4({
h2(Button12, { className: "dim-cardAction", kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165")
),
summary ? h2("div", { className: "dxw-summary dim-cardSummary" }, summary) : null,
account.lastMessageError ? h2("div", {
className: "dxw-summary dim-cardSummary",
role: "status"
}, `\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25\uFF1A${account.lastMessageError.message}`) : null,
account.lastMessageError ? h2(LastMessageErrorSummary, {
className: "dxw-summary",
error: account.lastMessageError
}) : null,
feedback ? h2("div", {
className: "dxw-summary dim-cardFeedback",
role: "status",
@ -9262,11 +9338,11 @@ var QR_DATA_URL4 = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i;
function isRecord7(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function text4(value, fallback, max = 240) {
function text5(value, fallback, max = 240) {
return typeof value === "string" && value.trim() ? value.trim().slice(0, max) : fallback;
}
function id4(value) {
const result = text4(value, "", 128);
const result = text5(value, "", 128);
return /^[a-z\d_-]+$/i.test(result) ? result : void 0;
}
function timestamp6(value) {
@ -9279,8 +9355,8 @@ function unwrapRpcResult9(result) {
throw new Error("WhatsApp \u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94");
}
if (!result.ok) {
const error = new Error(text4(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
error.code = text4(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
const error = new Error(text5(result.error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25"));
error.code = text5(result.error?.code, "WHATSAPP_RPC_ERROR", 80);
throw error;
}
return result.value;
@ -9293,7 +9369,7 @@ function normalizeProvisioning6(value, now = Date.now()) {
if (!isRecord7(source)) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u8FDB\u5EA6");
const attemptId = id4(source.attemptId);
if (!attemptId) throw new Error("WhatsApp \u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u626B\u7801\u4EFB\u52A1");
const reported = text4(source.status, "failed", 32);
const reported = text5(source.status, "failed", 32);
const result = {
attemptId,
status: PROVISION_STATES5.has(reported) ? reported : "failed",
@ -9305,8 +9381,8 @@ function normalizeProvisioning6(value, now = Date.now()) {
if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl;
if (id4(source.botId)) result.botId = id4(source.botId);
if (isRecord7(source.error)) result.error = {
code: text4(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
message: text4(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
code: text5(source.error.code, "WHATSAPP_PROVISION_FAILED", 80),
message: text5(source.error.message, "WhatsApp \u6CA1\u6709\u63A5\u5165\u5B8C\u6210")
};
return result;
}
@ -9318,7 +9394,7 @@ function normalizeBot6(value) {
botId: id4(value.botId),
connected,
state: connected ? "connected" : state,
workspace: text4(value.workspace, "", 4096),
workspace: text5(value.workspace, "", 4096),
agentPreset: normalizeAgentPresetId(value.agentPreset),
accessPolicy: {
accessMode: ["self-only", "private-allowlist", "open"].includes(
@ -9327,16 +9403,17 @@ function normalizeBot6(value) {
allowedNumbers: Array.isArray(value.accessPolicy?.allowedNumbers) ? [...new Set(value.accessPolicy.allowedNumbers.filter((entry) => typeof entry === "string" && /^[1-9]\d{4,14}$/.test(entry)))] : []
},
bot: {
name: text4(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
idMasked: text4(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
name: text5(value.bot?.name, "WhatsApp\u673A\u5668\u4EBA", 100),
idMasked: text5(value.bot?.idMasked, "WhatsApp\u8D26\u53F7", 140)
},
health: {
summary: text4(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
summary: text5(value.health?.summary, connected ? "WhatsApp Web \u5173\u8054\u8BBE\u5907\u8FD0\u884C\u6B63\u5E38" : "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"),
lastCheckedAt: timestamp6(value.health?.lastCheckedAt)
},
lastMessageError: normalizeLastMessageError(value.lastMessageError),
error: isRecord7(value.error) ? {
code: text4(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
message: text4(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
code: text5(value.error.code, "WHATSAPP_ACCOUNT_ERROR", 80),
message: text5(value.error.message, "WhatsApp \u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA")
} : null
};
}
@ -9356,8 +9433,8 @@ function normalizeSnapshot8(value) {
}
function presentError9(error) {
return {
code: text4(error?.code, "WHATSAPP_ERROR", 80),
message: text4(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
code: text5(error?.code, "WHATSAPP_ERROR", 80),
message: text5(error?.message, "WhatsApp \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5")
};
}
function formatRemaining6(milliseconds) {
@ -9867,6 +9944,10 @@ function WhatsappAccountCard({
}, "\u79FB\u9664\u63A5\u5165")
),
summary ? h2("div", { className: "ddt-summary dim-cardSummary" }, summary) : null,
account.lastMessageError ? h2(LastMessageErrorSummary, {
className: "ddt-summary",
error: account.lastMessageError
}) : null,
testNotice ? h2("div", {
className: "ddt-summary dim-cardFeedback",
role: "status"