@@ -41,6 +41,42 @@ export const formatError = (error: unknown): string => {
4141 return String ( error ) ;
4242} ;
4343
44+ /**
45+ * Defect(예측되지 않은 에러)에서 정보 추출
46+ */
47+ const extractDefectInfo = (
48+ defect : unknown ,
49+ ) : { summary : string ; details : string } => {
50+ // Effect Tagged Error인 경우
51+ if ( defect && typeof defect === 'object' && '_tag' in defect ) {
52+ const tag = ( defect as { _tag : string } ) . _tag ;
53+ const message =
54+ 'message' in defect ? String ( ( defect as { message : unknown } ) . message ) : '' ;
55+ return {
56+ summary : `${ tag } ${ message ? `: ${ message } ` : '' } ` ,
57+ details : `Tagged Error [${ tag } ]: ${ JSON . stringify ( defect , null , 2 ) } ` ,
58+ } ;
59+ }
60+
61+ // 일반 객체인 경우
62+ if ( defect !== null && typeof defect === 'object' ) {
63+ const keys = Object . keys ( defect ) ;
64+ const summary =
65+ keys . length > 0
66+ ? `Object with keys: ${ keys . slice ( 0 , 3 ) . join ( ', ' ) } ${ keys . length > 3 ? '...' : '' } `
67+ : 'Empty object' ;
68+ return {
69+ summary,
70+ details : JSON . stringify ( defect , null , 2 ) ,
71+ } ;
72+ }
73+
74+ return {
75+ summary : String ( defect ) ,
76+ details : `Value (${ typeof defect } ): ${ String ( defect ) } ` ,
77+ } ;
78+ } ;
79+
4480// Effect Cause를 프로덕션용으로 포맷팅
4581export const formatCauseForProduction = (
4682 cause : Cause . Cause < unknown > ,
@@ -49,7 +85,16 @@ export const formatCauseForProduction = (
4985 if ( failure . _tag === 'Some' ) {
5086 return formatError ( failure . value ) ;
5187 }
52- return 'Unknown error occurred' ;
88+
89+ // Defect 정보도 포함
90+ const defects = Cause . defects ( cause ) ;
91+ if ( defects . length > 0 ) {
92+ const firstDefect = Chunk . unsafeGet ( defects , 0 ) ;
93+ const info = extractDefectInfo ( firstDefect ) ;
94+ return `Unexpected error: ${ info . summary } ` ;
95+ }
96+
97+ return 'Effect execution failed' ;
5398} ;
5499
55100// Effect 프로그램의 실행 결과를 안전하게 처리
@@ -62,19 +107,30 @@ export const runSafeSync = <E, A>(effect: Effect.Effect<A, E>): A => {
62107 if ( failure . _tag === 'Some' ) {
63108 throw toCompatibleError ( failure . value ) ;
64109 }
110+ // 예측되지 않은 예외(Defect)인지 확인
65111 const defects = Cause . defects ( cause ) ;
66112 if ( defects . length > 0 ) {
67113 const firstDefect = Chunk . unsafeGet ( defects , 0 ) ;
68114 if ( firstDefect instanceof Error ) {
69115 throw firstDefect ;
70116 }
71117 const isProduction = process . env . NODE_ENV === 'production' ;
118+ const defectInfo = extractDefectInfo ( firstDefect ) ;
72119 const message = isProduction
73- ? `Unexpected error: ${ String ( firstDefect ) } `
74- : `Unexpected error: ${ String ( firstDefect ) } \nCause: ${ Cause . pretty ( cause ) } ` ;
75- throw new Error ( message ) ;
120+ ? `Unexpected error: ${ defectInfo . summary } `
121+ : `Unexpected error: ${ defectInfo . details } \nCause: ${ Cause . pretty ( cause ) } ` ;
122+ const error = new Error ( message ) ;
123+ error . name = 'UnexpectedDefectError' ;
124+ throw error ;
76125 }
77- throw new Error ( `Unhandled Exit: ${ Cause . pretty ( cause ) } ` ) ;
126+ // 그 외 (예: 중단)의 경우
127+ const isProduction = process . env . NODE_ENV === 'production' ;
128+ const message = isProduction
129+ ? 'Effect execution failed unexpectedly'
130+ : `Unhandled Effect Exit:\n${ Cause . pretty ( cause ) } ` ;
131+ const error = new Error ( message ) ;
132+ error . name = 'UnhandledExitError' ;
133+ throw error ;
78134 } ,
79135 onSuccess : value => value ,
80136 } ) ;
@@ -98,21 +154,26 @@ export const runSafePromise = <E, A>(
98154 if ( defects . length > 0 ) {
99155 const firstDefect = Chunk . unsafeGet ( defects , 0 ) ;
100156 if ( firstDefect instanceof Error ) {
101- // 원본 Error 객체를 그대로 반환
102157 return Promise . reject ( firstDefect ) ;
103158 }
104- // Error 객체가 아니면 환경에 따라 상세 정보 포함
105159 const isProduction = process . env . NODE_ENV === 'production' ;
160+ const defectInfo = extractDefectInfo ( firstDefect ) ;
106161 const message = isProduction
107- ? `Unexpected error: ${ String ( firstDefect ) } `
108- : `Unexpected error: ${ String ( firstDefect ) } \nCause: ${ Cause . pretty ( cause ) } ` ;
109- return Promise . reject ( new Error ( message ) ) ;
162+ ? `Unexpected error: ${ defectInfo . summary } `
163+ : `Unexpected error: ${ defectInfo . details } \nCause: ${ Cause . pretty ( cause ) } ` ;
164+ const error = new Error ( message ) ;
165+ error . name = 'UnexpectedDefectError' ;
166+ return Promise . reject ( error ) ;
110167 }
111168
112- // 3. 그 외 (예: 중단)의 경우, Cause를 문자열로 변환하여 반환
113- return Promise . reject (
114- new Error ( `Unhandled Exit: ${ Cause . pretty ( cause ) } ` ) ,
115- ) ;
169+ // 3. 그 외 (예: 중단)의 경우
170+ const isProduction = process . env . NODE_ENV === 'production' ;
171+ const message = isProduction
172+ ? 'Effect execution failed unexpectedly'
173+ : `Unhandled Effect Exit:\n${ Cause . pretty ( cause ) } ` ;
174+ const error = new Error ( message ) ;
175+ error . name = 'UnhandledExitError' ;
176+ return Promise . reject ( error ) ;
116177 } ,
117178 onSuccess : value => Promise . resolve ( value ) ,
118179 } ) ,
@@ -325,10 +386,36 @@ export const toCompatibleError = (effectError: unknown): Error => {
325386 return error ;
326387 }
327388
389+ // Unknown 에러 타입에 대한 개선된 처리
390+ // Tagged Error 확인 (_tag 속성 존재 여부)
391+ if ( effectError && typeof effectError === 'object' && '_tag' in effectError ) {
392+ const taggedError = effectError as { _tag : string } ;
393+ const formatted = formatError ( effectError ) ;
394+ const error = new Error ( formatted ) ;
395+ error . name = `UnknownTaggedError_${ taggedError . _tag } ` ;
396+ if ( ! isProduction ) {
397+ Object . defineProperty ( error , 'originalError' , {
398+ value : effectError ,
399+ writable : false ,
400+ enumerable : true ,
401+ } ) ;
402+ }
403+ if ( isProduction ) {
404+ delete error . stack ;
405+ }
406+ return error ;
407+ }
408+
328409 const formatted = formatError ( effectError ) ;
329- // 하위 호환성을 위해 여전히 Error 사용하지만 스택 제거
330410 const error = new Error ( formatted ) ;
331- error . name = 'FromSolapiError' ;
411+ error . name = 'UnknownSolapiError' ;
412+ if ( ! isProduction ) {
413+ Object . defineProperty ( error , 'originalError' , {
414+ value : effectError ,
415+ writable : false ,
416+ enumerable : true ,
417+ } ) ;
418+ }
332419 if ( isProduction ) {
333420 delete error . stack ;
334421 }
0 commit comments