import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { type NextRequest, NextResponse } from 'next/server' import { telegramSendDocumentContract } from '@/lib/api/contracts/tools/communication/messaging' import { parseRequest } from '@/lib/api/server' import { checkInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' import { processFilesToUserFiles } from '@/lib/uploads/utils/file-utils' import { downloadServableFileFromStorage } from '@/lib/uploads/utils/file-utils.server' import { docNotReadyResponse } from '@/lib/uploads/utils/servable-file-response' import { assertToolFileAccess } from '@/app/api/files/authorization' import { convertMarkdownToHTML } from '@/tools/telegram/utils' export const dynamic = 'force-dynamic' const logger = createLogger('TelegramSendDocumentAPI') export const POST = withRouteHandler(async (request: NextRequest) => { const requestId = generateRequestId() try { const authResult = await checkInternalAuth(request, { requireWorkflowId: false, }) if (!authResult.success || !authResult.userId) { logger.warn(`[${requestId}] Unauthorized Telegram send attempt: ${authResult.error}`) return NextResponse.json( { success: false, error: authResult.error || 'Authentication required', }, { status: 401 } ) } logger.info(`[${requestId}] Authenticated Telegram send request via ${authResult.authType}`, { userId: authResult.userId, }) const parsed = await parseRequest(telegramSendDocumentContract, request, {}) if (!parsed.success) return parsed.response const validatedData = parsed.data.body logger.info(`[${requestId}] Sending Telegram document`, { chatId: validatedData.chatId, hasFiles: !!(validatedData.files && validatedData.files.length > 0), fileCount: validatedData.files?.length || 0, }) if (!validatedData.files || validatedData.files.length === 0) { return NextResponse.json( { success: false, error: 'At least one document file is required for sendDocument operation', }, { status: 400 } ) } const userFiles = processFilesToUserFiles(validatedData.files, requestId, logger) if (userFiles.length === 0) { logger.warn(`[${requestId}] No valid files to upload`) return NextResponse.json( { success: false, error: 'No valid files provided for upload', }, { status: 400 } ) } const maxSize = 50 * 1024 * 1024 // 50MB const tooLargeFiles = userFiles.filter((file) => file.size > maxSize) if (tooLargeFiles.length > 0) { const filesInfo = tooLargeFiles .map((f) => `${f.name} (${(f.size / (1024 * 1024)).toFixed(2)}MB)`) .join(', ') return NextResponse.json( { success: false, error: `The following files exceed Telegram's 50MB limit: ${filesInfo}`, }, { status: 400 } ) } const userFile = userFiles[0] logger.info(`[${requestId}] Uploading document: ${userFile.name}`) const denied = await assertToolFileAccess(userFile.key, authResult.userId, requestId, logger) if (denied) return denied let buffer: Buffer let contentType: string try { const downloaded = await downloadServableFileFromStorage(userFile, requestId, logger) buffer = downloaded.buffer contentType = downloaded.contentType } catch (error) { const notReady = docNotReadyResponse(error) if (notReady) return notReady logger.error(`[${requestId}] Failed to download document ${userFile.name}:`, error) return NextResponse.json( { success: false, error: `Failed to download document: ${getErrorMessage(error, 'Unknown error')}`, }, { status: 500 } ) } if (buffer.length > maxSize) { const sizeMB = (buffer.length / (1024 * 1024)).toFixed(2) return NextResponse.json( { success: false, error: `The following files exceed Telegram's 50MB limit: ${userFile.name} (${sizeMB}MB)`, }, { status: 400 } ) } const resolvedMimeType = contentType || userFile.type || 'application/octet-stream' const filesOutput = [ { name: userFile.name, mimeType: resolvedMimeType, data: buffer.toString('base64'), size: buffer.length, }, ] logger.info(`[${requestId}] Downloaded file: ${buffer.length} bytes`) const formData = new FormData() formData.append('chat_id', validatedData.chatId) const blob = new Blob([new Uint8Array(buffer)], { type: resolvedMimeType }) formData.append('document', blob, userFile.name) if (validatedData.caption) { formData.append('caption', convertMarkdownToHTML(validatedData.caption)) formData.append('parse_mode', 'HTML') } const telegramApiUrl = `https://api.telegram.org/bot${validatedData.botToken}/sendDocument` logger.info(`[${requestId}] Sending request to Telegram API`) const response = await fetch(telegramApiUrl, { method: 'POST', body: formData, }) const data = await response.json() if (!data.ok) { logger.error(`[${requestId}] Telegram API error:`, data) return NextResponse.json( { success: false, error: data.description || 'Failed to send document to Telegram', }, { status: response.status } ) } logger.info(`[${requestId}] Document sent successfully`) return NextResponse.json({ success: true, output: { message: 'Document sent successfully', data: data.result, files: filesOutput, }, }) } catch (error) { logger.error(`[${requestId}] Error sending Telegram document:`, error) return NextResponse.json( { success: false, error: getErrorMessage(error, 'Unknown error occurred'), }, { status: 500 } ) } })