@nine-lab/nine-mu 0.1.334 → 0.1.335

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.334",
3
+ "version": "0.1.335",
4
4
  "description": "AI-Driven Full-Stack Code Fabrication Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-mu.umd.js",
@@ -946,6 +946,16 @@
946
946
  display: block;
947
947
  width: 100%;
948
948
  height: 100%;
949
+ color: inherit;
950
+ font-size: inherit;
951
+ line-height: inherit;
952
+
953
+ /* 내부 모든 엘리먼트의 여백 계산법을 어드민 기본형에 동기화 */
954
+ .nine-error-container *,
955
+ .nine-error-container *::before,
956
+ .nine-error-container *::after {
957
+ box-sizing: border-box;
958
+ }
949
959
 
950
960
  .nine-error-container {
951
961
  padding: 30px;
@@ -1012,10 +1022,10 @@
1012
1022
  font-size: 14px;
1013
1023
  color: #718096;
1014
1024
  }
1025
+ }
1015
1026
 
1016
- @keyframes pulse {
1017
- 0% { opacity: 0.6; }
1018
- 50% { opacity: 1; }
1019
- 100% { opacity: 0.6; }
1020
- }
1027
+ @keyframes pulse {
1028
+ 0% { opacity: 0.6; }
1029
+ 50% { opacity: 1; }
1030
+ 100% { opacity: 0.6; }
1021
1031
  }
@@ -1,34 +1,32 @@
1
1
  // src/components/exception/ExceptionHook.js
