Files
thrilltrack-explorer/src/lib/supabaseClient.ts
2025-11-04 17:34:16 +00:00

66 lines
2.3 KiB
TypeScript

/**
* 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;
/**
* 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 proxy for chained query methods
return new Proxy(result, {
get(queryTarget: any, queryProp: string | symbol) {
const queryValue = queryTarget[queryProp];
// If it's a function, wrap it to track the call
if (typeof queryValue === 'function') {
return async (...queryArgs: any[]) => {
try {
const response = await queryValue.apply(queryTarget, queryArgs);
// Log breadcrumb after response
breadcrumb.apiCall(
endpoint,
String(queryProp).toUpperCase(),
response.error ? 400 : 200
);
return response;
} catch (error) {
// Log breadcrumb for exceptions
breadcrumb.apiCall(endpoint, String(queryProp).toUpperCase(), 500);
throw error;
}
};
}
return queryValue;
}
});
};
}
return value;
}
}) as SupabaseClient;
}
export const supabase = wrapSupabaseClient(baseClient);