@nine-lab/nine-mu 0.1.339 β 0.1.341
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 +69 -32
- package/dist/nine-mu.js.map +1 -1
- package/dist/nine-mu.umd.js +1 -1
- package/dist/nine-mu.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/exception/ExceptionHook.js +72 -36
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/components/exception/ExceptionHook.js
|
|
2
2
|
import { nine } from '@nine-lab/nine-util';
|
|
3
|
+
import { trace } from '@nopeer';
|
|
3
4
|
|
|
4
5
|
export class ExceptionHook extends HTMLElement {
|
|
5
|
-
// π‘ λΉκ³΅κ° μΈμ€ν΄μ€ νλ μ μ
|
|
6
6
|
#lastPath = window.location.pathname;
|
|
7
7
|
#hasError = false;
|
|
8
8
|
#cssPath = "/css/nine-exception-hook.css";
|
|
@@ -10,15 +10,15 @@ export class ExceptionHook extends HTMLElement {
|
|
|
10
10
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super();
|
|
13
|
-
// Shadow DOM(open λͺ¨λ) νμ±ν
|
|
14
13
|
this.attachShadow({ mode: 'open' });
|
|
14
|
+
trace.log("π [nine-exception-hook] μΈμ€ν΄μ€ μμ±λ¨");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
connectedCallback() {
|
|
18
|
+
trace.log("π [nine-exception-hook] DOMμ λ§μ΄νΈλ¨. μ΄λ²€νΈ 리μ€λ λ°μΈλ© μμ");
|
|
18
19
|
this.#renderer();
|
|
19
20
|
this.#injectShadowStylesheet();
|
|
20
21
|
|
|
21
|
-
// π― 리μ‘νΈ λ° κ°λ° μ€λ²λ μ΄μ stopPropagationμ μ°ννκΈ° μν μ΄μ€ μ€λνΌ κ°λ
|
|
22
22
|
this.#setupGlobalSniffer();
|
|
23
23
|
|
|
24
24
|
window.addEventListener('unhandledrejection', this.#handlePromiseError, true);
|
|
@@ -27,36 +27,42 @@ export class ExceptionHook extends HTMLElement {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
disconnectedCallback() {
|
|
30
|
+
trace.log("π [nine-exception-hook] DOMμμ μΈλ§μ΄νΈλ¨. 리μ€λ ν΄μ ");
|
|
30
31
|
window.removeEventListener('error', this.#handleRuntimeError, true);
|
|
31
32
|
window.removeEventListener('unhandledrejection', this.#handlePromiseError, true);
|
|
32
33
|
window.removeEventListener('popstate', this.#handleLocationChange);
|
|
33
34
|
document.removeEventListener('click', this.#handleLocationChange, true);
|
|
34
35
|
|
|
35
|
-
// π― μμ onerror νΈλ€λ¬ 볡ꡬ
|
|
36
36
|
if (window.onerror === this.#handleRuntimeError || this.#oldOnError) {
|
|
37
37
|
window.onerror = this.#oldOnError;
|
|
38
|
+
trace.log("π [nine-exception-hook] window.onerror 볡ꡬ μλ£");
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
#setupGlobalSniffer() {
|
|
42
|
-
// νμ€ μΊ‘μ²λ§ 리μ€λ λ±λ‘
|
|
43
43
|
window.addEventListener('error', this.#handleRuntimeError, true);
|
|
44
|
+
trace.log("π [nine-exception-hook] window.addEventListener('error') λ±λ‘ μλ£");
|
|
44
45
|
|
|
45
|
-
// π― [μΉνΈν€] ν νλ μμν¬κ° μ΄λ²€νΈλ₯Ό μΌμΌλ 무쑰건 μ€νλλ μμ hook κ°λ‘μ±κΈ°
|
|
46
46
|
this.#oldOnError = window.onerror;
|
|
47
47
|
window.onerror = (message, source, lineno, colno, error) => {
|
|
48
|
+
trace.log("π¨ [nine-exception-hook] μμ window.onerror ν¬μ°©!!", { message, source, lineno, error });
|
|
49
|
+
|
|
48
50
|
if (!this.#hasError) {
|
|
51
|
+
trace.log("π― [nine-exception-hook] νμ¬ μλ¬ μν μμ -> μλ¬ λ³΄λ μΆλ ₯ μλ");
|
|
49
52
|
const errorMessage = error?.message || message || "μ μ μλ λ°νμ μμΈ";
|
|
50
53
|
const errorStack = error?.stack || `${source}:${lineno}:${colno}`;
|
|
51
54
|
this.#renderError(errorMessage, errorStack);
|
|
55
|
+
} else {
|
|
56
|
+
trace.log("β οΈ [nine-exception-hook] μ΄λ―Έ μλ¬ νλ©΄μ΄ νμ±νλμ΄ μμ΄ μμ onerror ν¨μ€");
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
// κΈ°μ‘΄μ λ±λ‘λμ΄ μλ λ€λ₯Έ onerror μμ§(Vite, λΈλΌμ°μ λ±)μ΄ μμΌλ©΄ κ·Έλλ‘ μ€νλλλ‘ μμ
|
|
55
59
|
if (this.#oldOnError) {
|
|
60
|
+
trace.log("π [nine-exception-hook] κΈ°μ‘΄μ λ±λ‘λμ΄ μλ λ€λ₯Έ onerror μμ§μΌλ‘ μμ");
|
|
56
61
|
return this.#oldOnError(message, source, lineno, colno, error);
|
|
57
62
|
}
|
|
58
63
|
return false;
|
|
59
64
|
};
|
|
65
|
+
trace.log("π [nine-exception-hook] μμ window.onerror κ°λ‘μ±κΈ°(Chaining) μλ£");
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
#renderer = () => {
|
|
@@ -85,33 +91,47 @@ export class ExceptionHook extends HTMLElement {
|
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
#handleRuntimeError = (event) => {
|
|
88
|
-
|
|
94
|
+
trace.log("π¨ [nine-exception-hook] window.addEventListener('error') 리μ€λ ν¬μ°©!!", event);
|
|
95
|
+
|
|
96
|
+
if (this.#hasError) {
|
|
97
|
+
trace.log("β οΈ [nine-exception-hook] μ΄λ―Έ μλ¬ νλ©΄μ΄ νμ±νλμ΄ μμ΄ μ΄λ²€νΈ 리μ€λ ν¨μ€");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
89
100
|
|
|
90
|
-
// π― event.errorκ° nullμ΄κ±°λ μ μ€λλλΌλ messageλ₯Ό ν΅ν΄ μλ¬λ₯Ό 무쑰건 ν¬μ°©ν©λλ€.
|
|
91
101
|
const errorMessage = event.error?.message || event.message || String(event);
|
|
92
102
|
const errorStack = event.error?.stack || "No stack trace available";
|
|
93
103
|
|
|
94
|
-
// λΈλΌμ°μ λ΄λΆ μ€ν¬λ¦½νΈ λ‘λ© μλ¬ μμΈ μ²λ¦¬ ν κ°μ°¨μμ΄ λ°μΈλ©
|
|
95
104
|
if (errorMessage && errorMessage !== "Script error.") {
|
|
105
|
+
trace.log("π― [nine-exception-hook] μ μμ μΈ μλ¬ λ©μμ§ νμΈ -> μλ¬ λ³΄λ μΆλ ₯ μλ", { errorMessage });
|
|
96
106
|
this.#renderError(errorMessage, errorStack);
|
|
107
|
+
} else {
|
|
108
|
+
trace.log("β οΈ [nine-exception-hook] 'Script error.' μ΄κ±°λ λΉ λ©μμ§λΌ 무μλ¨");
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
#handlePromiseError = (event) => {
|
|
113
|
+
trace.log("π¨ [nine-exception-hook] unhandledrejection (Promise μλ¬) ν¬μ°©!!", event);
|
|
114
|
+
|
|
101
115
|
if (this.#hasError) return;
|
|
102
116
|
|
|
103
|
-
// λΉλκΈ° λΉμ μ λ°νμ κ±°λΆ(ex. null.data μ½κΈ° μλ¬) μΊμΉ
|
|
104
117
|
const reason = event.reason;
|
|
105
118
|
const errorMessage = reason?.message || String(reason || "Unhandled Promise Rejection");
|
|
106
119
|
const errorStack = reason?.stack || "No stack trace available";
|
|
107
120
|
|
|
121
|
+
trace.log("π― [nine-exception-hook] Promise κ±°λΆ νμΈ -> μλ¬ λ³΄λ μΆλ ₯ μλ");
|
|
108
122
|
this.#renderError(errorMessage, errorStack);
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
#handleLocationChange = () => {
|
|
112
126
|
setTimeout(() => {
|
|
127
|
+
trace.log("π [nine-exception-hook] μ£Όμ μ΄λ κ°μ§ 체ν¬", {
|
|
128
|
+
hasError: this.#hasError,
|
|
129
|
+
lastPath: this.#lastPath,
|
|
130
|
+
currentPath: window.location.pathname
|
|
131
|
+
});
|
|
132
|
+
|
|
113
133
|
if (this.#hasError && this.#lastPath !== window.location.pathname) {
|
|
114
|
-
|
|
134
|
+
trace.log("β¨ [nine-exception-hook] Shadow DOM λ΄λΆ μμΈ μ²μ λ° μ μ 볡ꡬ");
|
|
115
135
|
this.#lastPath = window.location.pathname;
|
|
116
136
|
this.#hasError = false;
|
|
117
137
|
|
|
@@ -125,6 +145,7 @@ export class ExceptionHook extends HTMLElement {
|
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
#sendToAiAction = async (errorMessage, errorStack) => {
|
|
148
|
+
trace.log("π [nine-exception-hook] AI μμ μμ² λ²νΌ ν΄λ¦λ¨");
|
|
128
149
|
const btn = this.shadowRoot.querySelector('.nine-ai-btn');
|
|
129
150
|
const footer = this.shadowRoot.querySelector('.nine-error-footer');
|
|
130
151
|
if (!btn) return;
|
|
@@ -135,6 +156,7 @@ export class ExceptionHook extends HTMLElement {
|
|
|
135
156
|
|
|
136
157
|
try {
|
|
137
158
|
if (window.triggerAutoRecovery) {
|
|
159
|
+
trace.log("π‘ [nine-exception-hook] window.triggerAutoRecovery νΈμΆ μ€ν");
|
|
138
160
|
await window.triggerAutoRecovery({
|
|
139
161
|
message: errorMessage,
|
|
140
162
|
stack: errorStack || "No stack trace available",
|
|
@@ -147,7 +169,7 @@ export class ExceptionHook extends HTMLElement {
|
|
|
147
169
|
throw new Error("window.triggerAutoRecovery κ΄μ ν μμ§μ΄ λ‘λλμ§ μμμ΅λλ€.");
|
|
148
170
|
}
|
|
149
171
|
} catch (err) {
|
|
150
|
-
|
|
172
|
+
trace.error("β AI μ μ‘ μ€ν¨:", err);
|
|
151
173
|
btn.disabled = false;
|
|
152
174
|
btn.innerText = "β μ¬μ μ‘ μλ";
|
|
153
175
|
footer.innerHTML = `<span style="color: #E53E3E;">β οΈ μ μ‘ μ€ν¨: ${err.message}</span>`;
|
|
@@ -158,33 +180,47 @@ export class ExceptionHook extends HTMLElement {
|
|
|
158
180
|
if (this.#hasError) return;
|
|
159
181
|
this.#hasError = true;
|
|
160
182
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
// π― [ν΅μ¬] 리μ‘νΈκ° μλ¬ λ°μ ν νμ DOMμ Unmount/μ‘°μνλ λκΈ°μ μΈ νμ΄λ°μ
|
|
184
|
+
// μμ ν νλ €λ³΄λΈ λ€(setTimeout 0)μ μμ νκ² Web Component UIλ₯Ό κ½μ λ£μ΅λλ€.
|
|
185
|
+
setTimeout(() => {
|
|
186
|
+
console.log("π¨ [nine-exception-hook] 리μ‘νΈ μ¬μ΄ν΄ μ’
λ£ ν μλ¬ UI μ΅μ’
λ λλ§");
|
|
187
|
+
|
|
188
|
+
const coreContainer = this.shadowRoot.querySelector('.nine-hook-core');
|
|
189
|
+
if (coreContainer) {
|
|
190
|
+
coreContainer.style.display = 'none';
|
|
191
|
+
console.log("π¨ [nine-exception-hook] <slot> λ³Έλ¬Έ μμ 컨ν
μ΄λ μ¨κΉ");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const exceptionBoard = this.shadowRoot.querySelector('.nine-exception-board');
|
|
195
|
+
if (!exceptionBoard) {
|
|
196
|
+
console.error("β [nine-exception-hook] .nine-exception-board μ리먼νΈλ₯Ό μ°Ύμ μ μμ΅λλ€.");
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const errorHTML = `
|
|
201
|
+
<div class="nine-error-container">
|
|
202
|
+
<h3 class="nine-error-title">β οΈ μμ€ν
μμΈ κ°μ§ (${this.tagName.toLowerCase()})</h3>
|
|
203
|
+
<p class="nine-error-label">[μλ¬ μμΈ λ‘κ·Έ]:</p>
|
|
204
|
+
<pre class="nine-error-log">${errorMessage}</pre>
|
|
205
|
+
|
|
206
|
+
<div class="nine-action-area" style="margin-top: 20px; display: flex; align-items: center; gap: 15px;">
|
|
207
|
+
<button class="nine-ai-btn">π€ AIμκ² μμ€μ½λ μμ μμ²</button>
|
|
208
|
+
<div class="nine-error-footer">
|
|
209
|
+
λ²νΌμ λλ₯΄λ©΄ AIκ° λ‘κ·Έ λ° μ»΄ν¬λνΈ λ§΅μ μμΆμ νμ¬ μμ μ μμν©λλ€.
|
|
210
|
+
</div>
|
|
177
211
|
</div>
|
|
178
212
|
</div>
|
|
179
|
-
|
|
180
|
-
`;
|
|
213
|
+
`;
|
|
181
214
|
|
|
182
|
-
|
|
215
|
+
exceptionBoard.innerHTML = errorHTML;
|
|
216
|
+
console.log("π¨ [nine-exception-hook] Shadow DOMμ μλ¬ UI μ΅μ’
μ½μ
μ±κ³΅");
|
|
183
217
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
218
|
+
const aiBtn = this.shadowRoot.querySelector('.nine-ai-btn');
|
|
219
|
+
if (aiBtn) {
|
|
220
|
+
aiBtn.addEventListener('click', () => this.#sendToAiAction(errorMessage, errorStack));
|
|
221
|
+
console.log("π¨ [nine-exception-hook] AI μμ² λ²νΌ μ΄λ²€νΈ 리μ€λ μ΅μ’
λ°μΈλ© μ±κ³΅");
|
|
222
|
+
}
|
|
223
|
+
}, 0);
|
|
188
224
|
}
|
|
189
225
|
}
|
|
190
226
|
|