import { getQuery, setHeader } from "h3"; import { getAuthContext } from "../../../utils/auth"; import { prisma } from "../../../utils/prisma"; import { requireTelegramBotToken, telegramApiBase, telegramBotApi } from "../../../utils/telegram"; const TELEGRAM_AUDIO_FILE_MARKER = "tg-file:"; type TelegramFileMeta = { file_id: string; file_path?: string; }; function parseTelegramFileId(audioUrl: string | null | undefined) { const raw = String(audioUrl ?? "").trim(); if (!raw.startsWith(TELEGRAM_AUDIO_FILE_MARKER)) return null; const fileId = raw.slice(TELEGRAM_AUDIO_FILE_MARKER.length).trim(); return fileId || null; } export default defineEventHandler(async (event) => { const auth = await getAuthContext(event); const query = getQuery(event); const messageId = String(query.messageId ?? "").trim(); if (!messageId) { throw createError({ statusCode: 400, statusMessage: "messageId is required" }); } const message = await prisma.contactMessage.findFirst({ where: { id: messageId, channel: "TELEGRAM", contact: { teamId: auth.teamId }, }, select: { audioUrl: true, }, }); if (!message) { throw createError({ statusCode: 404, statusMessage: "telegram message not found" }); } const fileId = parseTelegramFileId(message.audioUrl); if (!fileId) { throw createError({ statusCode: 404, statusMessage: "telegram audio 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") || "audio/ogg"; 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=60"); if (contentLength) { const parsedLength = Number(contentLength); if (Number.isFinite(parsedLength) && parsedLength >= 0) { setHeader(event, "content-length", parsedLength); } } return body; });