Refactor auth.utils.ts

Refactor auth.utils.ts into smaller modules for better organization and maintainability. Split functions into networkUtils.ts, responseUtils.ts, and toastUtils.ts based on their purpose.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-15 13:48:29 +00:00
parent 76f9b3b4df
commit 5b73eddd4f
9 changed files with 143 additions and 113 deletions

View File

@@ -1,229 +0,0 @@
import { toast } from '@/hooks/useToast.wrapper';
import { supabase } from '@/lib/supabase';
// 토스트 메시지 표시 유틸리티 함수
export const showAuthToast = (title: string, description: string, variant: 'default' | 'destructive' = 'default') => {
toast({ title, description, variant });
};
// 에러 메시지 처리 유틸리티 함수
export const handleNetworkError = (error: any): string => {
if (error.message && error.message.includes('fetch')) {
return '서버 연결에 실패했습니다. 네트워크 연결을 확인해주세요.';
} else if (error.message && error.message.includes('CORS')) {
return 'CORS 오류가 발생했습니다. 서버 설정 또는 CORS 프록시를 확인하세요.';
} else if (error.message && error.message.includes('NetworkError')) {
return '네트워크 오류가 발생했습니다. 인터넷 연결을 확인하세요.';
} else if (error.message && error.message.includes('json')) {
return '서버 응답 형식 오류: 서버가 올바른 JSON 응답을 반환하지 않았습니다.';
} else if (error.message && error.message.includes('timeout')) {
return '서버 응답 시간 초과: 서버가 응답하지 않습니다.';
} else if (error.message && error.message.includes('aborted')) {
return '요청이 중단되었습니다.';
}
return error.message || '예상치 못한 오류가 발생했습니다.';
};
// 응답 파싱 유틸리티 함수 개선
export const parseResponse = async (response: Response) => {
try {
// 비어있는 응답 또는 401 응답을 먼저 확인
if (response.status === 401) {
if (response.headers.get('content-length') === '0' || await response.clone().text() === '') {
return {
error: '인증 실패: 잘못된 인증 정보 또는 서버 설정 문제',
status: 401
};
}
}
// 응답 내용 확인 (디버깅용)
const responseText = await response.text();
console.log('응답 원본:', responseText, 'Status:', response.status);
// 빈 응답 또는 공백만 있는 응답 처리
if (!responseText || responseText.trim() === '') {
if (response.status === 401) {
return {
error: '인증 실패: 서버가 인증을 거부했습니다.',
status: 401
};
} else if (response.status === 404) {
return {
error: '서버 경로를 찾을 수 없습니다. Supabase URL을 확인하세요.',
status: 404
};
} else if (response.status >= 200 && response.status < 300) {
return {
success: true,
status: response.status,
message: '서버가 성공 상태를 반환했지만 응답 내용이 없습니다.'
};
} else {
return {
error: `서버가 빈 응답을 반환했습니다 (상태 코드: ${response.status})`,
status: response.status
};
}
}
try {
return JSON.parse(responseText);
} catch (parseError) {
console.error('JSON 파싱 오류:', parseError, '원본 텍스트:', responseText);
// HTTP 상태 코드에 따른 적절한 오류 메시지 반환
if (response.status === 401) {
return {
error: '인증 실패: 이메일 또는 비밀번호가 올바르지 않습니다.',
status: 401
};
} else if (response.status === 404) {
return {
error: '서버 경로를 찾을 수 없습니다. Supabase URL을 확인하세요.',
status: 404
};
} else if (response.status >= 500) {
return {
error: '서버 내부 오류가 발생했습니다.',
status: response.status
};
} else if (response.status >= 200 && response.status < 300) {
return {
success: true,
status: response.status,
message: '서버가 성공 상태를 반환했지만 JSON 형식이 아닙니다.'
};
} else {
return {
error: `응답 형식 오류 (상태 코드: ${response.status}): 서버가 올바른 JSON 응답을 반환하지 않았습니다.`,
status: response.status,
rawResponse: responseText
};
}
}
} catch (parseError) {
console.error('응답 파싱 오류:', parseError);
throw parseError;
}
};
// CORS 문제 확인
export const hasCorsIssue = (error: any): boolean => {
if (!error) return false;
const errorMessage = error.message || '';
return (
errorMessage.includes('Failed to fetch') ||
errorMessage.includes('CORS') ||
errorMessage.includes('Network') ||
errorMessage.includes('프록시')
);
};
// Supabase 연결 상태 확인
export const checkSupabaseConnection = async (): Promise<boolean> => {
try {
const { data, error } = await supabase.auth.getSession();
// 오류가 없으면 연결 성공
if (!error) {
return true;
}
// 오류 메시지 확인
if (error.message && (
error.message.includes('Failed to fetch') ||
error.message.includes('Network') ||
error.message.includes('CORS')
)) {
return false;
}
// 다른 오류는 연결은 됐지만 세션/인증 관련 오류이므로 연결은 성공
return true;
} catch (err) {
console.error('Supabase 연결 확인 중 오류:', err);
return false;
}
};
// 서버 연결 상태 검사 (개선 버전)
export const verifyServerConnection = async (): Promise<{
connected: boolean;
message: string;
statusCode?: number;
}> => {
try {
const start = Date.now();
// Supabase URL 가져오기
const supabaseUrl = supabase.auth.url;
// 단순 헬스 체크 요청
const response = await fetch(`${supabaseUrl}/`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
// 연결 확인만을 위한 요청이므로 짧은 타임아웃 설정
signal: AbortSignal.timeout(3000)
});
const elapsed = Date.now() - start;
if (response.ok || response.status === 401) {
// 401도 서버가 응답했다는 의미이므로 연결 성공으로 간주
return {
connected: true,
message: `서버 연결 성공 (응답 시간: ${elapsed}ms)`,
statusCode: response.status
};
} else {
return {
connected: false,
message: `서버 응답 오류: ${response.status} ${response.statusText}`,
statusCode: response.status
};
}
} catch (error: any) {
console.error('서버 연결 확인 중 오류:', error);
// 오류 유형에 따른 메시지 설정
let errorMessage = '알 수 없는 네트워크 오류';
if (error.message) {
if (error.message.includes('Failed to fetch')) {
errorMessage = 'CORS 정책 오류 또는 서버 연결 실패';
} else if (error.message.includes('NetworkError')) {
errorMessage = '네트워크 연결 실패';
} else if (error.message.includes('TypeError')) {
errorMessage = '네트워크 요청 형식 오류';
} else if (error.message.includes('timeout')) {
errorMessage = '서버 응답 시간 초과';
} else if (error.message.includes('aborted')) {
errorMessage = '요청이 중단됨';
} else {
errorMessage = error.message;
}
}
return {
connected: false,
message: errorMessage
};
}
};
// 서버 URL 검증
export const validateServerUrl = (url: string): boolean => {
try {
// URL 유효성 검사
new URL(url);
return true;
} catch (e) {
return false;
}
};

View File

@@ -1,6 +1,5 @@
import { supabase } from '@/lib/supabase';
import { handleNetworkError, showAuthToast } from './auth.utils';
import { handleNetworkError, showAuthToast } from '@/utils/auth';
export const resetPassword = async (email: string) => {
try {

View File

@@ -1,6 +1,10 @@
import { supabase } from '@/lib/supabase';
import { handleNetworkError, parseResponse, showAuthToast, verifyServerConnection } from './auth.utils';
import {
handleNetworkError,
parseResponse,
showAuthToast,
verifyServerConnection
} from '@/utils/auth';
export const signIn = async (email: string, password: string) => {
try {

View File

@@ -1,6 +1,5 @@
import { supabase } from '@/lib/supabase';
import { showAuthToast } from './auth.utils';
import { showAuthToast } from '@/utils/auth';
export const signOut = async (): Promise<void> => {
try {

View File

@@ -1,6 +1,9 @@
import { supabase } from '@/lib/supabase';
import { handleNetworkError, parseResponse, showAuthToast } from './auth.utils';
import {
handleNetworkError,
parseResponse,
showAuthToast
} from '@/utils/auth';
export const signUp = async (email: string, password: string, username: string) => {
try {