import { ErrorInfo } from "react"; import { Ticket, createTicket, getAuthToken, sendTicketMessage } from ".."; let errorsQueue: ComponentError[] = []; let timeoutId: ReturnType; interface ComponentError { timestamp: number; message: string; callStack: string | undefined; componentStack: string | null | undefined; } function isErrorReportingAllowed(error?: Error): boolean { // Если ошибка помечена как debug-override — всегда отправлять if (error && (error as any).__forceSend) return true; // Проверяем домен const currentDomain = window.location.hostname; return currentDomain !== 'localhost'; } // Новый API: getTickets — callback, возвращающий актуальные тикеты export function handleComponentError(error: Error, info: ErrorInfo, getTickets: () => Ticket[]) { //репортим только о авторизонышах if (!getAuthToken()) return; // Проверяем разрешение на отправку ошибок (по домену) if (!isErrorReportingAllowed(error)) { console.log('❌ Отправка ошибки заблокирована:', error.message); return; } console.log(`✅ Обработка ошибки: ${error.message}`); // Копируем __forceSend если есть const componentError: ComponentError & { __forceSend?: boolean } = { timestamp: Math.floor(Date.now() / 1000), message: error.message, callStack: error.stack, componentStack: info.componentStack, ...(error && (error as any).__forceSend ? { __forceSend: true } : {}) }; queueErrorRequest(componentError, getTickets); } // Ставит ошибку в очередь для отправки, через 1 секунду вызывает sendErrorsToServer export function queueErrorRequest(error: ComponentError, getTickets: () => Ticket[]) { errorsQueue.push(error); clearTimeout(timeoutId); timeoutId = setTimeout(() => { sendErrorsToServer(getTickets); }, 1000); } // Отправляет накопленные ошибки в тикеты, ищет существующий тикет с system: true или создает новый export async function sendErrorsToServer(getTickets: () => Ticket[]) { if (errorsQueue.length === 0) return; // Проверяем разрешение на отправку ошибок (по домену и debug-override) // Если хотя бы одна ошибка в очереди с __forceSend, отправляем всё const forceSend = errorsQueue.some(e => (e as any).__forceSend); if (!forceSend && !isErrorReportingAllowed()) { console.log('❌ Отправка ошибок заблокирована, очищаем очередь'); errorsQueue = []; return; } const tickets = getTickets(); try { // Формируем сообщение об ошибке const errorMessage = errorsQueue.map(error => { return `[${new Date(error.timestamp * 1000).toISOString()}] ${error.message}\n\nCall Stack:\n${error.callStack || 'N/A'}\n\nComponent Stack:\n${error.componentStack || 'N/A'}`; }).join('\n\n---\n\n'); // ВСЕГДА ищем тикет через API const existingSystemTicket = await findSystemTicket(tickets); if (existingSystemTicket) { sendTicketMessage({ ticketId: existingSystemTicket, message: errorMessage, systemError: true, }); } else { // Создаем новый тикет для ошибки createTicket({ message: errorMessage, useToken: true, systemError: true, }); } } catch (error) { console.error('Error in sendErrorsToServer:', error); } finally { // Очищаем очередь ошибок errorsQueue = []; } } // Ищет существующий тикет с system: true export async function findSystemTicket(tickets: Ticket[]) { for (const ticket of tickets) { console.log("[findSystemTicket] Проверяем тикет:", ticket); if (!('messages' in ticket)) { if (ticket.top_message && ticket.top_message.system === true) { console.log("[findSystemTicket] Найден тикет по top_message.system:true:", ticket.id); return ticket.id; } } } } export function clearErrorHandlingConfig () { clearTimeout(timeoutId); errorsQueue = []; }