mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-15 03:50:40 +00:00
* fix(feishu): pass proxy agent to WSClient for environments behind HTTPS proxy The Lark SDK WSClient uses the `ws` library which does not automatically respect https_proxy/HTTP_PROXY environment variables. This causes WebSocket connection failures in proxy environments (e.g. WSL2 with a local proxy). Detect proxy env vars and pass an HttpsProxyAgent to WSClient via the existing `agent` constructor option. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): add generic type parameter to HttpsProxyAgent return type Fix TS2314: `HttpsProxyAgent<Uri>` requires a type argument. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(feishu): wire ws proxy dependency and coverage * chore(lockfile): resolve axios peer lock entry after rebase --------- Co-authored-by: lirui <lirui@fxiaoke.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
132 lines
3.3 KiB
TypeScript
132 lines
3.3 KiB
TypeScript
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
import type { FeishuDomain, ResolvedFeishuAccount } from "./types.js";
|
|
|
|
function getWsProxyAgent(): HttpsProxyAgent<string> | undefined {
|
|
const proxyUrl =
|
|
process.env.https_proxy ||
|
|
process.env.HTTPS_PROXY ||
|
|
process.env.http_proxy ||
|
|
process.env.HTTP_PROXY;
|
|
if (!proxyUrl) return undefined;
|
|
return new HttpsProxyAgent(proxyUrl);
|
|
}
|
|
|
|
// Multi-account client cache
|
|
const clientCache = new Map<
|
|
string,
|
|
{
|
|
client: Lark.Client;
|
|
config: { appId: string; appSecret: string; domain?: FeishuDomain };
|
|
}
|
|
>();
|
|
|
|
function resolveDomain(domain: FeishuDomain | undefined): Lark.Domain | string {
|
|
if (domain === "lark") {
|
|
return Lark.Domain.Lark;
|
|
}
|
|
if (domain === "feishu" || !domain) {
|
|
return Lark.Domain.Feishu;
|
|
}
|
|
return domain.replace(/\/+$/, ""); // Custom URL for private deployment
|
|
}
|
|
|
|
/**
|
|
* Credentials needed to create a Feishu client.
|
|
* Both FeishuConfig and ResolvedFeishuAccount satisfy this interface.
|
|
*/
|
|
export type FeishuClientCredentials = {
|
|
accountId?: string;
|
|
appId?: string;
|
|
appSecret?: string;
|
|
domain?: FeishuDomain;
|
|
};
|
|
|
|
/**
|
|
* Create or get a cached Feishu client for an account.
|
|
* Accepts any object with appId, appSecret, and optional domain/accountId.
|
|
*/
|
|
export function createFeishuClient(creds: FeishuClientCredentials): Lark.Client {
|
|
const { accountId = "default", appId, appSecret, domain } = creds;
|
|
|
|
if (!appId || !appSecret) {
|
|
throw new Error(`Feishu credentials not configured for account "${accountId}"`);
|
|
}
|
|
|
|
// Check cache
|
|
const cached = clientCache.get(accountId);
|
|
if (
|
|
cached &&
|
|
cached.config.appId === appId &&
|
|
cached.config.appSecret === appSecret &&
|
|
cached.config.domain === domain
|
|
) {
|
|
return cached.client;
|
|
}
|
|
|
|
// Create new client
|
|
const client = new Lark.Client({
|
|
appId,
|
|
appSecret,
|
|
appType: Lark.AppType.SelfBuild,
|
|
domain: resolveDomain(domain),
|
|
});
|
|
|
|
// Cache it
|
|
clientCache.set(accountId, {
|
|
client,
|
|
config: { appId, appSecret, domain },
|
|
});
|
|
|
|
return client;
|
|
}
|
|
|
|
/**
|
|
* Create a Feishu WebSocket client for an account.
|
|
* Note: WSClient is not cached since each call creates a new connection.
|
|
*/
|
|
export function createFeishuWSClient(account: ResolvedFeishuAccount): Lark.WSClient {
|
|
const { accountId, appId, appSecret, domain } = account;
|
|
|
|
if (!appId || !appSecret) {
|
|
throw new Error(`Feishu credentials not configured for account "${accountId}"`);
|
|
}
|
|
|
|
const agent = getWsProxyAgent();
|
|
return new Lark.WSClient({
|
|
appId,
|
|
appSecret,
|
|
domain: resolveDomain(domain),
|
|
loggerLevel: Lark.LoggerLevel.info,
|
|
...(agent ? { agent } : {}),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create an event dispatcher for an account.
|
|
*/
|
|
export function createEventDispatcher(account: ResolvedFeishuAccount): Lark.EventDispatcher {
|
|
return new Lark.EventDispatcher({
|
|
encryptKey: account.encryptKey,
|
|
verificationToken: account.verificationToken,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get a cached client for an account (if exists).
|
|
*/
|
|
export function getFeishuClient(accountId: string): Lark.Client | null {
|
|
return clientCache.get(accountId)?.client ?? null;
|
|
}
|
|
|
|
/**
|
|
* Clear client cache for a specific account or all accounts.
|
|
*/
|
|
export function clearClientCache(accountId?: string): void {
|
|
if (accountId) {
|
|
clientCache.delete(accountId);
|
|
} else {
|
|
clientCache.clear();
|
|
}
|
|
}
|