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