From 2493f958de19788ed5c31165be4c46b8263adffb Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 12:12:07 +0000 Subject: [PATCH] Refactor supabase.ts into modules Refactor the supabase.ts file into smaller modules, separating test functionalities and default client configurations while preserving all code functionalities. --- src/lib/supabase.ts | 267 ------------------------------------- src/lib/supabase/client.ts | 132 ++++++++++++++++++ src/lib/supabase/config.ts | 29 ++++ src/lib/supabase/index.ts | 11 ++ src/lib/supabase/tests.ts | 119 +++++++++++++++++ 5 files changed, 291 insertions(+), 267 deletions(-) delete mode 100644 src/lib/supabase.ts create mode 100644 src/lib/supabase/client.ts create mode 100644 src/lib/supabase/config.ts create mode 100644 src/lib/supabase/index.ts create mode 100644 src/lib/supabase/tests.ts diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts deleted file mode 100644 index 3847cf8..0000000 --- a/src/lib/supabase.ts +++ /dev/null @@ -1,267 +0,0 @@ - -import { createClient } from '@supabase/supabase-js'; - -// 온프레미스 Supabase URL과 anon key 설정 -const getSupabaseUrl = () => { - // 로컬 스토리지에서 설정된 URL을 우선 사용 - const storedUrl = localStorage.getItem('supabase_url'); - if (storedUrl) return storedUrl; - - // 환경 변수 또는 기본값 사용 - return process.env.SUPABASE_URL || 'http://a11.ism.kr:8000'; -}; - -const getSupabaseKey = () => { - // 로컬 스토리지에서 설정된 키를 우선 사용 - const storedKey = localStorage.getItem('supabase_key'); - if (storedKey) return storedKey; - - // 환경 변수 또는 기본값 사용 - return process.env.SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzQyMDM5MzU4LCJleHAiOjQ4OTU2MzkzNTh9.XK0vetdwv_H2MHj4ewTfZGtSbrbSNDaV5xJhNo_Hdp8'; -}; - -const supabaseUrl = getSupabaseUrl(); -const supabaseAnonKey = getSupabaseKey(); - -// 유효한 URL이 설정되었는지 확인 -const isValidUrl = supabaseUrl && supabaseAnonKey && - !supabaseUrl.includes('your-onpremise-supabase-url') && - !supabaseAnonKey.includes('your-onpremise-anon-key'); - -let supabaseClient; - -try { - console.log(`Supabase 클라이언트 생성 시도: ${supabaseUrl}`); - - // Supabase 클라이언트 생성 - supabaseClient = createClient(supabaseUrl, supabaseAnonKey, { - auth: { - autoRefreshToken: true, - persistSession: true, - // 온프레미스 설치를 위한 추가 설정 - flowType: 'implicit', - }, - global: { - fetch: (url, options) => { - // CORS 디버깅을 위한 사용자 정의 fetch - console.log('Supabase fetch 요청:', url); - return fetch(url, options).then(response => { - console.log('Supabase 응답 상태:', response.status); - return response; - }).catch(err => { - console.error('Supabase fetch 오류:', err); - throw err; - }); - } - } - }); - - // CORS 문제 확인을 위한 기본 헤더 테스트 - (async () => { - try { - // 기본 서버 상태 확인 (CORS 테스트) - console.log('Supabase 서버 상태 확인 중...'); - const response = await fetch(`${supabaseUrl}/rest/v1/`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - 'apikey': supabaseAnonKey, - }, - }); - - if (response.ok) { - console.log('Supabase REST API 연결 성공:', response.status); - } else { - console.warn('Supabase REST API 연결 실패:', response.status, response.statusText); - // 응답 세부 정보 로깅 - try { - const errorText = await response.text(); - console.warn('Supabase REST API 오류 응답:', errorText); - } catch (e) { - console.error('응답 내용 읽기 실패:', e); - } - } - } catch (err) { - console.error('Supabase 서버 상태 확인 중 오류 (CORS 문제 가능성):', err); - } - })(); - - // Supabase 연결 테스트 - (async () => { - try { - console.log('Supabase 인증 테스트 시도 중...'); - const { data, error } = await supabaseClient.auth.getSession(); - if (error) { - console.warn('Supabase 연결 테스트 실패:', error.message); - } else { - console.log('Supabase 연결 성공!', data); - } - - // 추가 테스트: 공개 데이터 조회 시도 - try { - console.log('Supabase 데이터베이스 공개 테이블 조회 시도...'); - const { data: tableData, error: tableError } = await supabaseClient - .from('transactions') - .select('*') - .limit(1); - - if (tableError) { - console.warn('Supabase 데이터베이스 테스트 실패:', tableError.message); - } else { - console.log('Supabase 데이터베이스 테스트 성공:', tableData); - } - } catch (dbErr) { - console.error('Supabase 데이터베이스 테스트 중 예외 발생:', dbErr); - } - } catch (err) { - console.error('Supabase 연결 확인 중 오류:', err); - } - })(); - - // Supabase 연결 로그 - console.log('Supabase 클라이언트가 생성되었습니다.'); - - // 유효성 검사 로그 - if (!isValidUrl) { - console.warn('경고: 기본 Supabase URL 또는 Anon Key가 감지되었습니다. Supabase 설정 페이지에서 온프레미스 설정을 구성하세요.'); - } -} catch (error) { - console.error('Supabase 클라이언트 생성 오류:', error); - - // 더미 클라이언트 생성 (앱이 완전히 실패하지 않도록) - supabaseClient = { - auth: { - getUser: () => Promise.resolve({ data: { user: null } }), - getSession: () => Promise.resolve({ data: { session: null } }), - signInWithPassword: () => Promise.reject(new Error('Supabase 설정이 필요합니다')), - signUp: () => Promise.reject(new Error('Supabase 설정이 필요합니다')), - signOut: () => Promise.resolve({ error: null }), - onAuthStateChange: () => ({ data: { subscription: { unsubscribe: () => {} } } }), - }, - from: () => ({ - select: () => ({ eq: () => ({ data: null, error: new Error('Supabase 설정이 필요합니다') }) }), - insert: () => ({ error: new Error('Supabase 설정이 필요합니다') }), - delete: () => ({ eq: () => ({ error: new Error('Supabase 설정이 필요합니다') }) }), - }), - }; -} - -export const supabase = supabaseClient; - -// 온프레미스 연결을 위한 설정 도우미 함수 -export const configureSupabase = (url: string, key: string) => { - // 로컬 스토리지에 설정 저장 - localStorage.setItem('supabase_url', url); - localStorage.setItem('supabase_key', key); - - // 페이지 새로고침 - 새로운 설정으로 Supabase 클라이언트 초기화 - window.location.reload(); -}; - -// 테스트용 직접 로그인 함수 (디버깅 전용) -export const testSupabaseLogin = async (email: string, password: string) => { - try { - console.log('테스트 로그인 시도:', email); - - const { data, error } = await supabaseClient.auth.signInWithPassword({ - email, - password - }); - - if (error) { - console.error('테스트 로그인 오류:', error); - return { success: false, error }; - } - - console.log('테스트 로그인 성공:', data); - return { success: true, data }; - } catch (err) { - console.error('테스트 로그인 중 예외 발생:', err); - return { success: false, error: err }; - } -}; - -// API 테스트 도우미 함수 -export const testSupabaseConnection = async () => { - const results = { - url: supabaseUrl, - client: !!supabaseClient, - restApi: false, - auth: false, - database: false, - errors: [] as string[] - }; - - try { - // 1. REST API 접근 테스트 - try { - console.log('REST API 테스트 시작...'); - const response = await fetch(`${supabaseUrl}/rest/v1/`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - 'apikey': supabaseAnonKey, - }, - }); - - results.restApi = response.ok; - if (!response.ok) { - const errorBody = await response.text(); - results.errors.push(`REST API 오류(${response.status} ${response.statusText}): ${errorBody || '응답 없음'}`); - console.error('REST API 테스트 실패:', response.status, errorBody); - } else { - console.log('REST API 테스트 성공'); - } - } catch (err: any) { - results.errors.push(`REST API 예외: ${err.message || '알 수 없는 오류'}`); - console.error('REST API 테스트 중 예외:', err); - } - - // 2. 인증 서비스 테스트 - try { - console.log('인증 서비스 테스트 시작...'); - const { data, error } = await supabaseClient.auth.getSession(); - results.auth = !error; - if (error) { - results.errors.push(`인증 오류: ${error.message}`); - console.error('인증 테스트 실패:', error); - } else { - console.log('인증 테스트 성공'); - } - } catch (err: any) { - results.errors.push(`인증 예외: ${err.message || '알 수 없는 오류'}`); - console.error('인증 테스트 중 예외:', err); - } - - // 3. 데이터베이스 연결 테스트 - try { - console.log('데이터베이스 연결 테스트 시작...'); - const { data, error } = await supabaseClient - .from('transactions') - .select('*') - .limit(1); - - results.database = !error; - if (error) { - results.errors.push(`데이터베이스 오류: ${error.message}`); - console.error('데이터베이스 테스트 실패:', error); - } else { - console.log('데이터베이스 테스트 성공', data); - } - } catch (err: any) { - results.errors.push(`데이터베이스 예외: ${err.message || '알 수 없는 오류'}`); - console.error('데이터베이스 테스트 중 예외:', err); - } - - // 오류가 없는 경우 메시지 추가 - if (results.errors.length === 0) { - results.errors.push('모든 테스트 통과! 연결 상태가 정상입니다.'); - } - } catch (err: any) { - results.errors.push(`테스트 실행 예외: ${err.message || '알 수 없는 오류'}`); - console.error('전체 테스트 실행 중 예외:', err); - } - - console.log('Supabase 연결 테스트 결과:', results); - return results; -}; diff --git a/src/lib/supabase/client.ts b/src/lib/supabase/client.ts new file mode 100644 index 0000000..3d46105 --- /dev/null +++ b/src/lib/supabase/client.ts @@ -0,0 +1,132 @@ + +import { createClient } from '@supabase/supabase-js'; +import { getSupabaseUrl, getSupabaseKey } from './config'; + +const supabaseUrl = getSupabaseUrl(); +const supabaseAnonKey = getSupabaseKey(); + +// 유효한 URL이 설정되었는지 확인 +const isValidUrl = supabaseUrl && supabaseAnonKey && + !supabaseUrl.includes('your-onpremise-supabase-url') && + !supabaseAnonKey.includes('your-onpremise-anon-key'); + +let supabaseClient; + +try { + console.log(`Supabase 클라이언트 생성 시도: ${supabaseUrl}`); + + // Supabase 클라이언트 생성 + supabaseClient = createClient(supabaseUrl, supabaseAnonKey, { + auth: { + autoRefreshToken: true, + persistSession: true, + // 온프레미스 설치를 위한 추가 설정 + flowType: 'implicit', + }, + global: { + fetch: (url, options) => { + // CORS 디버깅을 위한 사용자 정의 fetch + console.log('Supabase fetch 요청:', url); + return fetch(url, options).then(response => { + console.log('Supabase 응답 상태:', response.status); + return response; + }).catch(err => { + console.error('Supabase fetch 오류:', err); + throw err; + }); + } + } + }); + + // CORS 문제 확인을 위한 기본 헤더 테스트 + (async () => { + try { + // 기본 서버 상태 확인 (CORS 테스트) + console.log('Supabase 서버 상태 확인 중...'); + const response = await fetch(`${supabaseUrl}/rest/v1/`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'apikey': supabaseAnonKey, + }, + }); + + if (response.ok) { + console.log('Supabase REST API 연결 성공:', response.status); + } else { + console.warn('Supabase REST API 연결 실패:', response.status, response.statusText); + // 응답 세부 정보 로깅 + try { + const errorText = await response.text(); + console.warn('Supabase REST API 오류 응답:', errorText); + } catch (e) { + console.error('응답 내용 읽기 실패:', e); + } + } + } catch (err) { + console.error('Supabase 서버 상태 확인 중 오류 (CORS 문제 가능성):', err); + } + })(); + + // Supabase 연결 테스트 + (async () => { + try { + console.log('Supabase 인증 테스트 시도 중...'); + const { data, error } = await supabaseClient.auth.getSession(); + if (error) { + console.warn('Supabase 연결 테스트 실패:', error.message); + } else { + console.log('Supabase 연결 성공!', data); + } + + // 추가 테스트: 공개 데이터 조회 시도 + try { + console.log('Supabase 데이터베이스 공개 테이블 조회 시도...'); + const { data: tableData, error: tableError } = await supabaseClient + .from('transactions') + .select('*') + .limit(1); + + if (tableError) { + console.warn('Supabase 데이터베이스 테스트 실패:', tableError.message); + } else { + console.log('Supabase 데이터베이스 테스트 성공:', tableData); + } + } catch (dbErr) { + console.error('Supabase 데이터베이스 테스트 중 예외 발생:', dbErr); + } + } catch (err) { + console.error('Supabase 연결 확인 중 오류:', err); + } + })(); + + // Supabase 연결 로그 + console.log('Supabase 클라이언트가 생성되었습니다.'); + + // 유효성 검사 로그 + if (!isValidUrl) { + console.warn('경고: 기본 Supabase URL 또는 Anon Key가 감지되었습니다. Supabase 설정 페이지에서 온프레미스 설정을 구성하세요.'); + } +} catch (error) { + console.error('Supabase 클라이언트 생성 오류:', error); + + // 더미 클라이언트 생성 (앱이 완전히 실패하지 않도록) + supabaseClient = { + auth: { + getUser: () => Promise.resolve({ data: { user: null } }), + getSession: () => Promise.resolve({ data: { session: null } }), + signInWithPassword: () => Promise.reject(new Error('Supabase 설정이 필요합니다')), + signUp: () => Promise.reject(new Error('Supabase 설정이 필요합니다')), + signOut: () => Promise.resolve({ error: null }), + onAuthStateChange: () => ({ data: { subscription: { unsubscribe: () => {} } } }), + }, + from: () => ({ + select: () => ({ eq: () => ({ data: null, error: new Error('Supabase 설정이 필요합니다') }) }), + insert: () => ({ error: new Error('Supabase 설정이 필요합니다') }), + delete: () => ({ eq: () => ({ error: new Error('Supabase 설정이 필요합니다') }) }), + }), + }; +} + +export const supabase = supabaseClient; +export { isValidUrl }; diff --git a/src/lib/supabase/config.ts b/src/lib/supabase/config.ts new file mode 100644 index 0000000..c2c1ac6 --- /dev/null +++ b/src/lib/supabase/config.ts @@ -0,0 +1,29 @@ + +// 온프레미스 Supabase URL과 anon key 설정 +export const getSupabaseUrl = () => { + // 로컬 스토리지에서 설정된 URL을 우선 사용 + const storedUrl = localStorage.getItem('supabase_url'); + if (storedUrl) return storedUrl; + + // 환경 변수 또는 기본값 사용 + return process.env.SUPABASE_URL || 'http://a11.ism.kr:8000'; +}; + +export const getSupabaseKey = () => { + // 로컬 스토리지에서 설정된 키를 우선 사용 + const storedKey = localStorage.getItem('supabase_key'); + if (storedKey) return storedKey; + + // 환경 변수 또는 기본값 사용 + return process.env.SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzQyMDM5MzU4LCJleHAiOjQ4OTU2MzkzNTh9.XK0vetdwv_H2MHj4ewTfZGtSbrbSNDaV5xJhNo_Hdp8'; +}; + +// 온프레미스 연결을 위한 설정 도우미 함수 +export const configureSupabase = (url: string, key: string) => { + // 로컬 스토리지에 설정 저장 + localStorage.setItem('supabase_url', url); + localStorage.setItem('supabase_key', key); + + // 페이지 새로고침 - 새로운 설정으로 Supabase 클라이언트 초기화 + window.location.reload(); +}; diff --git a/src/lib/supabase/index.ts b/src/lib/supabase/index.ts new file mode 100644 index 0000000..58284df --- /dev/null +++ b/src/lib/supabase/index.ts @@ -0,0 +1,11 @@ + +// 메인 내보내기 파일 + +// Supabase 클라이언트 내보내기 +export { supabase } from './client'; + +// 설정 관련 유틸리티 내보내기 +export { configureSupabase } from './config'; + +// 테스트 도구 내보내기 +export { testSupabaseLogin, testSupabaseConnection } from './tests'; diff --git a/src/lib/supabase/tests.ts b/src/lib/supabase/tests.ts new file mode 100644 index 0000000..a131655 --- /dev/null +++ b/src/lib/supabase/tests.ts @@ -0,0 +1,119 @@ + +import { supabase } from './client'; + +// 테스트용 직접 로그인 함수 (디버깅 전용) +export const testSupabaseLogin = async (email: string, password: string) => { + try { + console.log('테스트 로그인 시도:', email); + + const { data, error } = await supabase.auth.signInWithPassword({ + email, + password + }); + + if (error) { + console.error('테스트 로그인 오류:', error); + return { success: false, error }; + } + + console.log('테스트 로그인 성공:', data); + return { success: true, data }; + } catch (err) { + console.error('테스트 로그인 중 예외 발생:', err); + return { success: false, error: err }; + } +}; + +// API 테스트 도우미 함수 +export const testSupabaseConnection = async () => { + const results = { + url: getSupabaseUrl(), + client: !!supabase, + restApi: false, + auth: false, + database: false, + errors: [] as string[] + }; + + try { + // 1. REST API 접근 테스트 + try { + console.log('REST API 테스트 시작...'); + const response = await fetch(`${results.url}/rest/v1/`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'apikey': getSupabaseKey(), + }, + }); + + results.restApi = response.ok; + if (!response.ok) { + const errorBody = await response.text(); + results.errors.push(`REST API 오류(${response.status} ${response.statusText}): ${errorBody || '응답 없음'}`); + console.error('REST API 테스트 실패:', response.status, errorBody); + } else { + console.log('REST API 테스트 성공'); + } + } catch (err: any) { + results.errors.push(`REST API 예외: ${err.message || '알 수 없는 오류'}`); + console.error('REST API 테스트 중 예외:', err); + } + + // 2. 인증 서비스 테스트 + try { + console.log('인증 서비스 테스트 시작...'); + const { data, error } = await supabase.auth.getSession(); + results.auth = !error; + if (error) { + results.errors.push(`인증 오류: ${error.message}`); + console.error('인증 테스트 실패:', error); + } else { + console.log('인증 테스트 성공'); + } + } catch (err: any) { + results.errors.push(`인증 예외: ${err.message || '알 수 없는 오류'}`); + console.error('인증 테스트 중 예외:', err); + } + + // 3. 데이터베이스 연결 테스트 + try { + console.log('데이터베이스 연결 테스트 시작...'); + const { data, error } = await supabase + .from('transactions') + .select('*') + .limit(1); + + results.database = !error; + if (error) { + results.errors.push(`데이터베이스 오류: ${error.message}`); + console.error('데이터베이스 테스트 실패:', error); + } else { + console.log('데이터베이스 테스트 성공', data); + } + } catch (err: any) { + results.errors.push(`데이터베이스 예외: ${err.message || '알 수 없는 오류'}`); + console.error('데이터베이스 테스트 중 예외:', err); + } + + // 오류가 없는 경우 메시지 추가 + if (results.errors.length === 0) { + results.errors.push('모든 테스트 통과! 연결 상태가 정상입니다.'); + } + } catch (err: any) { + results.errors.push(`테스트 실행 예외: ${err.message || '알 수 없는 오류'}`); + console.error('전체 테스트 실행 중 예외:', err); + } + + console.log('Supabase 연결 테스트 결과:', results); + return results; +}; + +// 필요한 함수 불러오기 +function getSupabaseUrl() { + return localStorage.getItem('supabase_url') || process.env.SUPABASE_URL || 'http://a11.ism.kr:8000'; +} + +function getSupabaseKey() { + return localStorage.getItem('supabase_key') || process.env.SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzQyMDM5MzU4LCJleHAiOjQ4OTU2MzkzNTh9.XK0vetdwv_H2MHj4ewTfZGtSbrbSNDaV5xJhNo_Hdp8'; +}