2
2
  export class ExceptionHook extends HTMLElement {
3
+ // 💡 [핵심] 비공개 인스턴스 필드는 클래스 최상단에 먼저 선언해야 합니다.
4
+ #lastPath = window.location.pathname;
5
+ #hasError = false;
6
+ #cssPath = "/css/nine-exception-hook.css";
7
+
3
8
  constructor() {
4
9
  super();
5
- this.lastPath = window.location.pathname;
6
- this.hasError = false;
7
- this.cssPath = "/css/nine-exception-hook.css";
8
-
9
- // 💡 1. Shadow DOM(open 모드) 활성화 및 슬롯 공간 준비
10
+ // Shadow DOM(open 모드) 활성화
10
11
  this.attachShadow({ mode: 'open' });
11
-
12
- // 기본 구조 선언: 자식 엘리먼트들이 위치할 <slot>을 배치합니다.
13
-
14
12
  }
15
13
 
16
14
  connectedCallback() {
17
-
15
+ // 기본 스켈레톤 마크업 렌더링
18
16
  this.#renderer();
19
17
 
20
- // Shadow DOM 내부에 캡슐화된 스타일시트 링크 주입
18
+ // 정적 외부 스타일시트 링크 안전하게 결합
21
19
  this.#injectShadowStylesheet();
22
20
 
23
- window.addEventListener('error', this.#handleRuntimeError.bind(this), true);
24
- window.addEventListener('unhandledrejection', this.#handlePromiseError.bind(this), true);
25
- window.addEventListener('popstate', this.#handleLocationChange.bind(this));
26
- document.addEventListener('click', this.#handleLocationChange.bind(this), true);
21
+ window.addEventListener('error', this.#handleRuntimeError, true);
22
+ window.addEventListener('unhandledrejection', this.#handlePromiseError, true);
23
+ window.addEventListener('popstate', this.#handleLocationChange);
24
+ document.addEventListener('click', this.#handleLocationChange, true);
27
25
  }
28
26
 
29
27
  disconnectedCallback() {
30
- window.removeEventListener('error', this.#handleRuntimeError);
31
- window.removeEventListener('unhandledrejection', this.#handlePromiseError);
28
+ window.removeEventListener('error', this.#handleRuntimeError, true);
29
+ window.removeEventListener('unhandledrejection', this.#handlePromiseError, true);
32
30
  window.removeEventListener('popstate', this.#handleLocationChange);
33
31
  document.removeEventListener('click', this.#handleLocationChange, true);
34
32
  }
@@ -45,52 +43,50 @@ export class ExceptionHook extends HTMLElement {
45
43
  <div class="nine-hook-core">
46
44
  <slot></slot>
47
45
  </div>
46
+ <div class="nine-exception-board"></div>
48
47
  `;
49
48
  }
50
49
 
51
- // 💡 2. Shadow Root 내부 전용 스타일 링크 주입 함수
52
50
  #injectShadowStylesheet() {
53
- if (this.shadowRoot.querySelector(`link[href="${this.cssPath}"]`)) return;
51
+ // 💡 내부 필드 호출 시에도 모두 this.#형식으로 매핑합니다.
52
+ if (this.shadowRoot.querySelector(`link[href="${this.#cssPath}"]`)) return;
54
53
 
55
54
  const link = document.createElement('link');
56
55
  link.rel = 'stylesheet';
57
- link.href = this.cssPath;
58
- // head가 아닌 shadowRoot에 집어넣어 글로벌 오염을 완벽히 격리합니다.
56
+ link.href = this.#cssPath;
59
57
  this.shadowRoot.appendChild(link);
60
58
  }
61
59
 
62
- #handleRuntimeError(event) {
63
- // Shadow DOM 외부의 자식 영역(Light DOM) 검증을 위해 여전히 this.contains 활용
60
+ #handleRuntimeError = (event) => {
61
+ if (this.#hasError) return;
62
+
64
63
  if (this.contains(event.target) || event.error) {
65
64
  this.#renderError(event.error?.message || event.message, event.error?.stack);
66
65
  }
67
66
  }
68
67
 
69
-
70
- #handlePromiseError(event) {
68
+ #handlePromiseError = (event) => {
69
+ if (this.#hasError) return;
71
70
  this.#renderError(event.reason?.message || String(event.reason), event.reason?.stack);
72
71
  }
73
72
 
74
- #handleLocationChange() {
73
+ #handleLocationChange = () => {
75
74
  setTimeout(() => {
76
- if (this.hasError && this.lastPath !== window.location.pathname) {
75
+ if (this.#hasError && this.#lastPath !== window.location.pathname) {
77
76
  console.log("✨ [nine-exception-hook] Shadow DOM 내부 예외 청소 및 정상 복구");
78
- this.lastPath = window.location.pathname;
79
- this.hasError = false;
77
+ this.#lastPath = window.location.pathname;
78
+ this.#hasError = false;
80
79
 
81
- // 💡 3. 복구 시 Shadow Root 내부의 에러 컨테이너만 타겟팅해서 제거
82
- const errorBox = this.shadowRoot.querySelector('.nine-error-container');
83
- if (errorBox) errorBox.remove();
80
+ const exceptionBoard = this.shadowRoot.querySelector('.nine-exception-board');
81
+ if (exceptionBoard) exceptionBoard.innerHTML = '';
84
82
 
85
- // 숨겨두었던 원래 본문 슬롯 구역을 다시 노출
86
83
  const coreContainer = this.shadowRoot.querySelector('.nine-hook-core');
87
84
  if (coreContainer) coreContainer.style.display = '';
88
85
  }
89
86
  }, 10);
90
87
  }
91
88
 
92
- async #sendToAiAction(errorMessage, errorStack) {
93
- // 💡 4. DOM 쿼리 탐색을 모두 this가 아닌 this.shadowRoot로 전환
89
+ #sendToAiAction = async (errorMessage, errorStack) => {
94
90
  const btn = this.shadowRoot.querySelector('.nine-ai-btn');
95
91
  const footer = this.shadowRoot.querySelector('.nine-error-footer');
96
92
  if (!btn) return;
@@ -121,14 +117,15 @@ export class ExceptionHook extends HTMLElement {
121
117
  }
122
118
 
123
119
  #renderError(errorMessage, errorStack) {
124
- if (this.hasError) return;
125
- this.hasError = true;
120
+ if (this.#hasError) return;
121
+ this.#hasError = true;
126
122
 
127
- // 💡 5. 리액트의 원본 마크업을 건드리지 않고, 슬롯이 감싸진 껍데기만 숨김 처리
128
123
  const coreContainer = this.shadowRoot.querySelector('.nine-hook-core');
129
124
  if (coreContainer) coreContainer.style.display = 'none';
130
125
 
131
- // Shadow DOM 내부에 렌더링할 마크업 구조 설계
126
+ const exceptionBoard = this.shadowRoot.querySelector('.nine-exception-board');
127
+ if (!exceptionBoard) return;
128
+
132
129
  const errorHTML = `
133
130
  <div class="nine-error-container">
134
131
  <h3 class="nine-error-title">⚠️ 시스템 예외 감지 (${this.tagName.toLowerCase()})</h3>
@@ -144,10 +141,8 @@ export class ExceptionHook extends HTMLElement {
144
141
  </div>
145
142
  `;
146
143
 
147
- // shadowRoot 최하단에 안전하게 안착시킵니다.
148
- this.shadowRoot.insertAdjacentHTML('beforeend', errorHTML);
144
+ exceptionBoard.innerHTML = errorHTML;
149
145
 
150
- // 버튼 이벤트 바인딩도 shadowRoot 기준 처리
151
146
  const aiBtn = this.shadowRoot.querySelector('.nine-ai-btn');
152
147
  if (aiBtn) {
153
148
  aiBtn.addEventListener('click', () => this.#sendToAiAction(errorMessage, errorStack));