import { createClient } from '@supabase/supabase-js'; // Get environment variables const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; /** * Custom error class for Supabase-related errors */ export class SupabaseError extends Error { constructor( message: string, public readonly code?: string, public readonly originalError?: unknown ) { super(message); this.name = 'SupabaseError'; } } /** * Check if Supabase is properly configured */ export function isSupabaseConfigured(): boolean { return !!(supabaseUrl && supabaseAnonKey); } /** * Check if service role is available (server-side only) */ export function isServiceRoleAvailable(): boolean { return !!(process.env.SUPABASE_SERVICE_ROLE_KEY && supabaseUrl); } // Create client only if we have the required variables // This prevents build-time errors let client: ReturnType | undefined; if (typeof window !== 'undefined' && supabaseUrl && supabaseAnonKey) { client = createClient(supabaseUrl, supabaseAnonKey, { auth: { autoRefreshToken: true, persistSession: true, }, }); } // Export the client (will be undefined on server/build) export const supabaseClient = client as ReturnType; /** * Admin client for server-side operations (uses service role key) * @throws {SupabaseError} If Supabase is not configured */ export function getServiceSupabase() { const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY; if (!serviceKey || !supabaseUrl) { throw new SupabaseError( 'Missing Supabase service configuration. Please check your environment variables.', 'CONFIG_MISSING' ); } try { return createClient(supabaseUrl, serviceKey, { auth: { autoRefreshToken: false, persistSession: false, }, }); } catch (error) { throw new SupabaseError( 'Failed to initialize Supabase client', 'INIT_ERROR', error ); } } /** * Server-side client with user's JWT (for API routes/actions) * @throws {SupabaseError} If Supabase is not configured */ export function getSupabaseWithToken(token: string) { if (!supabaseUrl || !supabaseAnonKey) { throw new SupabaseError( 'Missing Supabase configuration. Please check your environment variables.', 'CONFIG_MISSING' ); } try { return createClient(supabaseUrl, supabaseAnonKey, { auth: { autoRefreshToken: false, persistSession: false, }, global: { headers: { Authorization: `Bearer ${token}`, }, }, }); } catch (error) { throw new SupabaseError( 'Failed to initialize Supabase client with token', 'INIT_ERROR', error ); } } /** * Safe wrapper for Supabase operations with proper error handling */ export async function withSupabase( operation: () => Promise, errorMessage: string = 'Database operation failed' ): Promise { try { return await operation(); } catch (error) { if (error instanceof SupabaseError) { throw error; } // Handle Supabase-specific errors if (error && typeof error === 'object' && 'code' in error) { const supabaseError = error as { code: string; message?: string }; throw new SupabaseError( supabaseError.message || errorMessage, supabaseError.code, error ); } throw new SupabaseError( errorMessage, 'UNKNOWN_ERROR', error ); } }