@nine-lab/nine-mu 0.1.345 โ†’ 0.1.347

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.345",
3
+ "version": "0.1.347",
4
4
  "description": "AI-Driven Full-Stack Code Fabrication Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-mu.umd.js",
@@ -25,6 +25,7 @@
25
25
  "@nine-lab/nine-nomenu": "*",
26
26
  "@nine-lab/nine-util": "^0.9.126",
27
27
  "@nine-lab/nine-ux": "^0.1.244",
28
+ "@vitejs/plugin-react": "^6.0.2",
28
29
  "terser": "^5.31.0",
29
30
  "vite": "^6.0.0"
30
31
  },
@@ -1,211 +1,92 @@
1
- // src/components/exception/ExceptionHook.js
2
- import { nine } from '@nine-lab/nine-util';
3
- import { trace } from '@nopeer';
1
+ import React from 'react';
4
2
 
5
- export class ExceptionHook extends HTMLElement {
6
- #lastPath = window.location.pathname;
7
- #hasError = false;
8
- #cssPath = "/css/nine-exception-hook.css";
9
- #oldOnError = null;
3
+ export class NineExceptionHook extends React.Component {
10
4
 
11
- constructor() {
12
- super();
13
- this.attachShadow({ mode: 'open' });
5
+ constructor(props) {
6
+ super(props);
7
+ this.state = { hasError: false, error: null };
8
+ this.lastPath = window.location.pathname;
9
+ this.handleLocationChange = this.handleLocationChange.bind(this);
14
10
  }
15
11
 
16
- connectedCallback() {
17
- this.#renderer();
18
- this.#injectShadowStylesheet();
19
- this.#setupGlobalSniffer();
20
-
21
- window.addEventListener('unhandledrejection', this.#handlePromiseError, true);
22
- window.addEventListener('popstate', this.#handleLocationChange);
23
- document.addEventListener('click', this.#handleLocationChange, true);
12
+ static getDerivedStateFromError(error) {
13
+ return { hasError: true, error };
24
14
  }
25
15
 
26
- disconnectedCallback() {
27
- window.removeEventListener('error', this.#handleRuntimeError, true);
28
- window.removeEventListener('unhandledrejection', this.#handlePromiseError, true);
29
- window.removeEventListener('popstate', this.#handleLocationChange);
30
- document.removeEventListener('click', this.#handleLocationChange, true);
16
+ componentDidCatch(error, errorInfo) {
17
+ console.error("๐Ÿšจ [Nine-Library] ๋ณธ๋ฌธ ๋ Œ๋”๋ง ์—๋Ÿฌ ํฌ์ฐฉ:", error);
31
18
 
32
- if (window.onerror === this.#handleRuntimeError || this.#oldOnError) {
33
- window.onerror = this.#oldOnError;
19
+ if (window.triggerAutoRecovery) {
20
+ window.triggerAutoRecovery(error.message || String(error));
34
21
  }
35
- }
36
-
37
- #setupGlobalSniffer() {
38
- window.addEventListener('error', this.#handleRuntimeError, true);
39
-
40
- this.#oldOnError = window.onerror;
41
- window.onerror = (message, source, lineno, colno, error) => {
42
- if (!this.#hasError) {
43
- const errorMessage = error?.message || message || "์•Œ ์ˆ˜ ์—†๋Š” ๋Ÿฐํƒ€์ž„ ์˜ˆ์™ธ";
44
- const errorStack = error?.stack || `${source}:${lineno}:${colno}`;
45
- this.#renderError(errorMessage, errorStack);
46
- }
47
- if (this.#oldOnError) {
48
- return this.#oldOnError(message, source, lineno, colno, error);
49
- }
50
- return false;
51
- };
52
- }
53
-
54
- #renderer = () => {
55
- const customImport = nine.cssPath ? `@import "${nine.cssPath}/nine-mu.css";` : "";
56
-
57
- // ๐ŸŽฏ [ํ•ต์‹ฌ ๋ณ€๊ฒฝ 1] :host ์ž์ฒด๋ฅผ absolute์˜ ๊ธฐ์ค€์ ์ด ๋˜๋Š” block์œผ๋กœ ์žก๊ณ ,
58
- // ๋ฆฌ์•กํŠธ ์Šฌ๋กฏ ๋‚ด์šฉ๋ฌผ(๋ฉ”๋‰ด ๋“ฑ)์€ ์ ˆ๋Œ€ ์ˆจ๊ธฐ์ง€ ์•Š๊ณ  100% ํฌ๊ธฐ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
59
- this.shadowRoot.innerHTML = `
60
- <style>
61
- @import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-mu@${__APP_VERSION__}/dist/css/nine-mu.css";
62
- ${customImport}
63
-
64
- :host {
65
- display: block;
66
- width: 100%;
67
- height: 100%;
68
- position: relative !important; /* ๋‚ด๋ถ€ ์—๋Ÿฌ ๋ณด๋“œ์˜ ๊ธฐ์ค€์  ๊ธฐ๋‘ฅ ์ƒ์„ฑ */
69
- }
70
-
71
- .nine-hook-core {
72
- width: 100%;
73
- height: 100%;
74
- }
75
-
76
- /* ๐ŸŽฏ [ํ•ต์‹ฌ ๋ณ€๊ฒฝ 2] ๋ฆฌ์•กํŠธ ์Šฌ๋กฏ์„ ๊ฐ€๋ฆฌ์ง€ ์•Š๊ณ , ์˜ค์ง "์ด ์ปดํฌ๋„ŒํŠธ ๊ตฌ์—ญ"๋งŒ ๊ฐ€๋“ ์ฑ„์šฐ๋Š” ๋…๋ฆฝ ํŒ์—… ๋ ˆ์ด์–ด */
77
- .nine-hook-inner-cover {
78
- position: absolute !important;
79
- top: 0 !important;
80
- left: 0 !important;
81
- width: 100% !important;
82
- height: 100% !important;
83
- box-sizing: border-box !important;
84
- background-color: #FFF5F5 !important;
85
- z-index: 2147483647 !important; /* ๋ฆฌ์•กํŠธ ๋‚ด๋ถ€ ๊ทธ ์–ด๋–ค ์˜ค๋ฒ„๋ ˆ์ด๋ณด๋‹ค ๋ฌด์กฐ๊ฑด ์œ„ */
86
- overflow: auto !important;
87
- display: none; /* ํ‰์†Œ์—” ์ˆจ๊น€ */
88
- }
89
- </style>
90
-
91
- <div class="nine-hook-core">
92
- <slot></slot>
93
- </div>
94
- <div class="nine-exception-board class-target-board"></div>
95
- `;
96
- }
97
-
98
- #injectShadowStylesheet() {
99
- if (this.shadowRoot.querySelector(`link[href="${this.#cssPath}"]`)) return;
100
-
101
- const link = document.createElement('link');
102
- link.rel = 'stylesheet';
103
- link.href = this.#cssPath;
104
- this.shadowRoot.appendChild(link);
105
- }
106
-
107
- #handleRuntimeError = (event) => {
108
- if (this.#hasError) return;
109
-
110
- const errorMessage = event.error?.message || event.message || String(event);
111
- const errorStack = event.error?.stack || "No stack trace available";
112
22
 
113
- if (errorMessage && errorMessage !== "Script error.") {
114
- this.#renderError(errorMessage, errorStack);
23
+ if (this.props.onCatch) {
24
+ this.props.onCatch(error, errorInfo);
115
25
  }
116
26
  }
117
27
 
118
- #handlePromiseError = (event) => {
119
- if (this.#hasError) return;
120
-
121
- const reason = event.reason;
122
- const errorMessage = reason?.message || String(reason || "Unhandled Promise Rejection");
123
- const errorStack = reason?.stack || "No stack trace available";
28
+ componentDidMount() {
29
+ window.addEventListener('popstate', this.handleLocationChange);
30
+ document.addEventListener('click', this.handleLocationChange, true);
31
+ }
124
32
 
125
- this.#renderError(errorMessage, errorStack);
33
+ componentWillUnmount() {
34
+ window.removeEventListener('popstate', this.handleLocationChange);
35
+ document.removeEventListener('click', this.handleLocationChange, true);
126
36
  }
127
37
 
128
- #handleLocationChange = () => {
38
+ handleLocationChange() {
129
39
  setTimeout(() => {
130
- if (this.#hasError && this.#lastPath !== window.location.pathname) {
131
- this.#lastPath = window.location.pathname;
132
- this.#hasError = false;
133
-
134
- const exceptionBoard = this.shadowRoot.querySelector('.nine-exception-board');
135
- if (exceptionBoard) {
136
- exceptionBoard.innerHTML = '';
137
- exceptionBoard.className = 'nine-exception-board'; // ํด๋ž˜์Šค ๋ฆฌ์…‹
138
- }
40
+ if (this.state.hasError && this.lastPath !== window.location.pathname) {
41
+ console.log("โœจ [Nine-Library] ํŽ˜์ด์ง€ ์ฃผ์†Œ ๋ณ€๊ฒฝ ๊ฐ์ง€ -> ๋ฆฌ์•กํŠธ ์—๋Ÿฌ ์ƒํƒœ ์ดˆ๊ธฐํ™”");
42
+ this.lastPath = window.location.pathname;
43
+ this.setState({ hasError: false, error: null });
139
44
  }
140
- }, 50);
45
+ }, 10);
141
46
  }
142
47
 
143
- #sendToAiAction = async (errorMessage, errorStack) => {
144
- const btn = this.shadowRoot.querySelector('.nine-ai-btn');
145
- const footer = this.shadowRoot.querySelector('.nine-error-footer');
146
- if (!btn) return;
147
-
148
- btn.disabled = true;
149
- btn.innerText = "โšก AI ๊ด€์ œํƒ‘์— ์†Œ์Šค ๋ถ„์„ ์š”์ฒญ ์ค‘...";
150
- btn.classList.add('loading');
151
-
152
- try {
153
- if (window.triggerAutoRecovery) {
154
- await window.triggerAutoRecovery({
155
- message: errorMessage,
156
- stack: errorStack || "No stack trace available",
157
- path: window.location.pathname
158
- });
159
-
160
- footer.innerHTML = `โœ… <b>AI ๊ด€์ œํƒ‘ ์ ‘์ˆ˜ ์™„๋ฃŒ:</b> ๋ถ„์„์„ ๋ฐ”ํƒ•์œผ๋กœ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๊ต์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”.`;
161
- btn.innerText = "๐Ÿš€ ์ „์†ก ์™„๋ฃŒ";
162
- } else {
163
- throw new Error("window.triggerAutoRecovery ๊ด€์ œํƒ‘ ์—”์ง„์ด ๋กœ๋“œ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.");
48
+ render() {
49
+ if (this.state.hasError) {
50
+ if (this.props.fallback) {
51
+ return this.props.fallback(this.state.error);
164
52
  }
165
- } catch (err) {
166
- btn.disabled = false;
167
- btn.innerText = "โŒ ์žฌ์ „์†ก ์‹œ๋„";
168
- footer.innerHTML = `<span style="color: #E53E3E;">โš ๏ธ ์ „์†ก ์‹คํŒจ: ${err.message}</span>`;
169
- }
170
- }
171
53
 
172
- #renderError(errorMessage, errorStack) {
173
- if (this.#hasError) return;
174
- this.#hasError = true;
175
-
176
- setTimeout(() => {
177
- const exceptionBoard = this.shadowRoot.querySelector('.nine-exception-board');
178
- if (!exceptionBoard) return;
179
-
180
- // ๐ŸŽฏ [ํ•ต์‹ฌ ๋ณ€๊ฒฝ 3] ๊ธฐ์กด ์Šฌ๋กฏ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ˆจ๊ธฐ์ง€(display: none) ์•Š์Šต๋‹ˆ๋‹ค!
181
- // ๋Œ€์‹  ์—๋Ÿฌ ๋ณด๋“œ์— ์ปค๋ฒ„ ํด๋ž˜์Šค๋ฅผ ์ฃผ์ž…ํ•˜์—ฌ "์˜ค์ง ๋ณธ๋ฌธ ๊ณต๊ฐ„๋งŒ" ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์™„์ „ํžˆ ๋ฎ์–ด์”Œ์›๋‹ˆ๋‹ค.
182
- exceptionBoard.className = 'nine-hook-inner-cover';
183
-
184
- const errorHTML = `
185
- <div class="nine-error-container" style="padding: 30px; box-sizing: border-box; font-family: sans-serif; background: white; min-height: 100%; text-align: left;">
186
- <h3 class="nine-error-title" style="color: #C53030; margin-top: 0; font-size: 20px; font-weight: 700; border-bottom: 2px solid #FED2D2; padding-bottom: 12px; font-family: sans-serif;">โš ๏ธ ์‹œ์Šคํ…œ ์˜ˆ์™ธ ๊ฐ์ง€ (${this.tagName.toLowerCase()})</h3>
187
- <p class="nine-error-label" style="font-weight: bold; margin: 15px 0 6px 0; color: #4A5568; font-size: 14px; font-family: sans-serif;">[์—๋Ÿฌ ์›์ธ ๋กœ๊ทธ]:</p>
188
- <pre class="nine-error-log" style="background: #1A202C; color: #EDF2F7; padding: 15px; border-radius: 6px; overflow-x: auto; white-space: pre-wrap; font-family: monospace; font-size: 13px; line-height: 1.5; margin-bottom: 20px;">${errorMessage}\n\n[Stack Trace]\n${errorStack}</pre>
189
-
190
- <div class="nine-action-area" style="display: flex; align-items: center; gap: 15px; border-top: 1px solid #E2E8F0; padding-top: 15px;">
191
- <button class="nine-ai-btn" style="background: #3182CE; color: white; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 14px;">๐Ÿค– AI์—๊ฒŒ ์†Œ์Šค์ฝ”๋“œ ์ˆ˜์ • ์š”์ฒญ</button>
192
- <div class="nine-error-footer" style="font-size: 13px; color: #718096; line-height: 1.4; font-family: sans-serif;">
193
- ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด AI๊ฐ€ ๋กœ๊ทธ ๋ฐ ์ปดํฌ๋„ŒํŠธ ๋งต์„ ์—ญ์ถ”์ ํ•˜์—ฌ ์ˆ˜์ •์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
194
- </div>
195
- </div>
196
- </div>
197
- `;
198
-
199
- exceptionBoard.innerHTML = errorHTML;
54
+ const errorMessage = this.state.error?.message || String(this.state.error);
55
+
56
+ // โญ Vite ๋นŒ๋“œ ํ†ต๊ณผ๋ฅผ ์œ„ํ•ด ์ˆœ์ˆ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜(React.createElement)๋กœ ๋ณ€๊ฒฝ
57
+ return React.createElement(
58
+ 'div',
59
+ {
60
+ style: {
61
+ padding: '30px',
62
+ margin: '20px',
63
+ background: '#FFF5F5',
64
+ border: '1px solid #FEB2B2',
65
+ borderRadius: '8px',
66
+ fontFamily: 'sans-serif',
67
+ textAlign: 'left',
68
+ ...this.props.containerStyle
69
+ }
70
+ },
71
+ React.createElement('h3', { style: { color: '#C53030', marginTop: 0, fontSize: '18px' } }, 'โš ๏ธ ์ปดํฌ๋„ŒํŠธ ๋นŒ๋“œ/๋ Œ๋”๋ง ์—๋Ÿฌ ๊ฐ์ง€'),
72
+ React.createElement('p', { style: { margin: '10px 0 5px 0', fontWeight: 'bold', color: '#4A5568' } }, '[์—๋Ÿฌ ์›์ธ ๋กœ๊ทธ]:'),
73
+ React.createElement('pre', {
74
+ style: {
75
+ background: '#1A202C',
76
+ color: '#EDF2F7',
77
+ padding: '15px',
78
+ borderRadius: '6px',
79
+ overflowX: 'auto',
80
+ whiteSpace: 'pre-wrap',
81
+ fontFamily: 'monospace'
82
+ }
83
+ }, errorMessage),
84
+ React.createElement('div', { style: { marginTop: '15px', fontSize: '14px', color: '#718096' } }, '๐Ÿ”„ ์—๋Ÿฌ ๋กœ๊ทธ๊ฐ€ ๊ด€์ œํƒ‘์œผ๋กœ ์ž๋™ ํ”ผ๋“œ๋ฐฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. AI๊ฐ€ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์žฌ์ˆ˜์ •ํ•˜๋Š” ๋™์•ˆ ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”...')
85
+ );
86
+ }
200
87
 
201
- const aiBtn = exceptionBoard.querySelector('.nine-ai-btn');
202
- if (aiBtn) {
203
- aiBtn.addEventListener('click', () => this.#sendToAiAction(errorMessage, errorStack));
204
- }
205
- }, 0);
88
+ return this.props.children;
206
89
  }
207
90
  }
208
91
 
209
- if (!customElements.get('nine-exception-hook')) {
210
- customElements.define('nine-exception-hook', ExceptionHook);
211
- }
92
+ 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 ์—”์ง„ ๋ฉ”์ธ ํด๋ž˜์Šค
@@ -20,4 +20,4 @@ export const NineMu = {
20
20
 
21
21
  // ๊ธฐ๋ณธ export ๋ฐ ์ปดํฌ๋„ŒํŠธ export
22
22
  export default NineMu;
23
- export { NineChat, NineDiff, NineDiffPopup };
23
+ export { NineChat, NineDiff, NineDiffPopup, NineExceptionHook };
package/vite.config.js CHANGED
@@ -19,7 +19,7 @@ export default defineConfig({
19
19
  formats: ['es', 'umd']
20
20
  },
21
21
  rollupOptions: {
22
- external: ['@nine-lab/nine-ai', '@nine-lab/nine-util', '@nine-lab/nine-ux'],
22
+ external: ['@nine-lab/nine-ai', '@nine-lab/nine-util', '@nine-lab/nine-ux', 'react', 'react-dom'],
23
23
  output: {
24
24
  globals: {
25
25
  '@nine-lab/nine-ai': 'NineAi',
@@ -31,5 +31,9 @@ export default defineConfig({
31
31
  minify: 'terser',
32
32
  sourcemap: true,
33
33
  emptyOutDir: true
34
+ },
35
+ esbuild: {
36
+ loader: 'jsx',
37
+ include: /src\/.*\.js$/, // src ํด๋” ๋‚ด์˜ ๋ชจ๋“  .js ํŒŒ์ผ์„ ๋Œ€์ƒ์œผ๋กœ ์ง€์ •
34
38
  }
35
39
  });