refactor(feishu): split monitor startup and transport concerns

This commit is contained in:
Peter Steinberger
2026-03-02 04:09:19 +00:00
parent c0bf42f2a8
commit f46bd2e0cc
10 changed files with 943 additions and 761 deletions

View File

@@ -1,3 +1,4 @@
import { raceWithTimeoutAndAbort } from "./async.js";
import { createFeishuClient, type FeishuClientCredentials } from "./client.js";
import type { FeishuProbeResult } from "./types.js";
@@ -10,13 +11,37 @@ const PROBE_CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes
const MAX_PROBE_CACHE_SIZE = 64;
export const FEISHU_PROBE_REQUEST_TIMEOUT_MS = 10_000;
export async function probeFeishu(creds?: FeishuClientCredentials): Promise<FeishuProbeResult> {
export type ProbeFeishuOptions = {
timeoutMs?: number;
abortSignal?: AbortSignal;
};
type FeishuBotInfoResponse = {
code: number;
msg?: string;
bot?: { bot_name?: string; open_id?: string };
data?: { bot?: { bot_name?: string; open_id?: string } };
};
export async function probeFeishu(
creds?: FeishuClientCredentials,
options: ProbeFeishuOptions = {},
): Promise<FeishuProbeResult> {
if (!creds?.appId || !creds?.appSecret) {
return {
ok: false,
error: "missing credentials (appId, appSecret)",
};
}
if (options.abortSignal?.aborted) {
return {
ok: false,
appId: creds.appId,
error: "probe aborted",
};
}
const timeoutMs = options.timeoutMs ?? FEISHU_PROBE_REQUEST_TIMEOUT_MS;
// Return cached result if still valid.
// Use accountId when available; otherwise include appSecret prefix so two
@@ -32,12 +57,42 @@ export async function probeFeishu(creds?: FeishuClientCredentials): Promise<Feis
const client = createFeishuClient(creds);
// Use bot/v3/info API to get bot information
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK generic request method
const response = await (client as any).request({
method: "GET",
url: "/open-apis/bot/v3/info",
data: {},
timeout: FEISHU_PROBE_REQUEST_TIMEOUT_MS,
});
const responseResult = await raceWithTimeoutAndAbort<FeishuBotInfoResponse>(
(client as any).request({
method: "GET",
url: "/open-apis/bot/v3/info",
data: {},
timeout: timeoutMs,
}) as Promise<FeishuBotInfoResponse>,
{
timeoutMs,
abortSignal: options.abortSignal,
},
);
if (responseResult.status === "aborted") {
return {
ok: false,
appId: creds.appId,
error: "probe aborted",
};
}
if (responseResult.status === "timeout") {
return {
ok: false,
appId: creds.appId,
error: `probe timed out after ${timeoutMs}ms`,
};
}
const response = responseResult.value;
if (options.abortSignal?.aborted) {
return {
ok: false,
appId: creds.appId,
error: "probe aborted",
};
}
if (response.code !== 0) {
return {