

























@@ -53,6 +53,93 @@ type ChannelCapabilitiesReport = {
5353diagnostics?: ChannelCapabilitiesDiagnostics;
5454};
555556+const CHANNEL_CAPABILITIES_TIMEOUT_MAX_MS = 30_000;
57+58+type ChannelCapabilitiesStepResult<T> =
59+| { kind: "value"; value: T }
60+| { kind: "error"; error: unknown }
61+| { kind: "timeout" };
62+63+function resolveChannelCapabilitiesTimeoutMs(timeoutMs: number) {
64+return Math.min(timeoutMs, CHANNEL_CAPABILITIES_TIMEOUT_MAX_MS);
65+}
66+67+async function raceChannelCapabilitiesStep<T>(params: {
68+timeoutMs: number;
69+run: () => Promise<T> | T;
70+}): Promise<ChannelCapabilitiesStepResult<T>> {
71+let timeout: ReturnType<typeof setTimeout> | undefined;
72+const timeoutPromise = new Promise<ChannelCapabilitiesStepResult<T>>((resolve) => {
73+timeout = setTimeout(() => resolve({ kind: "timeout" }), params.timeoutMs);
74+timeout.unref?.();
75+});
76+const resultPromise: Promise<ChannelCapabilitiesStepResult<T>> = Promise.resolve()
77+.then(params.run)
78+.then(
79+(value): ChannelCapabilitiesStepResult<T> => ({ kind: "value", value }),
80+(error: unknown): ChannelCapabilitiesStepResult<T> => ({ kind: "error", error }),
81+);
82+const result = await Promise.race([resultPromise, timeoutPromise]);
83+if (timeout) {
84+clearTimeout(timeout);
85+}
86+return result;
87+}
88+89+async function runChannelCapabilitiesProbe(params: {
90+timeoutMs: number;
91+run: () => unknown;
92+}): Promise<unknown> {
93+const result = await raceChannelCapabilitiesStep(params);
94+switch (result.kind) {
95+case "value":
96+return result.value;
97+case "timeout":
98+return {
99+ok: false,
100+timedOut: true,
101+error: `probe timed out after ${params.timeoutMs}ms`,
102+};
103+case "error":
104+return { ok: false, error: formatErrorMessage(result.error) };
105+}
106+return undefined;
107+}
108+109+async function runChannelCapabilitiesDiagnostics(params: {
110+timeoutMs: number;
111+run: () =>
112+| Promise<ChannelCapabilitiesDiagnostics | undefined>
113+| ChannelCapabilitiesDiagnostics
114+| undefined;
115+}): Promise<ChannelCapabilitiesDiagnostics | undefined> {
116+const result = await raceChannelCapabilitiesStep(params);
117+switch (result.kind) {
118+case "value":
119+return result.value;
120+case "timeout":
121+return {
122+lines: [
123+{
124+text: `Diagnostics: timed out after ${params.timeoutMs}ms`,
125+tone: "error",
126+},
127+],
128+details: { timedOut: true },
129+};
130+case "error":
131+return {
132+lines: [
133+{
134+text: `Diagnostics: failed (${formatErrorMessage(result.error)})`,
135+tone: "error",
136+},
137+],
138+};
139+}
140+return undefined;
141+}
142+56143function formatSupport(capabilities?: ChannelCapabilities) {
57144if (!capabilities) {
58145return "unknown";
@@ -157,25 +244,29 @@ async function resolveChannelReports(params: {
157244 : (resolvedAccount as { enabled?: boolean }).enabled !== false;
158245let probe: unknown;
159246if (configured && enabled && plugin.status?.probeAccount) {
160-try {
161-probe = await plugin.status.probeAccount({
162- account: resolvedAccount,
163-timeoutMs,
164-cfg,
165-});
166-} catch (err) {
167-probe = { ok: false, error: formatErrorMessage(err) };
168-}
247+probe = await runChannelCapabilitiesProbe({
248+timeoutMs,
249+run: () =>
250+plugin.status?.probeAccount?.({
251+ account: resolvedAccount,
252+ timeoutMs,
253+ cfg,
254+ }),
255+});
169256}
170257171258const diagnostics =
172-configured && enabled
173- ? await plugin.status?.buildCapabilitiesDiagnostics?.({
174-account: resolvedAccount,
259+configured && enabled && plugin.status?.buildCapabilitiesDiagnostics
260+ ? await runChannelCapabilitiesDiagnostics({
175261 timeoutMs,
176- cfg,
177- probe,
178-target: params.target,
262+run: () =>
263+plugin.status?.buildCapabilitiesDiagnostics?.({
264+account: resolvedAccount,
265+ timeoutMs,
266+ cfg,
267+ probe,
268+target: params.target,
269+}),
179270})
180271 : undefined;
181272const discoveredActions = resolveMessageActionDiscoveryForPlugin({
@@ -221,7 +312,9 @@ export async function channelsCapabilitiesCommand(
221312return;
222313}
223314let cfg = loadedCfg;
224-const timeoutMs = parseTimeoutMsWithFallback(opts.timeout, 10_000);
315+const timeoutMs = resolveChannelCapabilitiesTimeoutMs(
316+parseTimeoutMsWithFallback(opts.timeout, 10_000),
317+);
225318const rawChannel = normalizeLowercaseStringOrEmpty(opts.channel);
226319const rawTarget = normalizeOptionalString(opts.target) ?? "";
227320@@ -350,10 +443,12 @@ export async function channelsCapabilitiesCommand(
350443const enabledLabel = report.enabled === false ? "disabled" : "enabled";
351444lines.push(`Status: ${configuredLabel}, ${enabledLabel}`);
352445}
353-const probeLines =
354-report.plugin.status?.formatCapabilitiesProbe?.({
355-probe: report.probe,
356-}) ?? formatGenericProbeLines(report.probe);
446+const formattedProbeLines = report.plugin.status?.formatCapabilitiesProbe?.({
447+probe: report.probe,
448+});
449+const probeLines = formattedProbeLines?.length
450+ ? formattedProbeLines
451+ : formatGenericProbeLines(report.probe);
357452if (probeLines.length > 0) {
358453lines.push(...probeLines.map(renderDisplayLine));
359454} else if (report.configured && report.enabled) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。