"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.readResponseBodyAsBuffer = readResponseBodyAsBuffer;exports.wecomFetch = wecomFetch; var _undici = require("undici"); const proxyDispatchers = new Map(); /** * **getProxyDispatcher (获取代理 Dispatcher)** * * 缓存并复用 ProxyAgent,避免重复创建连接池。 */ function getProxyDispatcher(proxyUrl) { const existing = proxyDispatchers.get(proxyUrl); if (existing) return existing; const created = new _undici.ProxyAgent(proxyUrl); proxyDispatchers.set(proxyUrl, created); return created; } function mergeAbortSignal(params) { const signals = []; if (params.signal) signals.push(params.signal); if (params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0) { signals.push(AbortSignal.timeout(params.timeoutMs)); } if (!signals.length) return undefined; if (signals.length === 1) return signals[0]; return AbortSignal.any(signals); } /** * **WecomHttpOptions (HTTP 选项)** * * @property proxyUrl 代理服务器地址 * @property timeoutMs 请求超时时间 (毫秒) * @property signal AbortSignal 信号 */ /** * **wecomFetch (统一 HTTP 请求)** * * 基于 `undici` 的 fetch 封装,自动处理 ProxyAgent 和 Timeout。 * 所有对企业微信 API 的调用都应经过此函数。 */ async function wecomFetch(input, init, opts) { const proxyUrl = opts?.proxyUrl?.trim() ?? ""; const dispatcher = proxyUrl ? getProxyDispatcher(proxyUrl) : undefined; const initSignal = init?.signal ?? undefined; const signal = mergeAbortSignal({ signal: opts?.signal ?? initSignal, timeoutMs: opts?.timeoutMs }); const headers = new Headers(init?.headers ?? {}); if (!headers.has("User-Agent")) { headers.set("User-Agent", "OpenClaw/2.0 (WeCom-Agent)"); } const nextInit = { ...(init ?? {}), ...(signal ? { signal } : {}), ...(dispatcher ? { dispatcher } : {}), headers }; try { return await (0, _undici.fetch)(input, nextInit); } catch (err) { if (err instanceof Error && err.name === "TypeError" && err.message === "fetch failed") { const cause = err.cause; console.error(`[wecom-http] fetch failed: ${input} (proxy: ${proxyUrl || "none"})${cause ? ` - cause: ${String(cause)}` : ""}`); } throw err; } } /** * **readResponseBodyAsBuffer (读取响应 Body)** * * 将 Response Body 读取为 Buffer,支持最大字节限制以防止内存溢出。 * 适用于下载媒体文件等场景。 */ async function readResponseBodyAsBuffer(res, maxBytes) { if (!res.body) return Buffer.alloc(0); const limit = maxBytes && Number.isFinite(maxBytes) && maxBytes > 0 ? maxBytes : undefined; const chunks = []; let total = 0; const reader = res.body.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; if (!value) continue; total += value.byteLength; if (limit && total > limit) { try { await reader.cancel("body too large"); } catch { // ignore }throw new Error(`response body too large (>${limit} bytes)`); } chunks.push(value); } return Buffer.concat(chunks.map((c) => Buffer.from(c))); } /* v9-40e2f7ebb66cdb11 */