Simplify Supabase client and remove mock fallback
cgen-43e2f0c3c9294158bef35e367965ba18
This commit is contained in:
parent
2fb9c140d0
commit
885693d2e6
1 changed files with 71 additions and 318 deletions
|
|
@ -1,12 +1,10 @@
|
||||||
import { createClient } from "@supabase/supabase-js";
|
import { createClient } from "@supabase/supabase-js";
|
||||||
import type { Database } from "./database.types";
|
import type { Database } from "./database.types";
|
||||||
import { mockAuth } from "./mock-auth";
|
|
||||||
|
|
||||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
|
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
|
||||||
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
||||||
|
|
||||||
// Check if we have valid environment variables
|
export const isSupabaseConfigured = Boolean(supabaseUrl && supabaseAnonKey);
|
||||||
export const isSupabaseConfigured = !!(supabaseUrl && supabaseAnonKey);
|
|
||||||
|
|
||||||
console.log("Supabase Config:", {
|
console.log("Supabase Config:", {
|
||||||
hasUrl: !!supabaseUrl,
|
hasUrl: !!supabaseUrl,
|
||||||
|
|
@ -16,327 +14,82 @@ console.log("Supabase Config:", {
|
||||||
isSupabaseConfigured,
|
isSupabaseConfigured,
|
||||||
});
|
});
|
||||||
|
|
||||||
let supabaseClient: any = null;
|
if (!isSupabaseConfigured) {
|
||||||
|
const message =
|
||||||
if (isSupabaseConfigured) {
|
"Supabase environment variables are missing. Please set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY.";
|
||||||
supabaseClient = createClient<Database>(supabaseUrl!, supabaseAnonKey!, {
|
console.error(message);
|
||||||
auth: {
|
throw new Error(message);
|
||||||
autoRefreshToken: true,
|
|
||||||
persistSession: true,
|
|
||||||
detectSessionInUrl: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test connection
|
|
||||||
setTimeout(async () => {
|
|
||||||
try {
|
|
||||||
console.log("🔍 Testing Supabase connection to:", supabaseUrl);
|
|
||||||
const { data, error } = await supabaseClient
|
|
||||||
.from("user_profiles")
|
|
||||||
.select("count", { count: "exact", head: true });
|
|
||||||
if (error) {
|
|
||||||
console.warn("⚠️ Supabase connection test failed:", error.message);
|
|
||||||
console.log("🔄 Falling back to mock authentication for development");
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
"✅ Supabase connection successful - found",
|
|
||||||
data,
|
|
||||||
"user profiles",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (err: any) {
|
|
||||||
console.warn("⚠️ Supabase connection error:", err.message);
|
|
||||||
console.log("🔄 Using mock authentication for development");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also test auth endpoint specifically
|
|
||||||
try {
|
|
||||||
console.log("🔍 Testing Supabase auth endpoint...");
|
|
||||||
const { data, error } = await supabaseClient.auth.getSession();
|
|
||||||
if (error) {
|
|
||||||
console.warn("⚠️ Supabase auth test failed:", error.message);
|
|
||||||
} else {
|
|
||||||
console.log("✅ Supabase auth endpoint accessible");
|
|
||||||
}
|
|
||||||
} catch (authErr: any) {
|
|
||||||
console.warn("⚠️ Supabase auth endpoint error:", authErr.message);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a proxy that falls back to mock when Supabase fails
|
export const supabase = createClient<Database>(supabaseUrl!, supabaseAnonKey!, {
|
||||||
export const supabase = new Proxy(supabaseClient || {}, {
|
auth: {
|
||||||
get(target, prop) {
|
autoRefreshToken: true,
|
||||||
if (prop === "auth") {
|
persistSession: true,
|
||||||
return {
|
detectSessionInUrl: true,
|
||||||
signInWithPassword: async (credentials: any) => {
|
|
||||||
if (isSupabaseConfigured && target && target.auth) {
|
|
||||||
try {
|
|
||||||
console.log("Attempting Supabase authentication...");
|
|
||||||
const result = await target.auth.signInWithPassword(credentials);
|
|
||||||
console.log("✅ Supabase authentication successful");
|
|
||||||
return result;
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn("⚠️ Supabase authentication failed:", error.message);
|
|
||||||
if (
|
|
||||||
error.message?.includes("Failed to fetch") ||
|
|
||||||
error.name === "AuthRetryableFetchError" ||
|
|
||||||
error.message?.includes("fetch")
|
|
||||||
) {
|
|
||||||
console.log("🔄 Falling back to mock authentication");
|
|
||||||
return await mockAuth.signInWithPassword(
|
|
||||||
credentials.email,
|
|
||||||
credentials.password,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
"🔄 Using mock authentication (Supabase not configured)",
|
|
||||||
);
|
|
||||||
return await mockAuth.signInWithPassword(
|
|
||||||
credentials.email,
|
|
||||||
credentials.password,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// OAuth sign-in (GitHub/Google). Falls back to mock in development.
|
|
||||||
signInWithOAuth: async (opts: any) => {
|
|
||||||
const provider = opts?.provider;
|
|
||||||
if (
|
|
||||||
isSupabaseConfigured &&
|
|
||||||
target &&
|
|
||||||
target.auth &&
|
|
||||||
typeof target.auth.signInWithOAuth === "function"
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return await target.auth.signInWithOAuth(opts);
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn(
|
|
||||||
"Supabase signInWithOAuth failed:",
|
|
||||||
error?.message || error,
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
return await mockAuth.signInWithOAuth(provider);
|
|
||||||
} catch (e) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mock fallback
|
|
||||||
return await mockAuth.signInWithOAuth(provider);
|
|
||||||
},
|
|
||||||
linkIdentity: async (options: { provider: string; redirectTo?: string }) => {
|
|
||||||
if (
|
|
||||||
isSupabaseConfigured &&
|
|
||||||
target &&
|
|
||||||
target.auth &&
|
|
||||||
typeof target.auth.linkIdentity === "function"
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return await target.auth.linkIdentity(options);
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn(
|
|
||||||
"Supabase linkIdentity failed:",
|
|
||||||
error?.message || error,
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
return await mockAuth.linkIdentity({ provider: options.provider });
|
|
||||||
} catch {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await mockAuth.linkIdentity({ provider: options.provider });
|
|
||||||
},
|
|
||||||
unlinkIdentity: async (options: { identity_id?: string; provider?: string }) => {
|
|
||||||
if (
|
|
||||||
isSupabaseConfigured &&
|
|
||||||
target &&
|
|
||||||
target.auth &&
|
|
||||||
typeof target.auth.unlinkIdentity === "function"
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
return await target.auth.unlinkIdentity(options);
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn(
|
|
||||||
"Supabase unlinkIdentity failed:",
|
|
||||||
error?.message || error,
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
return await mockAuth.unlinkIdentity(options);
|
|
||||||
} catch {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await mockAuth.unlinkIdentity(options);
|
|
||||||
},
|
|
||||||
signOut: async () => {
|
|
||||||
if (isSupabaseConfigured && target && target.auth) {
|
|
||||||
try {
|
|
||||||
return await target.auth.signOut();
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("Supabase signOut failed, using mock");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await mockAuth.signOut();
|
|
||||||
},
|
|
||||||
getUser: async () => {
|
|
||||||
if (isSupabaseConfigured && target && target.auth) {
|
|
||||||
try {
|
|
||||||
return await target.auth.getUser();
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("Supabase getUser failed, using mock");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await mockAuth.getUser();
|
|
||||||
},
|
|
||||||
getSession: async () => {
|
|
||||||
if (isSupabaseConfigured && target && target.auth) {
|
|
||||||
try {
|
|
||||||
return await target.auth.getSession();
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("Supabase getSession failed, using mock");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await mockAuth.getSession();
|
|
||||||
},
|
|
||||||
onAuthStateChange: (callback: any) => {
|
|
||||||
let realSub: any = null;
|
|
||||||
if (isSupabaseConfigured && target && target.auth) {
|
|
||||||
try {
|
|
||||||
realSub = target.auth.onAuthStateChange(callback);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(
|
|
||||||
"Supabase onAuthStateChange failed, will use mock too",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Always subscribe to mock as a safety net in case we fall back during auth
|
|
||||||
const mockSub = mockAuth.onAuthStateChange(callback);
|
|
||||||
|
|
||||||
// Return a combined unsubscribe that cleans up both
|
|
||||||
return {
|
|
||||||
data: {
|
|
||||||
subscription: {
|
|
||||||
unsubscribe: () => {
|
|
||||||
try {
|
|
||||||
realSub?.data?.subscription?.unsubscribe?.();
|
|
||||||
} catch {}
|
|
||||||
try {
|
|
||||||
mockSub?.data?.subscription?.unsubscribe?.();
|
|
||||||
} catch {}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as any;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop === "channel") {
|
|
||||||
if (
|
|
||||||
isSupabaseConfigured &&
|
|
||||||
target &&
|
|
||||||
typeof target.channel === "function"
|
|
||||||
) {
|
|
||||||
return target.channel.bind(target);
|
|
||||||
}
|
|
||||||
return function () {
|
|
||||||
const ch: any = {
|
|
||||||
on: () => ch,
|
|
||||||
subscribe: () => ({ unsubscribe: () => {} }),
|
|
||||||
unsubscribe: () => {},
|
|
||||||
};
|
|
||||||
return ch;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop === "from") {
|
|
||||||
if (isSupabaseConfigured && target && typeof target.from === "function") {
|
|
||||||
return target.from.bind(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chainable mock query builder to prevent runtime errors when Supabase is unavailable
|
|
||||||
const createMockBuilder = (initialData: any[] | any = []) => {
|
|
||||||
let rows = Array.isArray(initialData) ? initialData : [initialData];
|
|
||||||
const builder: any = {
|
|
||||||
select: () => builder,
|
|
||||||
insert: () => builder,
|
|
||||||
update: () => builder,
|
|
||||||
delete: () => builder,
|
|
||||||
eq: () => builder,
|
|
||||||
order: () => builder,
|
|
||||||
limit: () => builder,
|
|
||||||
single: async () => ({ data: rows[0] ?? {}, error: null }),
|
|
||||||
then: (resolve: any) => resolve({ data: rows, error: null }),
|
|
||||||
catch: () => builder,
|
|
||||||
finally: (cb: any) => {
|
|
||||||
cb?.();
|
|
||||||
return builder;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return builder;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createMockTable = (table: string) => ({
|
|
||||||
select: (_cols?: any, _opts?: any) => createMockBuilder([]),
|
|
||||||
insert: (payload?: any) =>
|
|
||||||
createMockBuilder(
|
|
||||||
Array.isArray(payload) ? payload : payload ? [payload] : [],
|
|
||||||
),
|
|
||||||
update: (payload?: any) => createMockBuilder(payload || {}),
|
|
||||||
delete: () => createMockBuilder([]),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (table: string) => createMockTable(table);
|
|
||||||
}
|
|
||||||
|
|
||||||
return target[prop];
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auth helpers
|
type SupabaseError = { message?: string };
|
||||||
export const auth = supabase.auth;
|
|
||||||
|
|
||||||
// Database helpers
|
|
||||||
export const db = supabase.from;
|
|
||||||
|
|
||||||
// Storage helpers
|
|
||||||
export const storage = supabase.storage;
|
|
||||||
|
|
||||||
// Real-time helpers
|
|
||||||
export const channel = supabase.channel;
|
|
||||||
|
|
||||||
// Test function for debugging
|
|
||||||
(window as any).testSupabase = async () => {
|
|
||||||
console.log("🧪 Manual Supabase Test");
|
|
||||||
console.log("URL:", supabaseUrl);
|
|
||||||
console.log("Key configured:", !!supabaseAnonKey);
|
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const testLogin = await supabase.auth.signInWithPassword({
|
console.log("🔍 Testing Supabase connection to:", supabaseUrl);
|
||||||
email: "test@example.com",
|
const { error } = await supabase
|
||||||
password: "test123",
|
|
||||||
});
|
|
||||||
console.log("Auth test result:", testLogin);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Auth test error:", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("user_profiles")
|
.from("user_profiles")
|
||||||
.select("*")
|
.select("count", { count: "exact", head: true });
|
||||||
.limit(1);
|
if (error) {
|
||||||
console.log("Database test - data:", data, "error:", error);
|
console.warn("⚠️ Supabase connection test failed:", error.message);
|
||||||
} catch (dbError) {
|
} else {
|
||||||
console.error("Database test error:", dbError);
|
console.log("✅ Supabase connection successful");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const error = err as SupabaseError;
|
||||||
|
console.warn("⚠️ Supabase connection error:", error?.message ?? err);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
try {
|
||||||
|
console.log("🔍 Testing Supabase auth endpoint...");
|
||||||
|
const { error } = await supabase.auth.getSession();
|
||||||
|
if (error) {
|
||||||
|
console.warn("⚠️ Supabase auth test failed:", error.message);
|
||||||
|
} else {
|
||||||
|
console.log("✅ Supabase auth endpoint accessible");
|
||||||
|
}
|
||||||
|
} catch (authErr) {
|
||||||
|
const error = authErr as SupabaseError;
|
||||||
|
console.warn("⚠️ Supabase auth endpoint error:", error?.message ?? authErr);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
export const auth = supabase.auth;
|
||||||
|
export const db = supabase.from.bind(supabase);
|
||||||
|
export const storage = supabase.storage;
|
||||||
|
export const channel = supabase.channel.bind(supabase);
|
||||||
|
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
(window as any).testSupabase = async () => {
|
||||||
|
console.log("🧪 Manual Supabase Test");
|
||||||
|
console.log("URL:", supabaseUrl);
|
||||||
|
console.log("Key configured:", !!supabaseAnonKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const testLogin = await supabase.auth.signInWithPassword({
|
||||||
|
email: "test@example.com",
|
||||||
|
password: "test123",
|
||||||
|
});
|
||||||
|
console.log("Auth test result:", testLogin);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Auth test error:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from("user_profiles")
|
||||||
|
.select("*")
|
||||||
|
.limit(1);
|
||||||
|
console.log("Database test - data:", data, "error:", error);
|
||||||
|
} catch (dbError) {
|
||||||
|
console.error("Database test error:", dbError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue