refactor: deduplicate shared helpers and test setup

This commit is contained in:
Peter Steinberger
2026-02-23 20:40:38 +00:00
parent 1f5e6444ee
commit 75423a00d6
33 changed files with 999 additions and 1112 deletions

View File

@@ -7,7 +7,7 @@ import { createFeishuClient } from "./client.js";
import { normalizeFeishuExternalKey } from "./external-keys.js";
import { getFeishuRuntime } from "./runtime.js";
import { assertFeishuMessageApiSuccess, toFeishuSendResult } from "./send-result.js";
import { resolveReceiveIdType, normalizeFeishuTarget } from "./targets.js";
import { resolveFeishuSendTarget } from "./send-target.js";
export type DownloadImageResult = {
buffer: Buffer;
@@ -268,18 +268,11 @@ export async function sendImageFeishu(params: {
accountId?: string;
}): Promise<SendMediaResult> {
const { cfg, to, imageKey, replyToMessageId, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${to}`);
}
const receiveIdType = resolveReceiveIdType(receiveId);
const { client, receiveId, receiveIdType } = resolveFeishuSendTarget({
cfg,
to,
accountId,
});
const content = JSON.stringify({ image_key: imageKey });
if (replyToMessageId) {
@@ -320,18 +313,11 @@ export async function sendFileFeishu(params: {
}): Promise<SendMediaResult> {
const { cfg, to, fileKey, replyToMessageId, accountId } = params;
const msgType = params.msgType ?? "file";
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${to}`);
}
const receiveIdType = resolveReceiveIdType(receiveId);
const { client, receiveId, receiveIdType } = resolveFeishuSendTarget({
cfg,
to,
accountId,
});
const content = JSON.stringify({ file_key: fileKey });
if (replyToMessageId) {

View File

@@ -0,0 +1,25 @@
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
import { resolveFeishuAccount } from "./accounts.js";
import { createFeishuClient } from "./client.js";
import { resolveReceiveIdType, normalizeFeishuTarget } from "./targets.js";
export function resolveFeishuSendTarget(params: {
cfg: ClawdbotConfig;
to: string;
accountId?: string;
}) {
const account = resolveFeishuAccount({ cfg: params.cfg, accountId: params.accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(params.to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${params.to}`);
}
return {
client,
receiveId,
receiveIdType: resolveReceiveIdType(receiveId),
};
}

View File

@@ -5,8 +5,8 @@ import type { MentionTarget } from "./mention.js";
import { buildMentionedMessage, buildMentionedCardContent } from "./mention.js";
import { getFeishuRuntime } from "./runtime.js";
import { assertFeishuMessageApiSuccess, toFeishuSendResult } from "./send-result.js";
import { resolveReceiveIdType, normalizeFeishuTarget } from "./targets.js";
import type { FeishuSendResult, ResolvedFeishuAccount } from "./types.js";
import { resolveFeishuSendTarget } from "./send-target.js";
import type { FeishuSendResult } from "./types.js";
export type FeishuMessageInfo = {
messageId: string;
@@ -128,18 +128,7 @@ export async function sendMessageFeishu(
params: SendFeishuMessageParams,
): Promise<FeishuSendResult> {
const { cfg, to, text, replyToMessageId, mentions, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${to}`);
}
const receiveIdType = resolveReceiveIdType(receiveId);
const { client, receiveId, receiveIdType } = resolveFeishuSendTarget({ cfg, to, accountId });
const tableMode = getFeishuRuntime().channel.text.resolveMarkdownTableMode({
cfg,
channel: "feishu",
@@ -188,18 +177,7 @@ export type SendFeishuCardParams = {
export async function sendCardFeishu(params: SendFeishuCardParams): Promise<FeishuSendResult> {
const { cfg, to, card, replyToMessageId, accountId } = params;
const account = resolveFeishuAccount({ cfg, accountId });
if (!account.configured) {
throw new Error(`Feishu account "${account.accountId}" not configured`);
}
const client = createFeishuClient(account);
const receiveId = normalizeFeishuTarget(to);
if (!receiveId) {
throw new Error(`Invalid Feishu target: ${to}`);
}
const receiveIdType = resolveReceiveIdType(receiveId);
const { client, receiveId, receiveIdType } = resolveFeishuSendTarget({ cfg, to, accountId });
const content = JSON.stringify(card);
if (replyToMessageId) {

View File

@@ -132,6 +132,26 @@ export class FeishuStreamingSession {
this.log?.(`Started streaming: cardId=${cardId}, messageId=${sendRes.data.message_id}`);
}
private async updateCardContent(text: string, onError?: (error: unknown) => void): Promise<void> {
if (!this.state) {
return;
}
const apiBase = resolveApiBase(this.creds.domain);
this.state.sequence += 1;
await fetch(`${apiBase}/cardkit/v1/cards/${this.state.cardId}/elements/content/content`, {
method: "PUT",
headers: {
Authorization: `Bearer ${await getToken(this.creds)}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: text,
sequence: this.state.sequence,
uuid: `s_${this.state.cardId}_${this.state.sequence}`,
}),
}).catch((error) => onError?.(error));
}
async update(text: string): Promise<void> {
if (!this.state || this.closed) {
return;
@@ -150,20 +170,7 @@ export class FeishuStreamingSession {
return;
}
this.state.currentText = text;
this.state.sequence += 1;
const apiBase = resolveApiBase(this.creds.domain);
await fetch(`${apiBase}/cardkit/v1/cards/${this.state.cardId}/elements/content/content`, {
method: "PUT",
headers: {
Authorization: `Bearer ${await getToken(this.creds)}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: text,
sequence: this.state.sequence,
uuid: `s_${this.state.cardId}_${this.state.sequence}`,
}),
}).catch((e) => this.log?.(`Update failed: ${String(e)}`));
await this.updateCardContent(text, (e) => this.log?.(`Update failed: ${String(e)}`));
});
await this.queue;
}
@@ -181,19 +188,7 @@ export class FeishuStreamingSession {
// Only send final update if content differs from what's already displayed
if (text && text !== this.state.currentText) {
this.state.sequence += 1;
await fetch(`${apiBase}/cardkit/v1/cards/${this.state.cardId}/elements/content/content`, {
method: "PUT",
headers: {
Authorization: `Bearer ${await getToken(this.creds)}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: text,
sequence: this.state.sequence,
uuid: `s_${this.state.cardId}_${this.state.sequence}`,
}),
}).catch(() => {});
await this.updateCardContent(text);
this.state.currentText = text;
}