@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nine-lab/nine-mu",
3
- "version": "0.1.338",
3
+ "version": "0.1.340",
4
4
  "description": "AI-Driven Full-Stack Code Fabrication Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-mu.umd.js",
@@ -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
- window.addEventListener('error', this.#handleRuntimeError, true);
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
- <style>
39
- @import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-mu@${__APP_VERSION__}/dist/css/nine-mu.css";
40
- ${customImport}
41
- </style>
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
- if (this.#hasError) return;
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
- // 2. 개발 ν™˜κ²½(Vite, Webpack) 및 λ¦¬μ•‘νŠΈ 특유의 무쑰건적인 μ „μ—­ μ—λŸ¬ μ „νŒŒ 캐치
68
- // λ¦¬μ•‘νŠΈ μ—λŸ¬λŠ” 보톡 μ „μ—­ window둜 λ˜μ Έμ§€λ―€λ‘œ, 이 훅이 λ–  μžˆλŠ” μƒνƒœλΌλ©΄ κ·Έλƒ₯ 가차없이 μž‘μ•„μ•Ό ν•©λ‹ˆλ‹€.
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
- // ν•„μš”μ‹œ λΈŒλΌμš°μ € κΈ°λ³Έ λΉ¨κ°„ μ—λŸ¬μ°½(Vite Overlay λ“±) μ–΅μ œ 원할 λ•Œ ν™œμ„±ν™”
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
- console.log("✨ [nine-exception-hook] Shadow DOM λ‚΄λΆ€ μ˜ˆμ™Έ μ²­μ†Œ 및 정상 볡ꡬ");
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
- console.error("❌ AI 전솑 μ‹€νŒ¨:", err);
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
- if (this.#hasError) return;
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) coreContainer.style.display = 'none';
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) return;
191
+ if (!exceptionBoard) {
192
+ trace.error("❌ [nine-exception-hook] .nine-exception-board μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.");
193
+ return;
194
+ }
146
195
 
147
196
  const errorHTML = `
148
- <div class="nine-error-container">
149
- <h3 class="nine-error-title">⚠️ μ‹œμŠ€ν…œ μ˜ˆμ™Έ 감지 (${this.tagName.toLowerCase()})</h3>
150
- <p class="nine-error-label">[μ—λŸ¬ 원인 둜그]:</p>
151
- <pre class="nine-error-log">${errorMessage}</pre>
152
-
153
- <div class="nine-action-area" style="margin-top: 20px; display: flex; align-items: center; gap: 15px;">
154
- <button class="nine-ai-btn">πŸ€– AIμ—κ²Œ μ†ŒμŠ€μ½”λ“œ μˆ˜μ • μš”μ²­</button>
155
- <div class="nine-error-footer">
156
- λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ AIκ°€ 둜그 및 μ»΄ν¬λ„ŒνŠΈ 맡을 μ—­μΆ”μ ν•˜μ—¬ μˆ˜μ •μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.
157
- </div>
158
- </div>
159
- </div>
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
  }