@nine-lab/nine-mu 0.1.346 → 0.1.348
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nine-mu.js +159 -6
- package/dist/nine-mu.js.map +1 -1
- package/dist/nine-mu.umd.js +3 -3
- package/dist/nine-mu.umd.js.map +1 -1
- package/package.json +2 -1
- package/src/components/exception/ExceptionHook.js +127 -25
- package/src/index.js +2 -2
- package/vite.config.js +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nine-lab/nine-mu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.348",
|
|
4
4
|
"description": "AI-Driven Full-Stack Code Fabrication Engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/nine-mu.umd.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"@nine-lab/nine-nomenu": "*",
|
|
26
26
|
"@nine-lab/nine-util": "^0.9.126",
|
|
27
27
|
"@nine-lab/nine-ux": "^0.1.244",
|
|
28
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
28
29
|
"terser": "^5.31.0",
|
|
29
30
|
"vite": "^6.0.0"
|
|
30
31
|
},
|
|
@@ -1,30 +1,85 @@
|
|
|
1
|
-
// src/components/exception/ExceptionHook.js
|
|
2
|
-
import { nine } from '@nine-lab/nine-util';
|
|
3
|
-
import { trace } from '@nopeer';
|
|
4
|
-
// npm 라이브러리용 패키지의 핵심 소스 (예: src/components/ContentErrorBoundary.jsx)
|
|
5
1
|
import React from 'react';
|
|
6
2
|
|
|
3
|
+
// ==========================================
|
|
4
|
+
// 1. 외부에서 수정 및 관리가 용이하도록 CSS 분리
|
|
5
|
+
// ==========================================
|
|
6
|
+
export const NineExceptionStyles = {
|
|
7
|
+
container: {
|
|
8
|
+
padding: '30px',
|
|
9
|
+
margin: '20px',
|
|
10
|
+
background: '#FFF5F5',
|
|
11
|
+
border: '1px solid #FEB2B2',
|
|
12
|
+
borderRadius: '8px',
|
|
13
|
+
fontFamily: 'sans-serif',
|
|
14
|
+
textAlign: 'left'
|
|
15
|
+
},
|
|
16
|
+
title: {
|
|
17
|
+
color: '#C53030',
|
|
18
|
+
marginTop: 0,
|
|
19
|
+
fontSize: '18px',
|
|
20
|
+
display: 'flex',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
gap: '8px'
|
|
23
|
+
},
|
|
24
|
+
label: {
|
|
25
|
+
margin: '10px 0 5px 0',
|
|
26
|
+
fontWeight: 'bold',
|
|
27
|
+
color: '#4A5568'
|
|
28
|
+
},
|
|
29
|
+
pre: {
|
|
30
|
+
background: '#1A202C',
|
|
31
|
+
color: '#EDF2F7',
|
|
32
|
+
padding: '15px',
|
|
33
|
+
borderRadius: '6px',
|
|
34
|
+
overflowX: 'auto',
|
|
35
|
+
whiteSpace: 'pre-wrap',
|
|
36
|
+
fontFamily: 'monospace',
|
|
37
|
+
fontSize: '14px'
|
|
38
|
+
},
|
|
39
|
+
footer: {
|
|
40
|
+
marginTop: '15px',
|
|
41
|
+
fontSize: '14px',
|
|
42
|
+
color: '#718096',
|
|
43
|
+
display: 'flex',
|
|
44
|
+
flexDirection: 'column',
|
|
45
|
+
gap: '10px'
|
|
46
|
+
},
|
|
47
|
+
button: {
|
|
48
|
+
padding: '10px 16px',
|
|
49
|
+
background: '#E53E3E',
|
|
50
|
+
color: '#FFFFFF',
|
|
51
|
+
border: 'none',
|
|
52
|
+
borderRadius: '6px',
|
|
53
|
+
cursor: 'pointer',
|
|
54
|
+
fontWeight: 'bold',
|
|
55
|
+
fontSize: '14px',
|
|
56
|
+
alignSelf: 'flex-start',
|
|
57
|
+
transition: 'background 0.2s',
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// ==========================================
|
|
62
|
+
// 2. 컴포넌트 본문
|
|
63
|
+
// ==========================================
|
|
7
64
|
export class NineExceptionHook extends React.Component {
|
|
65
|
+
|
|
8
66
|
constructor(props) {
|
|
9
67
|
super(props);
|
|
10
|
-
|
|
68
|
+
// 관제탑 전송 상태 관리를 위해 정송 단계(idle, sending, success) 추가
|
|
69
|
+
this.state = { hasError: false, error: null, reportStatus: 'idle' };
|
|
11
70
|
this.lastPath = window.location.pathname;
|
|
12
71
|
this.handleLocationChange = this.handleLocationChange.bind(this);
|
|
72
|
+
this.handleReport = this.handleReport.bind(this);
|
|
13
73
|
}
|
|
14
74
|
|
|
15
75
|
static getDerivedStateFromError(error) {
|
|
16
|
-
return { hasError: true, error };
|
|
76
|
+
return { hasError: true, error, reportStatus: 'idle' };
|
|
17
77
|
}
|
|
18
78
|
|
|
19
79
|
componentDidCatch(error, errorInfo) {
|
|
20
80
|
console.error("🚨 [Nine-Library] 본문 렌더링 에러 포착:", error);
|
|
21
81
|
|
|
22
|
-
//
|
|
23
|
-
if (window.triggerAutoRecovery) {
|
|
24
|
-
window.triggerAutoRecovery(error.message || String(error));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// 2. 라이브러리 확장성: 컴포넌트 자체 Props로 콜백을 넘겨받았다면 실행
|
|
82
|
+
// 자동 복구 엔진 호출 제거 (버튼 클릭 시 처리로 이관)
|
|
28
83
|
if (this.props.onCatch) {
|
|
29
84
|
this.props.onCatch(error, errorInfo);
|
|
30
85
|
}
|
|
@@ -45,31 +100,78 @@ export class NineExceptionHook extends React.Component {
|
|
|
45
100
|
if (this.state.hasError && this.lastPath !== window.location.pathname) {
|
|
46
101
|
console.log("✨ [Nine-Library] 페이지 주소 변경 감지 -> 리액트 에러 상태 초기화");
|
|
47
102
|
this.lastPath = window.location.pathname;
|
|
48
|
-
this.setState({ hasError: false, error: null });
|
|
103
|
+
this.setState({ hasError: false, error: null, reportStatus: 'idle' });
|
|
49
104
|
}
|
|
50
105
|
}, 10);
|
|
51
106
|
}
|
|
52
107
|
|
|
108
|
+
// 🚀 버튼 클릭 시 실행될 관제탑 수동 신고 핸들러
|
|
109
|
+
handleReport() {
|
|
110
|
+
if (this.state.reportStatus !== 'idle') return;
|
|
111
|
+
|
|
112
|
+
this.setState({ reportStatus: 'sending' });
|
|
113
|
+
const errorMessage = this.state.error?.message || String(this.state.error);
|
|
114
|
+
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
if (window.triggerAutoRecovery) {
|
|
117
|
+
window.triggerAutoRecovery(errorMessage);
|
|
118
|
+
} else {
|
|
119
|
+
console.warn("⚠️ [Nine-Library] window.triggerAutoRecovery 가 정의되지 않았습니다.");
|
|
120
|
+
}
|
|
121
|
+
this.setState({ reportStatus: 'success' });
|
|
122
|
+
}, 500); // 사용자 경험(UX) 피드백용 0.5초 딜레이
|
|
123
|
+
}
|
|
124
|
+
|
|
53
125
|
render() {
|
|
54
126
|
if (this.state.hasError) {
|
|
55
|
-
// 라이브러리 커스텀 UI 제공 (외부에서 커스텀 fallback UI를 주입하지 않았다면 기본 템플릿 사용)
|
|
56
127
|
if (this.props.fallback) {
|
|
57
128
|
return this.props.fallback(this.state.error);
|
|
58
129
|
}
|
|
59
130
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
131
|
+
const errorMessage = this.state.error?.message || String(this.state.error);
|
|
132
|
+
const customStyles = this.props.styles || {}; // props로 스타일 통째로 덮어쓰기 지원
|
|
133
|
+
|
|
134
|
+
// 버튼 텍스트 상태 제어
|
|
135
|
+
let buttonText = '🚀 관제탑에 에러 피드백 전송하기';
|
|
136
|
+
if (this.state.reportStatus === 'sending') buttonText = '⏳ 관제탑 연락 중...';
|
|
137
|
+
if (this.state.reportStatus === 'success') buttonText = '✅ 전송 완료! AI가 분석을 시작합니다.';
|
|
138
|
+
|
|
139
|
+
return React.createElement(
|
|
140
|
+
'div',
|
|
141
|
+
{
|
|
142
|
+
style: { ...NineExceptionStyles.container, ...customStyles.container, ...this.props.containerStyle }
|
|
143
|
+
},
|
|
144
|
+
React.createElement('h3', { style: { ...NineExceptionStyles.title, ...customStyles.title } }, '⚠️ 컴포넌트 빌드/렌더링 에러 감지'),
|
|
145
|
+
React.createElement('p', { style: { ...NineExceptionStyles.label, ...customStyles.label } }, '[에러 원인 로그]:'),
|
|
146
|
+
React.createElement('pre', { style: { ...NineExceptionStyles.pre, ...customStyles.pre } }, errorMessage),
|
|
147
|
+
|
|
148
|
+
// 하단 안내 영역 및 수동 전송 버튼
|
|
149
|
+
React.createElement(
|
|
150
|
+
'div',
|
|
151
|
+
{ style: { ...NineExceptionStyles.footer, ...customStyles.footer } },
|
|
152
|
+
React.createElement(
|
|
153
|
+
'button',
|
|
154
|
+
{
|
|
155
|
+
style: {
|
|
156
|
+
...NineExceptionStyles.button,
|
|
157
|
+
...customStyles.button,
|
|
158
|
+
backgroundColor: this.state.reportStatus === 'success' ? '#38A169' : (this.state.reportStatus === 'sending' ? '#A0AEC0' : '#E53E3E'),
|
|
159
|
+
cursor: this.state.reportStatus === 'idle' ? 'pointer' : 'not-allowed'
|
|
160
|
+
},
|
|
161
|
+
disabled: this.state.reportStatus !== 'idle',
|
|
162
|
+
onClick: this.handleReport
|
|
163
|
+
},
|
|
164
|
+
buttonText
|
|
165
|
+
),
|
|
166
|
+
this.state.reportStatus === 'success' && React.createElement(
|
|
167
|
+
'div',
|
|
168
|
+
{ style: { color: '#4A5568', fontSize: '13px', marginTop: '5px' } },
|
|
169
|
+
'🔄 AI가 소스 코드를 재수정하는 동안 잠시만 기다려주세요...'
|
|
170
|
+
)
|
|
171
|
+
)
|
|
71
172
|
);
|
|
72
173
|
}
|
|
174
|
+
|
|
73
175
|
return this.props.children;
|
|
74
176
|
}
|
|
75
177
|
}
|
package/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { NineDiff } from './components/NineDiff.js';
|
|
|
4
4
|
import { NineDiffPopup } from './components/NineDiffPopup.js';
|
|
5
5
|
import { NineMenuDiffPopup } from './components/NineMenuDiffPopup.js';
|
|
6
6
|
import './components/ChatMessage.js';
|
|
7
|
-
|
|
7
|
+
import { NineExceptionHook } from './components/exception/ExceptionHook.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Nine-Mu 엔진 메인 클래스
|
|
@@ -20,4 +20,4 @@ export const NineMu = {
|
|
|
20
20
|
|
|
21
21
|
// 기본 export 및 컴포넌트 export
|
|
22
22
|
export default NineMu;
|
|
23
|
-
export { NineChat, NineDiff, NineDiffPopup };
|
|
23
|
+
export { NineChat, NineDiff, NineDiffPopup, NineExceptionHook };
|
package/vite.config.js
CHANGED
|
@@ -19,7 +19,7 @@ export default defineConfig({
|
|
|
19
19
|
formats: ['es', 'umd']
|
|
20
20
|
},
|
|
21
21
|
rollupOptions: {
|
|
22
|
-
external: ['@nine-lab/nine-ai', '@nine-lab/nine-util', '@nine-lab/nine-ux'],
|
|
22
|
+
external: ['@nine-lab/nine-ai', '@nine-lab/nine-util', '@nine-lab/nine-ux', 'react', 'react-dom'],
|
|
23
23
|
output: {
|
|
24
24
|
globals: {
|
|
25
25
|
'@nine-lab/nine-ai': 'NineAi',
|
|
@@ -31,5 +31,9 @@ export default defineConfig({
|
|
|
31
31
|
minify: 'terser',
|
|
32
32
|
sourcemap: true,
|
|
33
33
|
emptyOutDir: true
|
|
34
|
+
},
|
|
35
|
+
esbuild: {
|
|
36
|
+
loader: 'jsx',
|
|
37
|
+
include: /src\/.*\.js$/, // src 폴더 내의 모든 .js 파일을 대상으로 지정
|
|
34
38
|
}
|
|
35
39
|
});
|