import { getQuery, setHeader } from "h3"; import { getAuthContext } from "../../../utils/auth"; import { prisma } from "../../../utils/prisma"; import { requireTelegramBotToken, telegramApiBase, telegramBotApi } from "../../../utils/telegram"; const TELEGRAM_FILE_MARKER = "tg-file:"; type TelegramFileMeta = { file_id: string; file_path?: string; }; function parseTelegramFileId(avatarUrl: string | null | undefined) { const raw = String(avatarUrl ?? "").trim(); if (!raw.startsWith(TELEGRAM_FILE_MARKER)) return null; const fileId = raw.slice(TELEGRAM_FILE_MARKER.length).trim(); return fileId || null; } export default defineEventHandler(async (event) => { const auth = await getAuthContext(event); const query = getQuery(event); const contactId = String(query.contactId ?? "").trim(); if (!contactId) { throw createError({ statusCode: 400, statusMessage: "contactId is required" }); } const contact = await prisma.contact.findFirst({ where: { id: contactId, teamId: auth.teamId, }, select: { avatarUrl: true, }, }); if (!contact) { throw createError({ statusCode: 404, statusMessage: "contact not found" }); } const fileId = parseTelegramFileId(contact.avatarUrl); if (!fileId) { throw createError({ statusCode: 404, statusMessage: "telegram avatar is missing" }); } const meta = await telegramBotApi("getFile", { file_id: fileId }); const filePath = String(meta?.file_path ?? "").trim(); if (!filePath) { throw createError({ statusCode: 502, statusMessage: "telegram file path is unavailable" }); } const apiBase = telegramApiBase().replace(/\/+$/, ""); const token = requireTelegramBotToken(); const remote = await fetch(`${apiBase}/file/bot${token}/${filePath}`); if (!remote.ok) { throw createError({ statusCode: 502, statusMessage: `telegram file fetch failed (${remote.status})` }); } const contentType = remote.headers.get("content-type") || "image/jpeg"; const contentLength = remote.headers.get("content-length"); const body = Buffer.from(await remote.arrayBuffer()); setHeader(event, "content-type", contentType); setHeader(event, "cache-control", "private, max-age=300"); if (contentLength) { const parsedLength = Number(contentLength); if (Number.isFinite(parsedLength) && parsedLength >= 0) { setHeader(event, "content-length", parsedLength); } } return body; });