@nine-lab/nine-mu 0.1.344 โ 0.1.346
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 +7 -211
- 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 +1 -1
- package/src/components/exception/ExceptionHook.js +50 -211
- package/src/index.js +1 -1
package/package.json
CHANGED
|
@@ -1,238 +1,77 @@
|
|
|
1
1
|
// src/components/exception/ExceptionHook.js
|
|
2
2
|
import { nine } from '@nine-lab/nine-util';
|
|
3
3
|
import { trace } from '@nopeer';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.attachShadow({ mode: 'open' });
|
|
14
|
-
trace.log("๐ [nine-exception-hook] ์ธ์คํด์ค ์์ฑ๋จ");
|
|
4
|
+
// npm ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ฉ ํจํค์ง์ ํต์ฌ ์์ค (์: src/components/ContentErrorBoundary.jsx)
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
export class NineExceptionHook extends React.Component {
|
|
8
|
+
constructor(props) {
|
|
9
|
+
super(props);
|
|
10
|
+
this.state = { hasError: false, error: null };
|
|
11
|
+
this.lastPath = window.location.pathname;
|
|
12
|
+
this.handleLocationChange = this.handleLocationChange.bind(this);
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.#renderer();
|
|
20
|
-
this.#injectShadowStylesheet();
|
|
21
|
-
|
|
22
|
-
this.#setupGlobalSniffer();
|
|
23
|
-
|
|
24
|
-
window.addEventListener('unhandledrejection', this.#handlePromiseError, true);
|
|
25
|
-
window.addEventListener('popstate', this.#handleLocationChange);
|
|
26
|
-
document.addEventListener('click', this.#handleLocationChange, true);
|
|
15
|
+
static getDerivedStateFromError(error) {
|
|
16
|
+
return { hasError: true, error };
|
|
27
17
|
}
|
|
28
18
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
window.removeEventListener('error', this.#handleRuntimeError, true);
|
|
32
|
-
window.removeEventListener('unhandledrejection', this.#handlePromiseError, true);
|
|
33
|
-
window.removeEventListener('popstate', this.#handleLocationChange);
|
|
34
|
-
document.removeEventListener('click', this.#handleLocationChange, true);
|
|
19
|
+
componentDidCatch(error, errorInfo) {
|
|
20
|
+
console.error("๐จ [Nine-Library] ๋ณธ๋ฌธ ๋ ๋๋ง ์๋ฌ ํฌ์ฐฉ:", error);
|
|
35
21
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
// 1. ์ธ๋ถ ์ ์ญ ๋ณต๊ตฌ ์์ง(triggerAutoRecovery)์ด ์์ผ๋ฉด ํธ์ถ
|
|
23
|
+
if (window.triggerAutoRecovery) {
|
|
24
|
+
window.triggerAutoRecovery(error.message || String(error));
|
|
39
25
|
}
|
|
40
26
|
|
|
41
|
-
//
|
|
42
|
-
this
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
#setupGlobalSniffer() {
|
|
46
|
-
window.addEventListener('error', this.#handleRuntimeError, true);
|
|
47
|
-
trace.log("๐ [nine-exception-hook] window.addEventListener('error') ๋ฑ๋ก ์๋ฃ");
|
|
48
|
-
|
|
49
|
-
this.#oldOnError = window.onerror;
|
|
50
|
-
window.onerror = (message, source, lineno, colno, error) => {
|
|
51
|
-
trace.log("๐จ [nine-exception-hook] ์์ window.onerror ํฌ์ฐฉ!!", { message, source, lineno, error });
|
|
52
|
-
|
|
53
|
-
if (!this.#hasError) {
|
|
54
|
-
trace.log("๐ฏ [nine-exception-hook] ํ์ฌ ์๋ฌ ์ํ ์์ -> ์๋ฌ ๋ณด๋ ์ถ๋ ฅ ์๋");
|
|
55
|
-
const errorMessage = error?.message || message || "์ ์ ์๋ ๋ฐํ์ ์์ธ";
|
|
56
|
-
const errorStack = error?.stack || `${source}:${lineno}:${colno}`;
|
|
57
|
-
this.#renderError(errorMessage, errorStack);
|
|
58
|
-
} else {
|
|
59
|
-
trace.log("โ ๏ธ [nine-exception-hook] ์ด๋ฏธ ์๋ฌ ํ๋ฉด์ด ํ์ฑํ๋์ด ์์ด ์์ onerror ํจ์ค");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (this.#oldOnError) {
|
|
63
|
-
trace.log("๐ [nine-exception-hook] ๊ธฐ์กด์ ๋ฑ๋ก๋์ด ์๋ ๋ค๋ฅธ onerror ์์ง์ผ๋ก ์์");
|
|
64
|
-
return this.#oldOnError(message, source, lineno, colno, error);
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
};
|
|
68
|
-
trace.log("๐ [nine-exception-hook] ์์ window.onerror ๊ฐ๋ก์ฑ๊ธฐ(Chaining) ์๋ฃ");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
#renderer = () => {
|
|
72
|
-
const customImport = nine.cssPath ? `@import "${nine.cssPath}/nine-mu.css";` : "";
|
|
73
|
-
|
|
74
|
-
this.shadowRoot.innerHTML = `
|
|
75
|
-
<style>
|
|
76
|
-
@import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-mu@${__APP_VERSION__}/dist/css/nine-mu.css";
|
|
77
|
-
${customImport}
|
|
78
|
-
:host {
|
|
79
|
-
display: block;
|
|
80
|
-
width: 100%;
|
|
81
|
-
height: 100%;
|
|
82
|
-
}
|
|
83
|
-
</style>
|
|
84
|
-
<div class="nine-hook-core" style="width: 100%; height: 100%;">
|
|
85
|
-
<slot></slot>
|
|
86
|
-
</div>
|
|
87
|
-
<div class="nine-exception-board"></div>
|
|
88
|
-
`;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
#injectShadowStylesheet() {
|
|
92
|
-
if (this.shadowRoot.querySelector(`link[href="${this.#cssPath}"]`)) return;
|
|
93
|
-
|
|
94
|
-
const link = document.createElement('link');
|
|
95
|
-
link.rel = 'stylesheet';
|
|
96
|
-
link.href = this.#cssPath;
|
|
97
|
-
this.shadowRoot.appendChild(link);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
#handleRuntimeError = (event) => {
|
|
101
|
-
trace.log("๐จ [nine-exception-hook] window.addEventListener('error') ๋ฆฌ์ค๋ ํฌ์ฐฉ!!", event);
|
|
102
|
-
|
|
103
|
-
if (this.#hasError) return;
|
|
104
|
-
|
|
105
|
-
const errorMessage = event.error?.message || event.message || String(event);
|
|
106
|
-
const errorStack = event.error?.stack || "No stack trace available";
|
|
107
|
-
|
|
108
|
-
if (errorMessage && errorMessage !== "Script error.") {
|
|
109
|
-
this.#renderError(errorMessage, errorStack);
|
|
27
|
+
// 2. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฅ์ฑ: ์ปดํฌ๋ํธ ์์ฒด Props๋ก ์ฝ๋ฐฑ์ ๋๊ฒจ๋ฐ์๋ค๋ฉด ์คํ
|
|
28
|
+
if (this.props.onCatch) {
|
|
29
|
+
this.props.onCatch(error, errorInfo);
|
|
110
30
|
}
|
|
111
31
|
}
|
|
112
32
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const reason = event.reason;
|
|
119
|
-
const errorMessage = reason?.message || String(reason || "Unhandled Promise Rejection");
|
|
120
|
-
const errorStack = reason?.stack || "No stack trace available";
|
|
33
|
+
componentDidMount() {
|
|
34
|
+
window.addEventListener('popstate', this.handleLocationChange);
|
|
35
|
+
document.addEventListener('click', this.handleLocationChange, true);
|
|
36
|
+
}
|
|
121
37
|
|
|
122
|
-
|
|
38
|
+
componentWillUnmount() {
|
|
39
|
+
window.removeEventListener('popstate', this.handleLocationChange);
|
|
40
|
+
document.removeEventListener('click', this.handleLocationChange, true);
|
|
123
41
|
}
|
|
124
42
|
|
|
125
|
-
|
|
43
|
+
handleLocationChange() {
|
|
126
44
|
setTimeout(() => {
|
|
127
|
-
if (this
|
|
128
|
-
|
|
129
|
-
this
|
|
130
|
-
this
|
|
131
|
-
|
|
132
|
-
this.#removeExternalOverlay();
|
|
133
|
-
|
|
134
|
-
const coreContainer = this.shadowRoot.querySelector('.nine-hook-core');
|
|
135
|
-
if (coreContainer) coreContainer.style.display = '';
|
|
45
|
+
if (this.state.hasError && this.lastPath !== window.location.pathname) {
|
|
46
|
+
console.log("โจ [Nine-Library] ํ์ด์ง ์ฃผ์ ๋ณ๊ฒฝ ๊ฐ์ง -> ๋ฆฌ์กํธ ์๋ฌ ์ํ ์ด๊ธฐํ");
|
|
47
|
+
this.lastPath = window.location.pathname;
|
|
48
|
+
this.setState({ hasError: false, error: null });
|
|
136
49
|
}
|
|
137
|
-
},
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
#removeExternalOverlay() {
|
|
141
|
-
const target = document.getElementById('nine-global-exception-container');
|
|
142
|
-
if (target) target.remove();
|
|
50
|
+
}, 10);
|
|
143
51
|
}
|
|
144
52
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (!btn) return;
|
|
151
|
-
|
|
152
|
-
btn.disabled = true;
|
|
153
|
-
btn.innerText = "โก AI ๊ด์ ํ์ ์์ค ๋ถ์ ์์ฒญ ์ค...";
|
|
154
|
-
btn.classList.add('loading');
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
if (window.triggerAutoRecovery) {
|
|
158
|
-
await window.triggerAutoRecovery({
|
|
159
|
-
message: errorMessage,
|
|
160
|
-
stack: errorStack || "No stack trace available",
|
|
161
|
-
path: window.location.pathname
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
footer.innerHTML = `โ
<b>AI ๊ด์ ํ ์ ์ ์๋ฃ:</b> ๋ถ์์ ๋ฐํ์ผ๋ก ์์ค ์ฝ๋๋ฅผ ๊ต์ ํ๊ณ ์์ต๋๋ค. ์ ์๋ง ๊ธฐ๋ค๋ ค์ฃผ์ธ์.`;
|
|
165
|
-
btn.innerText = "๐ ์ ์ก ์๋ฃ";
|
|
166
|
-
} else {
|
|
167
|
-
throw new Error("window.triggerAutoRecovery ๊ด์ ํ ์์ง์ด ๋ก๋๋์ง ์์์ต๋๋ค.");
|
|
53
|
+
render() {
|
|
54
|
+
if (this.state.hasError) {
|
|
55
|
+
// ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ปค์คํ
UI ์ ๊ณต (์ธ๋ถ์์ ์ปค์คํ
fallback UI๋ฅผ ์ฃผ์
ํ์ง ์์๋ค๋ฉด ๊ธฐ๋ณธ ํ
ํ๋ฆฟ ์ฌ์ฉ)
|
|
56
|
+
if (this.props.fallback) {
|
|
57
|
+
return this.props.fallback(this.state.error);
|
|
168
58
|
}
|
|
169
|
-
} catch (err) {
|
|
170
|
-
trace.error("โ AI ์ ์ก ์คํจ:", err);
|
|
171
|
-
btn.disabled = false;
|
|
172
|
-
btn.innerText = "โ ์ฌ์ ์ก ์๋";
|
|
173
|
-
footer.innerHTML = `<span style="color: #E53E3E;">โ ๏ธ ์ ์ก ์คํจ: ${err.message}</span>`;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
59
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// ๐ฏ [ํต์ฌ ๋ณ๊ฒฝ] Shadow DOM ๋ด๋ถ๊ฐ ์๋๋ผ document.body์ ์ง์ fixed ์ปจํ
์ด๋๋ฅผ ๊ฝ์๋ฒ๋ ค
|
|
188
|
-
// global-loading-overlay๋ฅผ ์๋ฒฝํ ๋ฎ์ด๋ฒ๋ฆฝ๋๋ค.
|
|
189
|
-
this.#removeExternalOverlay();
|
|
190
|
-
|
|
191
|
-
const externalContainer = document.createElement('div');
|
|
192
|
-
externalContainer.id = 'nine-global-exception-container';
|
|
193
|
-
|
|
194
|
-
// ์ธ๋ผ์ธ ์คํ์ผ๋ก ์ธ๋ถ ์์๋ฅผ ์์ ํ ์ฐจ๋จํ๊ณ ๋งจ ์์ผ๋ก ๋ฐฐ์น
|
|
195
|
-
Object.assign(externalContainer.style, {
|
|
196
|
-
position: 'fixed',
|
|
197
|
-
top: '0',
|
|
198
|
-
left: '0',
|
|
199
|
-
width: '100vw',
|
|
200
|
-
height: '100vh',
|
|
201
|
-
backgroundColor: '#FFF5F5',
|
|
202
|
-
zIndex: '2147483647', // ๋ธ๋ผ์ฐ์ ํํ ์ต๋ z-index ๊ฐ ๋ถ์ฌ
|
|
203
|
-
overflow: 'auto',
|
|
204
|
-
boxSizing: 'border-box',
|
|
205
|
-
display: 'block'
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
const errorHTML = `
|
|
209
|
-
<div class="nine-error-container" style="padding: 40px; max-width: 1200px; margin: 40px auto; font-family: sans-serif; background: white; border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.08); text-align: left;">
|
|
210
|
-
<h3 class="nine-error-title" style="color: #C53030; margin-top: 0; font-size: 22px; font-weight: 700; border-bottom: 2px solid #FED2D2; padding-bottom: 12px; font-family: sans-serif;">โ ๏ธ ์์คํ
์์ธ ๊ฐ์ง (nine-exception-hook)</h3>
|
|
211
|
-
<p class="nine-error-label" style="font-weight: bold; margin: 20px 0 8px 0; color: #4A5568; font-size: 15px; font-family: sans-serif;">[์๋ฌ ์์ธ ๋ก๊ทธ]:</p>
|
|
212
|
-
<pre class="nine-error-log" style="background: #1A202C; color: #EDF2F7; padding: 20px; border-radius: 6px; overflow-x: auto; white-space: pre-wrap; font-family: monospace; font-size: 14px; line-height: 1.6; margin-bottom: 25px;">${errorMessage}\n\n[Stack Trace]\n${errorStack}</pre>
|
|
213
|
-
|
|
214
|
-
<div class="nine-action-area" style="display: flex; align-items: center; gap: 20px; border-top: 1px solid #E2E8F0; padding-top: 20px;">
|
|
215
|
-
<button class="nine-ai-btn" style="background: #3182CE; color: white; border: none; padding: 14px 28px; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 16px;">๐ค AI์๊ฒ ์์ค์ฝ๋ ์์ ์์ฒญ</button>
|
|
216
|
-
<div class="nine-error-footer" style="font-size: 14px; color: #718096; line-height: 1.4; font-family: sans-serif;">
|
|
217
|
-
๋ฒํผ์ ๋๋ฅด๋ฉด AI๊ฐ ๋ก๊ทธ ๋ฐ ์ปดํฌ๋ํธ ๋งต์ ์ญ์ถ์ ํ์ฌ ์์ ์ ์์ํฉ๋๋ค.
|
|
218
|
-
</div>
|
|
60
|
+
return (
|
|
61
|
+
<div style={{ padding: '30px', margin: '20px', background: '#FFF5F5', border: '1px solid #FEB2B2', borderRadius: '8px', fontFamily: 'sans-serif', textAlign: 'left', ...this.props.containerStyle }}>
|
|
62
|
+
<h3 style={{ color: '#C53030', marginTop: 0, fontSize: '18px' }}>โ ๏ธ ์ปดํฌ๋ํธ ๋น๋/๋ ๋๋ง ์๋ฌ ๊ฐ์ง</h3>
|
|
63
|
+
<p style={{ margin: '10px 0 5px 0', fontWeight: 'bold', color: '#4A5568' }}>[์๋ฌ ์์ธ ๋ก๊ทธ]:</p>
|
|
64
|
+
<pre style={{ background: '#1A202C', color: '#EDF2F7', padding: '15px', borderRadius: '6px', overflowX: 'auto', whiteSpace: 'pre-wrap', fontFamily: 'monospace' }}>
|
|
65
|
+
{this.state.error?.message || String(this.state.error)}
|
|
66
|
+
</pre>
|
|
67
|
+
<div style={{ marginTop: '15px', fontSize: '14px', color: '#718096' }}>
|
|
68
|
+
๐ ์๋ฌ ๋ก๊ทธ๊ฐ ๊ด์ ํ์ผ๋ก ์๋ ํผ๋๋ฐฑ๋์์ต๋๋ค. AI๊ฐ ์์ค ์ฝ๋๋ฅผ ์ฌ์์ ํ๋ ๋์ ์ ์๋ง ๊ธฐ๋ค๋ ค์ฃผ์ธ์...
|
|
219
69
|
</div>
|
|
220
70
|
</div>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
document.body.appendChild(externalContainer);
|
|
225
|
-
trace.log("๐จ [nine-exception-hook] ๋ธ๋ผ์ฐ์ Body ์ต์๋จ ๋ ์ด์ด ๋ฐฐ์ ์ฑ๊ณต");
|
|
226
|
-
|
|
227
|
-
const aiBtn = externalContainer.querySelector('.nine-ai-btn');
|
|
228
|
-
if (aiBtn) {
|
|
229
|
-
aiBtn.addEventListener('click', () => this.#sendToAiAction(errorMessage, errorStack));
|
|
230
|
-
trace.log("๐จ [nine-exception-hook] AI ์์ฒญ ๋ฒํผ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ต์ข
๋ฐ์ธ๋ฉ ์ฑ๊ณต");
|
|
231
|
-
}
|
|
232
|
-
}, 0);
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return this.props.children;
|
|
233
74
|
}
|
|
234
75
|
}
|
|
235
76
|
|
|
236
|
-
|
|
237
|
-
customElements.define('nine-exception-hook', ExceptionHook);
|
|
238
|
-
}
|
|
77
|
+
export default NineExceptionHook;
|
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
|
-
import './components/exception/ExceptionHook.js';
|
|
7
|
+
//import { NineExceptionHook } from './components/exception/ExceptionHook.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Nine-Mu ์์ง ๋ฉ์ธ ํด๋์ค
|