openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
62 lines (61 loc) • 2.77 kB
JavaScript
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 };