UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

62 lines (61 loc) 2.77 kB
import { c as readFileDescriptorBounded } from "./boundary-file-read-uaJcf6X6.js"; import { t as pruneMapToMaxSize } from "./map-size-CNcWiFKu.js"; import { c as resolveAvatarMime, d as isAvatarImageMimeType, f as isRenderableAvatarImageDataUrl, l as AVATAR_MAX_BYTES } from "./avatar-policy-D8FQ_Wte.js"; import { d as normalizeMimeType } from "./mime-CVpcq9ju.js"; import { s as createImageProcessor } from "./image-ops-DU1SIRgh.js"; import { n as gatewayAvatarImageRevision } from "./assistant-avatar-cache-4x6DyL8R.js"; import { i as createHttpImageRepresentation } from "./http-image-response-DUkYrvGx.js"; import { fileTypeFromBuffer } from "file-type"; //#region src/gateway/assistant-avatar-thumbnail.runtime.ts const AVATAR_THUMBNAIL_SIDE = 128; const thumbnailCache = /* @__PURE__ */ new Map(); async function createAvatarThumbnail(source) { let body; let contentType; if ("file" in source) { body = await readFileDescriptorBounded(source.file.fd, AVATAR_MAX_BYTES); contentType = resolveAvatarMime(source.file.path); } else { if (!isRenderableAvatarImageDataUrl(source.dataUrl)) throw new Error("Unsupported avatar data URL"); const response = await fetch(source.dataUrl); contentType = response.headers.get("content-type") ?? ""; body = Buffer.from(await response.arrayBuffer()); if (body.length > 2097152) throw new Error("Avatar data URL exceeds size limit"); } const mime = normalizeMimeType(contentType); if (!mime || !isAvatarImageMimeType(mime)) throw new Error("Unsupported avatar image type"); if ([ "image/png", "image/jpeg", "image/webp" ].includes(mime)) { const detectedMime = (await fileTypeFromBuffer(body))?.mime; const animatedWebp = detectedMime === "image/webp" && body.length >= 21 && body.toString("ascii", 12, 16) === "VP8X" && (body.readUInt8(20) & 2) !== 0; if (detectedMime === "image/apng" || animatedWebp) return createHttpImageRepresentation(body, contentType); body = (await createImageProcessor().encode(body, { format: "png", resize: { maxSide: AVATAR_THUMBNAIL_SIDE, enlarge: false } })).data; contentType = "image/png"; } return createHttpImageRepresentation(body, contentType); } /** Caller retains descriptor ownership until this shared read has settled. */ async function readGatewayAvatarThumbnail(source) { const revision = gatewayAvatarImageRevision(source); const pending = thumbnailCache.get(revision) ?? createAvatarThumbnail(source); thumbnailCache.delete(revision); thumbnailCache.set(revision, pending); pruneMapToMaxSize(thumbnailCache, 4); try { return await pending; } catch (error) { if (thumbnailCache.get(revision) === pending) thumbnailCache.delete(revision); throw error; } } //#endregion export { readGatewayAvatarThumbnail };