From d5ec9755730a0be2a2c83e2e2f255ee6e24082a4 Mon Sep 17 00:00:00 2001 From: jjamming Date: Sun, 17 May 2026 16:35:55 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20Supabase=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EB=88=84=EB=9D=BD=20=EC=8B=9C=20=EC=95=B1?= =?UTF-8?q?=20=ED=81=AC=EB=9E=98=EC=8B=9C=20=EB=8C=80=EC=8B=A0=20=ED=86=A0?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=95=88=EB=82=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - supabase.ts: 모듈 로드 시 throw 제거. env 누락 시 Proxy 기반 lazy client로 호출 시점에만 SupabaseConfigError 발생 - AuthContext: 미설정 환경에서는 세션 조회/구독을 건너뛰어 앱 부팅 보장 - LoginPage/SignupPage: GitHub OAuth 버튼도 try/catch 처리하여 unhandled rejection 방지 - error.ts: SupabaseConfigError 인식 및 사용자 친화적 메시지 반환 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/contexts/AuthContext.tsx | 7 ++++++- src/lib/error.ts | 5 +++++ src/lib/supabase.ts | 24 ++++++++++++++++++++---- src/pages/LoginPage.tsx | 10 +++++++++- src/pages/SignupPage.tsx | 10 +++++++++- 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/lib/contexts/AuthContext.tsx b/src/lib/contexts/AuthContext.tsx index 5feeab0..98fe200 100644 --- a/src/lib/contexts/AuthContext.tsx +++ b/src/lib/contexts/AuthContext.tsx @@ -1,6 +1,6 @@ import { createContext, useEffect, useState } from "react"; import type { User } from "@supabase/supabase-js"; -import { supabase } from "@/lib/supabase"; +import { supabase, isSupabaseConfigured } from "@/lib/supabase"; interface AuthContextType { user: User | null; @@ -17,6 +17,11 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const [isLoading, setIsLoading] = useState(true); useEffect(() => { + if (!isSupabaseConfigured) { + setIsLoading(false); + return; + } + supabase.auth.getSession().then(({ data: { session } }) => { setUser(session?.user ?? null); setIsLoading(false); diff --git a/src/lib/error.ts b/src/lib/error.ts index 6570fe8..781b4d5 100644 --- a/src/lib/error.ts +++ b/src/lib/error.ts @@ -1,4 +1,5 @@ import { AuthError } from "@supabase/supabase-js"; +import { SupabaseConfigError } from "@/lib/supabase"; const AUTH_ERROR_MESSAGE_MAP: Record = { email_exists: "이미 사용 중인 이메일입니다.", @@ -22,6 +23,10 @@ const AUTH_ERROR_MESSAGE_MAP: Record = { }; export function generateErrorMessage(error: unknown) { + if (error instanceof SupabaseConfigError) { + return error.message; + } + if (error instanceof AuthError && error.code) { return ( AUTH_ERROR_MESSAGE_MAP[error.code] ?? diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts index 31e474d..05fc244 100644 --- a/src/lib/supabase.ts +++ b/src/lib/supabase.ts @@ -1,10 +1,26 @@ -import { createClient } from "@supabase/supabase-js"; +import { createClient, type SupabaseClient } from "@supabase/supabase-js"; const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; const supabaseKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY; -if (!supabaseUrl || !supabaseKey) { - throw new Error("Supabase 환경변수가 없거나 잘못되었습니다."); +export const isSupabaseConfigured = Boolean(supabaseUrl && supabaseKey); + +export class SupabaseConfigError extends Error { + constructor() { + super("인증 서비스 설정이 누락되었습니다. 잠시 후 다시 시도해주세요."); + this.name = "SupabaseConfigError"; + } +} + +function createUnconfiguredClient(): SupabaseClient { + const handler: ProxyHandler = { + get() { + throw new SupabaseConfigError(); + }, + }; + return new Proxy({}, handler) as SupabaseClient; } -export const supabase = createClient(supabaseUrl, supabaseKey); +export const supabase: SupabaseClient = isSupabaseConfigured + ? createClient(supabaseUrl, supabaseKey) + : createUnconfiguredClient(); diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index 38461ba..01c87e3 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -41,6 +41,14 @@ const LoginPage = () => { } }; + const handleClickGitHubSignIn = async () => { + try { + await signInWithGitHub(); + } catch (error) { + toast.error(generateErrorMessage(error)); + } + }; + return (
@@ -88,7 +96,7 @@ const LoginPage = () => {