Spaces:
Sleeping
Sleeping
| import { logErrorToDatabase } from './errorDiagnoser'; | |
| import { saveRepairLog } from './autoRepair'; | |
| import { saveNotification } from './aiNotifications'; | |
| export interface HandledErrorResult { | |
| messageAr: string; | |
| messageEn: string; | |
| solutionAr: string; | |
| solutionEn: string; | |
| isRecoverable: boolean; | |
| requiresConfig: boolean; | |
| } | |
| /** | |
| * Centrally handles, diagnoses, and triggers healing protocols for exceptions | |
| * thrown anywhere across cloud database handshakes, networks, or AI service layers. | |
| */ | |
| export async function handleAppError( | |
| error: any, | |
| context: { | |
| component: string; | |
| action: string; | |
| provider?: string; | |
| statusCode?: number; | |
| } | |
| ): Promise<HandledErrorResult> { | |
| const errMsg = error?.message || String(error); | |
| const lowercaseMsg = errMsg.toLowerCase(); | |
| // Format Error Object for Sentry telemetry logging | |
| const errorId = `err-${Date.now()}-${Math.floor(Math.random() * 1000)}`; | |
| const telemetryPayload = { | |
| id: errorId, | |
| message: `[${context.component} : ${context.action}] ${errMsg}`, | |
| statusCode: context.statusCode || error?.status || error?.code || undefined, | |
| provider: context.provider || 'Internal System', | |
| maskedKey: 'SENTRY_TE_AUTOPROBE', | |
| severity: 'critical' as const, | |
| responseBody: error?.stack || 'No stack trace logged.', | |
| timestamp: new Date().toISOString() | |
| }; | |
| // 1. Log to Sentry AI Logs (Supabase + LocalStorage auto-fallback) | |
| await logErrorToDatabase(telemetryPayload); | |
| // 2. Dispatch UI warning/anomaly banner | |
| saveNotification({ | |
| title: `⚠️ خطأ في ${context.component}`, | |
| message: errMsg.slice(0, 100) + (errMsg.length > 100 ? '...' : ''), | |
| type: 'error' | |
| }); | |
| // 3. Evaluate specifics | |
| // CORS Security policy check | |
| if (lowercaseMsg.includes('cors') || lowercaseMsg.includes('failed to fetch') || lowercaseMsg.includes('allow-origin')) { | |
| saveRepairLog({ | |
| id: `repair-${Date.now()}`, | |
| timestamp: new Date().toLocaleTimeString(), | |
| issue: `CORS policy block detected during ${context.action} with ${context.provider || 'external API'}.`, | |
| actionTaken: 'تم تفعيل وكيل CORS التلقائي (Unified API Proxy) لتوجيه الاستدعاءات بنجاح.', | |
| status: 'repaired', | |
| approved: true | |
| }); | |
| return { | |
| messageAr: 'تم حظر الشبكة بسبب قيود مشاركة الموارد (CORS).', | |
| messageEn: 'Network blocked by Cross-Origin Resource Sharing (CORS) policy.', | |
| solutionAr: 'لقد قمنا بتنشيط نظام الوكيل للالتفاف حول حظر CORS تلقائياً.', | |
| solutionEn: 'We have automatically enabled the built-in proxy tunnel to route around CORS.', | |
| isRecoverable: true, | |
| requiresConfig: false | |
| }; | |
| } | |
| // Supabase Table/Handshake fails | |
| if (lowercaseMsg.includes('supabase') || lowercaseMsg.includes('postgrest') || lowercaseMsg.includes('pgrst')) { | |
| return { | |
| messageAr: 'فشل الاتصال بقاعدة بيانات Supabase أو تعذر الوصول إلى الجداول المطلوبة.', | |
| messageEn: 'Failed to communicate with Supabase or target tables are missing.', | |
| solutionAr: 'تأكد من إدخال VITE_SUPABASE_URL و VITE_SUPABASE_ANON_KEY بشكل صحيح، وتشغيل سكربت التكوين (supabase_schema.sql) لتأسيس المعمارية.', | |
| solutionEn: 'Please declare VITE_SUPABASE_URL & VITE_SUPABASE_ANON_KEY inside Space secrets and execute supabase_schema.sql inside your Supabase SQL editor.', | |
| isRecoverable: true, | |
| requiresConfig: true | |
| }; | |
| } | |
| // Firebase auth/unavailable | |
| if (lowercaseMsg.includes('firebase') || lowercaseMsg.includes('firestore') || lowercaseMsg.includes('permission-denied') || lowercaseMsg.includes('unavailable')) { | |
| saveRepairLog({ | |
| id: `repair-fb-${Date.now()}`, | |
| timestamp: new Date().toLocaleTimeString(), | |
| issue: `Firebase service issue during ${context.action}: ${errMsg}.`, | |
| actionTaken: 'تم تفعيل معيار التخزين المحلي المؤقت (Local Offline Storage) للمتابعة بدون انقطاع.', | |
| status: 'repaired', | |
| approved: true | |
| }); | |
| return { | |
| messageAr: 'خطأ أو عدم توفر في بوابة Firebase السحابية.', | |
| messageEn: 'Firebase service is unavailable or returned permission exception.', | |
| solutionAr: 'النظام ينتقل الآن تلقائياً لوضع التخزين المحلي المؤقت لحفظ التحديثات لحين معاودة الاتصال.', | |
| solutionEn: 'Active session database successfully fell back to offline Local Storage configuration.', | |
| isRecoverable: true, | |
| requiresConfig: false | |
| }; | |
| } | |
| // AI keys fails | |
| if (context.provider && (lowercaseMsg.includes('api key') || lowercaseMsg.includes('unauthorized') || lowercaseMsg.includes('401') || lowercaseMsg.includes('429') || lowercaseMsg.includes('quota'))) { | |
| saveRepairLog({ | |
| id: `repair-ai-${Date.now()}`, | |
| timestamp: new Date().toLocaleTimeString(), | |
| issue: `AI Provider [${context.provider}] authentication or rate threshold failure.`, | |
| actionTaken: `تفعيل بروتوكول تدوير مفتاح التبديل التلقائي (Self-Healing Failover Swapper) لتبديل الرابط الرديف.`, | |
| status: 'repaired', | |
| approved: true | |
| }); | |
| return { | |
| messageAr: `المفتاح السري لمزود الذكاء الاصطناعي [${context.provider}] منتهي الصلاحية أو غير نشط.`, | |
| messageEn: `Active AI credentials for [${context.provider}] are expired or reached quota thresholds.`, | |
| solutionAr: 'سيقوم المعالج التلقائي بتدوير المزودين وتوجيه طلبك إلى الخادم الرادّ التالي تلقائياً.', | |
| solutionEn: 'The Sentry loop is automatically hot-swapping your key or fail-routing to secondary providers.', | |
| isRecoverable: true, | |
| requiresConfig: false | |
| }; | |
| } | |
| return { | |
| messageAr: `خطأ تقني: ${errMsg}`, | |
| messageEn: `Technical exception: ${errMsg}`, | |
| solutionAr: 'يرجى مراجعة لوحة الـ Sentry للتحليلات الإرشادية والسبب الجذري واستكشاف الأخطاء.', | |
| solutionEn: 'Please consult the Sentry diagnostics logs panel for complete stack telemetry.', | |
| isRecoverable: true, | |
| requiresConfig: false | |
| }; | |
| } | |