/** * Central Supabase Client Export with Automatic Breadcrumb Tracking * * All application code should import from this file instead of the base client. * This wrapper automatically tracks all database operations as breadcrumbs for error debugging. */ import { supabase as baseClient } from '@/integrations/supabase/client'; import { breadcrumb } from './errorBreadcrumbs'; type SupabaseClient = typeof baseClient; /** * Create a recursive proxy for query builders that tracks terminal method calls */ function createQueryProxy(queryBuilder: any, endpoint: string, operations: string[] = []): any { return new Proxy(queryBuilder, { get(target, prop: string | symbol) { const value = target[prop]; if (typeof value !== 'function') { return value; } // Terminal methods that execute queries and return promises const terminalMethods = ['then', 'single', 'maybeSingle']; if (terminalMethods.includes(String(prop))) { // Wrap terminal method to log breadcrumb when promise resolves return function(...args: any[]) { const result = value.apply(target, args); const fullOperation = operations.join('.'); // Intercept promise resolution to log breadcrumb if (result && typeof result.then === 'function') { return result.then( (response: any) => { // Log successful API call breadcrumb.apiCall( endpoint, fullOperation || 'query', response?.error ? 400 : 200 ); // Dispatch API connectivity up event on successful requests if (!response?.error) { window.dispatchEvent(new CustomEvent('api-connectivity-up')); } return response; }, (error: any) => { // Log failed API call breadcrumb.apiCall(endpoint, fullOperation || 'query', 500); throw error; } ); } return result; }; } // Builder methods - pass through synchronously and continue proxying return function(...args: any[]) { const result = value.apply(target, args); // Continue proxying the returned builder with accumulated operations return createQueryProxy(result, endpoint, [...operations, String(prop)]); }; } }); } /** * Wrap Supabase client to automatically track API calls as breadcrumbs */ function wrapSupabaseClient(client: SupabaseClient): SupabaseClient { return new Proxy(client, { get(target, prop: string | symbol) { const value = target[prop as keyof typeof target]; // Only wrap 'from' and 'rpc' methods for database operations if ((prop === 'from' || prop === 'rpc') && typeof value === 'function') { return (...args: any[]) => { const result = (value as any).apply(target, args); const endpoint = prop === 'from' ? `/table/${args[0]}` : `/rpc/${args[0]}`; // Return a recursive proxy that tracks the query chain return createQueryProxy(result, endpoint, []); }; } return value; } }) as SupabaseClient; } export const supabase = wrapSupabaseClient(baseClient);