@mandujs/core 0.9.41 → 0.9.43
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/README.ko.md +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/bundler/build.ts +91 -73
- package/src/bundler/css.ts +283 -0
- package/src/bundler/dev.ts +31 -6
- package/src/bundler/index.ts +1 -0
- package/src/client/globals.ts +44 -0
- package/src/client/index.ts +5 -4
- package/src/client/island.ts +8 -13
- package/src/client/router.ts +33 -41
- package/src/client/runtime.ts +23 -51
- package/src/client/window-state.ts +101 -0
- package/src/config/index.ts +1 -0
- package/src/config/mandu.ts +45 -9
- package/src/config/validate.ts +158 -0
- package/src/constants.ts +25 -0
- package/src/contract/client.ts +4 -3
- package/src/contract/define.ts +459 -0
- package/src/devtools/ai/context-builder.ts +375 -0
- package/src/devtools/ai/index.ts +25 -0
- package/src/devtools/ai/mcp-connector.ts +465 -0
- package/src/devtools/client/catchers/error-catcher.ts +327 -0
- package/src/devtools/client/catchers/index.ts +18 -0
- package/src/devtools/client/catchers/network-proxy.ts +363 -0
- package/src/devtools/client/components/index.ts +39 -0
- package/src/devtools/client/components/kitchen-root.tsx +362 -0
- package/src/devtools/client/components/mandu-character.tsx +241 -0
- package/src/devtools/client/components/overlay.tsx +368 -0
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -0
- package/src/devtools/client/components/panel/guard-panel.tsx +244 -0
- package/src/devtools/client/components/panel/index.ts +32 -0
- package/src/devtools/client/components/panel/islands-panel.tsx +304 -0
- package/src/devtools/client/components/panel/network-panel.tsx +292 -0
- package/src/devtools/client/components/panel/panel-container.tsx +259 -0
- package/src/devtools/client/filters/context-filters.ts +282 -0
- package/src/devtools/client/filters/index.ts +16 -0
- package/src/devtools/client/index.ts +63 -0
- package/src/devtools/client/persistence.ts +335 -0
- package/src/devtools/client/state-manager.ts +478 -0
- package/src/devtools/design-tokens.ts +263 -0
- package/src/devtools/hook/create-hook.ts +207 -0
- package/src/devtools/hook/index.ts +13 -0
- package/src/devtools/index.ts +439 -0
- package/src/devtools/init.ts +266 -0
- package/src/devtools/protocol.ts +237 -0
- package/src/devtools/server/index.ts +17 -0
- package/src/devtools/server/source-context.ts +444 -0
- package/src/devtools/types.ts +319 -0
- package/src/devtools/worker/index.ts +25 -0
- package/src/devtools/worker/redaction-worker.ts +222 -0
- package/src/devtools/worker/worker-manager.ts +409 -0
- package/src/error/formatter.ts +28 -24
- package/src/error/index.ts +13 -9
- package/src/error/result.ts +46 -0
- package/src/error/types.ts +6 -4
- package/src/filling/filling.ts +6 -5
- package/src/guard/check.ts +60 -56
- package/src/guard/types.ts +3 -1
- package/src/guard/watcher.ts +10 -1
- package/src/index.ts +81 -0
- package/src/intent/index.ts +310 -0
- package/src/island/index.ts +304 -0
- package/src/router/fs-patterns.ts +7 -0
- package/src/router/fs-routes.ts +20 -8
- package/src/router/fs-scanner.ts +117 -133
- package/src/runtime/server.ts +189 -61
- package/src/runtime/ssr.ts +14 -4
- package/src/runtime/streaming-ssr.ts +15 -4
- package/src/utils/bun.ts +8 -0
- package/src/utils/lru-cache.ts +75 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mandu Kitchen DevTools
|
|
3
|
+
* AI-Native Developer Tools for Mandu Framework
|
|
4
|
+
*
|
|
5
|
+
* @version 1.1.0
|
|
6
|
+
* @description "만두를 찌듯 편안하게 디버깅한다"
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Types
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
// Core
|
|
15
|
+
KitchenEvent,
|
|
16
|
+
|
|
17
|
+
// Error
|
|
18
|
+
ErrorType,
|
|
19
|
+
Severity,
|
|
20
|
+
NormalizedError,
|
|
21
|
+
|
|
22
|
+
// Island
|
|
23
|
+
HydrationStrategy,
|
|
24
|
+
IslandStatus,
|
|
25
|
+
IslandSnapshot,
|
|
26
|
+
|
|
27
|
+
// Network
|
|
28
|
+
NetworkRequest,
|
|
29
|
+
NetworkBodyPolicy,
|
|
30
|
+
|
|
31
|
+
// Guard
|
|
32
|
+
GuardViolation,
|
|
33
|
+
|
|
34
|
+
// AI Context
|
|
35
|
+
CodeContextInfo,
|
|
36
|
+
AIContextPayload,
|
|
37
|
+
|
|
38
|
+
// Redaction
|
|
39
|
+
RedactPattern,
|
|
40
|
+
|
|
41
|
+
// Persistence
|
|
42
|
+
PreserveLogConfig,
|
|
43
|
+
|
|
44
|
+
// Worker
|
|
45
|
+
WorkerPolicy,
|
|
46
|
+
WorkerTask,
|
|
47
|
+
|
|
48
|
+
// Config
|
|
49
|
+
Position,
|
|
50
|
+
Theme,
|
|
51
|
+
DevToolsConfig,
|
|
52
|
+
|
|
53
|
+
// Plugin
|
|
54
|
+
KitchenAPI,
|
|
55
|
+
KitchenPanelPlugin,
|
|
56
|
+
|
|
57
|
+
// Meta
|
|
58
|
+
MetaLogType,
|
|
59
|
+
KitchenMetaLog,
|
|
60
|
+
|
|
61
|
+
// Character
|
|
62
|
+
ManduState,
|
|
63
|
+
ManduCharacterData,
|
|
64
|
+
} from './types';
|
|
65
|
+
|
|
66
|
+
export { MANDU_CHARACTERS } from './types';
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Design Tokens
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
colors,
|
|
74
|
+
typography,
|
|
75
|
+
spacing,
|
|
76
|
+
borderRadius,
|
|
77
|
+
borderWidth,
|
|
78
|
+
shadows,
|
|
79
|
+
animation,
|
|
80
|
+
zIndex,
|
|
81
|
+
breakpoints,
|
|
82
|
+
ManduDesignTokens,
|
|
83
|
+
generateCSSVariables,
|
|
84
|
+
testIds,
|
|
85
|
+
type TestId,
|
|
86
|
+
} from './design-tokens';
|
|
87
|
+
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// Client
|
|
90
|
+
// ============================================================================
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
// State
|
|
94
|
+
KitchenStateManager,
|
|
95
|
+
getStateManager,
|
|
96
|
+
resetStateManager,
|
|
97
|
+
type KitchenState,
|
|
98
|
+
type StateListener,
|
|
99
|
+
|
|
100
|
+
// Error Catching
|
|
101
|
+
ErrorCatcher,
|
|
102
|
+
getErrorCatcher,
|
|
103
|
+
initializeErrorCatcher,
|
|
104
|
+
destroyErrorCatcher,
|
|
105
|
+
|
|
106
|
+
// Network Proxy
|
|
107
|
+
NetworkProxy,
|
|
108
|
+
getNetworkProxy,
|
|
109
|
+
initializeNetworkProxy,
|
|
110
|
+
destroyNetworkProxy,
|
|
111
|
+
|
|
112
|
+
// Filters
|
|
113
|
+
removeComments,
|
|
114
|
+
handleStrings,
|
|
115
|
+
redactBuiltInSecrets,
|
|
116
|
+
redactCustomPatterns,
|
|
117
|
+
truncate,
|
|
118
|
+
applyContextFilters,
|
|
119
|
+
sanitizeStackTrace,
|
|
120
|
+
sanitizeErrorMessage,
|
|
121
|
+
type FilterOptions,
|
|
122
|
+
|
|
123
|
+
// Persistence
|
|
124
|
+
PersistenceManager,
|
|
125
|
+
getPersistenceManager,
|
|
126
|
+
initializePersistence,
|
|
127
|
+
destroyPersistence,
|
|
128
|
+
|
|
129
|
+
// Components
|
|
130
|
+
ManduCharacter,
|
|
131
|
+
ManduBadge,
|
|
132
|
+
ErrorOverlay,
|
|
133
|
+
mountKitchen,
|
|
134
|
+
unmountKitchen,
|
|
135
|
+
isKitchenMounted,
|
|
136
|
+
type ManduCharacterProps,
|
|
137
|
+
type ManduBadgeProps,
|
|
138
|
+
type ErrorOverlayProps,
|
|
139
|
+
} from './client';
|
|
140
|
+
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Initialization
|
|
143
|
+
// ============================================================================
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
initManduKitchen,
|
|
147
|
+
destroyManduKitchen,
|
|
148
|
+
autoInit,
|
|
149
|
+
type KitchenInstance,
|
|
150
|
+
} from './init';
|
|
151
|
+
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// Protocol
|
|
154
|
+
// ============================================================================
|
|
155
|
+
|
|
156
|
+
export type { KitchenEvents } from './protocol';
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
// Type guards
|
|
160
|
+
isErrorEvent,
|
|
161
|
+
isIslandEvent,
|
|
162
|
+
isNetworkEvent,
|
|
163
|
+
isGuardEvent,
|
|
164
|
+
isHmrEvent,
|
|
165
|
+
|
|
166
|
+
// Event factories
|
|
167
|
+
createErrorEvent,
|
|
168
|
+
createIslandRegisterEvent,
|
|
169
|
+
createIslandHydrateStartEvent,
|
|
170
|
+
createIslandHydrateEndEvent,
|
|
171
|
+
createNetworkRequestEvent,
|
|
172
|
+
createNetworkResponseEvent,
|
|
173
|
+
createGuardViolationEvent,
|
|
174
|
+
createHmrUpdateEvent,
|
|
175
|
+
createHmrErrorEvent,
|
|
176
|
+
|
|
177
|
+
// Constants
|
|
178
|
+
DEVTOOLS_VERSION,
|
|
179
|
+
DEFAULT_CONFIG,
|
|
180
|
+
ALLOWED_HEADERS,
|
|
181
|
+
BLOCKED_HEADERS,
|
|
182
|
+
} from './protocol';
|
|
183
|
+
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Hook
|
|
186
|
+
// ============================================================================
|
|
187
|
+
|
|
188
|
+
export {
|
|
189
|
+
createDevtoolsHook,
|
|
190
|
+
getOrCreateHook,
|
|
191
|
+
getHook,
|
|
192
|
+
initializeHook,
|
|
193
|
+
type ManduDevtoolsHook,
|
|
194
|
+
type EventSink,
|
|
195
|
+
} from './hook';
|
|
196
|
+
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// Convenience Functions
|
|
199
|
+
// ============================================================================
|
|
200
|
+
|
|
201
|
+
import { getOrCreateHook } from './hook';
|
|
202
|
+
import type { NormalizedError, GuardViolation } from './types';
|
|
203
|
+
import {
|
|
204
|
+
createErrorEvent,
|
|
205
|
+
createHmrUpdateEvent,
|
|
206
|
+
createHmrErrorEvent,
|
|
207
|
+
createGuardViolationEvent,
|
|
208
|
+
} from './protocol';
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* 에러 리포트 (간편 API)
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* import { reportError } from '@mandu/core/devtools';
|
|
216
|
+
*
|
|
217
|
+
* try {
|
|
218
|
+
* // ...
|
|
219
|
+
* } catch (e) {
|
|
220
|
+
* reportError(e);
|
|
221
|
+
* }
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
export function reportError(
|
|
225
|
+
error: Error | string,
|
|
226
|
+
options?: Partial<Omit<NormalizedError, 'id' | 'timestamp' | 'message'>>
|
|
227
|
+
): void {
|
|
228
|
+
const hook = getOrCreateHook();
|
|
229
|
+
const message = typeof error === 'string' ? error : error.message;
|
|
230
|
+
const stack = typeof error === 'string' ? undefined : error.stack;
|
|
231
|
+
|
|
232
|
+
hook.emit(
|
|
233
|
+
createErrorEvent({
|
|
234
|
+
type: options?.type ?? 'runtime',
|
|
235
|
+
severity: options?.severity ?? 'error',
|
|
236
|
+
message,
|
|
237
|
+
stack,
|
|
238
|
+
url: typeof window !== 'undefined' ? window.location.href : '',
|
|
239
|
+
...options,
|
|
240
|
+
})
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* HMR 업데이트 알림 (간편 API)
|
|
246
|
+
*/
|
|
247
|
+
export function notifyHmrUpdate(routeId: string): void {
|
|
248
|
+
const hook = getOrCreateHook();
|
|
249
|
+
hook.emit(createHmrUpdateEvent(routeId));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* HMR 에러 알림 (간편 API)
|
|
254
|
+
*/
|
|
255
|
+
export function notifyHmrError(message: string, stack?: string): void {
|
|
256
|
+
const hook = getOrCreateHook();
|
|
257
|
+
hook.emit(createHmrErrorEvent(message, stack));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Guard 위반 리포트 (간편 API)
|
|
262
|
+
*/
|
|
263
|
+
export function reportGuardViolation(
|
|
264
|
+
violation: Omit<GuardViolation, 'id' | 'timestamp'>
|
|
265
|
+
): void {
|
|
266
|
+
const hook = getOrCreateHook();
|
|
267
|
+
hook.emit(createGuardViolationEvent(violation));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ============================================================================
|
|
271
|
+
// DevTools API (for external use)
|
|
272
|
+
// ============================================================================
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* DevTools 공개 API
|
|
276
|
+
* window.ManduDevTools로 접근 가능
|
|
277
|
+
*/
|
|
278
|
+
export const ManduDevTools = {
|
|
279
|
+
/**
|
|
280
|
+
* 로그 출력
|
|
281
|
+
*/
|
|
282
|
+
log(level: 'info' | 'warn' | 'error', message: string, data?: unknown): void {
|
|
283
|
+
const hook = getOrCreateHook();
|
|
284
|
+
hook.emit({
|
|
285
|
+
type: 'log',
|
|
286
|
+
timestamp: Date.now(),
|
|
287
|
+
data: { level, message, data },
|
|
288
|
+
});
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 에러 리포트
|
|
293
|
+
*/
|
|
294
|
+
reportError,
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* 타이머 시작
|
|
298
|
+
*/
|
|
299
|
+
time(label: string): void {
|
|
300
|
+
if (typeof performance !== 'undefined') {
|
|
301
|
+
performance.mark(`mandu-time-${label}`);
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 타이머 종료 및 시간 반환
|
|
307
|
+
*/
|
|
308
|
+
timeEnd(label: string): number {
|
|
309
|
+
if (typeof performance !== 'undefined') {
|
|
310
|
+
const markName = `mandu-time-${label}`;
|
|
311
|
+
try {
|
|
312
|
+
performance.measure(`mandu-measure-${label}`, markName);
|
|
313
|
+
const entries = performance.getEntriesByName(`mandu-measure-${label}`);
|
|
314
|
+
const duration = entries[entries.length - 1]?.duration ?? 0;
|
|
315
|
+
performance.clearMarks(markName);
|
|
316
|
+
performance.clearMeasures(`mandu-measure-${label}`);
|
|
317
|
+
return duration;
|
|
318
|
+
} catch {
|
|
319
|
+
return 0;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return 0;
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* DevTools 토글
|
|
327
|
+
*/
|
|
328
|
+
toggle(): void {
|
|
329
|
+
const hook = getOrCreateHook();
|
|
330
|
+
hook.emit({
|
|
331
|
+
type: 'devtools:toggle',
|
|
332
|
+
timestamp: Date.now(),
|
|
333
|
+
data: {},
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* DevTools 열기
|
|
339
|
+
*/
|
|
340
|
+
open(): void {
|
|
341
|
+
const hook = getOrCreateHook();
|
|
342
|
+
hook.emit({
|
|
343
|
+
type: 'devtools:open',
|
|
344
|
+
timestamp: Date.now(),
|
|
345
|
+
data: {},
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* DevTools 닫기
|
|
351
|
+
*/
|
|
352
|
+
close(): void {
|
|
353
|
+
const hook = getOrCreateHook();
|
|
354
|
+
hook.emit({
|
|
355
|
+
type: 'devtools:close',
|
|
356
|
+
timestamp: Date.now(),
|
|
357
|
+
data: {},
|
|
358
|
+
});
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* 에러 목록 클리어
|
|
363
|
+
*/
|
|
364
|
+
clearErrors(): void {
|
|
365
|
+
const hook = getOrCreateHook();
|
|
366
|
+
hook.emit({
|
|
367
|
+
type: 'error:clear',
|
|
368
|
+
timestamp: Date.now(),
|
|
369
|
+
data: {},
|
|
370
|
+
});
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// 브라우저 환경에서 전역 객체에 등록
|
|
375
|
+
if (typeof window !== 'undefined') {
|
|
376
|
+
(window as Window & { ManduDevTools?: typeof ManduDevTools }).ManduDevTools =
|
|
377
|
+
ManduDevTools;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// ============================================================================
|
|
381
|
+
// v1.1: Server Module (Source Context Provider)
|
|
382
|
+
// ============================================================================
|
|
383
|
+
|
|
384
|
+
export {
|
|
385
|
+
SourceContextProvider,
|
|
386
|
+
SourcemapParser,
|
|
387
|
+
createViteMiddleware,
|
|
388
|
+
manduSourceContextPlugin,
|
|
389
|
+
type SourceContextRequest,
|
|
390
|
+
type SourceContextResponse,
|
|
391
|
+
type SourceContextProviderOptions,
|
|
392
|
+
type SourcemapPosition,
|
|
393
|
+
type SourcemapParseResult,
|
|
394
|
+
} from './server';
|
|
395
|
+
|
|
396
|
+
// ============================================================================
|
|
397
|
+
// v1.1: Worker Module (Redaction Worker)
|
|
398
|
+
// ============================================================================
|
|
399
|
+
|
|
400
|
+
export {
|
|
401
|
+
// Redaction Worker
|
|
402
|
+
redactText,
|
|
403
|
+
truncateText,
|
|
404
|
+
BUILT_IN_SECRET_PATTERNS,
|
|
405
|
+
PII_PATTERNS,
|
|
406
|
+
type WorkerRequest,
|
|
407
|
+
type WorkerResponse,
|
|
408
|
+
|
|
409
|
+
// Worker Manager
|
|
410
|
+
WorkerManager,
|
|
411
|
+
getWorkerManager,
|
|
412
|
+
initializeWorkerManager,
|
|
413
|
+
destroyWorkerManager,
|
|
414
|
+
type WorkerStatus,
|
|
415
|
+
type WorkerManagerOptions,
|
|
416
|
+
} from './worker';
|
|
417
|
+
|
|
418
|
+
// ============================================================================
|
|
419
|
+
// v1.1: AI Module (Context Builder, MCP Connector)
|
|
420
|
+
// ============================================================================
|
|
421
|
+
|
|
422
|
+
export {
|
|
423
|
+
// Context Builder
|
|
424
|
+
AIContextBuilder,
|
|
425
|
+
getContextBuilder,
|
|
426
|
+
resetContextBuilder,
|
|
427
|
+
type ContextBuilderOptions,
|
|
428
|
+
type UserAction,
|
|
429
|
+
|
|
430
|
+
// MCP Connector
|
|
431
|
+
MCPConnector,
|
|
432
|
+
getMCPConnector,
|
|
433
|
+
destroyMCPConnector,
|
|
434
|
+
type MCPConnectorOptions,
|
|
435
|
+
type MCPMessage,
|
|
436
|
+
type AnalysisRequest,
|
|
437
|
+
type AnalysisResponse,
|
|
438
|
+
type MCPConnectionStatus,
|
|
439
|
+
} from './ai';
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mandu Kitchen DevTools - Initialization
|
|
3
|
+
* @version 1.1.0
|
|
4
|
+
*
|
|
5
|
+
* 통합 초기화 함수
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DevToolsConfig } from './types';
|
|
9
|
+
import { initializeHook } from './hook';
|
|
10
|
+
import {
|
|
11
|
+
mountKitchen,
|
|
12
|
+
unmountKitchen,
|
|
13
|
+
initializeErrorCatcher,
|
|
14
|
+
destroyErrorCatcher,
|
|
15
|
+
initializeNetworkProxy,
|
|
16
|
+
destroyNetworkProxy,
|
|
17
|
+
initializePersistence,
|
|
18
|
+
destroyPersistence,
|
|
19
|
+
getStateManager,
|
|
20
|
+
getPersistenceManager,
|
|
21
|
+
} from './client';
|
|
22
|
+
import { initializeWorkerManager, destroyWorkerManager } from './worker';
|
|
23
|
+
import { getContextBuilder, resetContextBuilder, getMCPConnector, destroyMCPConnector } from './ai';
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Types
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
export interface KitchenInstance {
|
|
30
|
+
/** DevTools 언마운트 및 정리 */
|
|
31
|
+
destroy: () => void;
|
|
32
|
+
/** 상태 관리자 접근 */
|
|
33
|
+
getState: () => any;
|
|
34
|
+
/** 에러 리포트 */
|
|
35
|
+
reportError: (error: Error | string) => void;
|
|
36
|
+
/** DevTools 열기 */
|
|
37
|
+
open: () => void;
|
|
38
|
+
/** DevTools 닫기 */
|
|
39
|
+
close: () => void;
|
|
40
|
+
/** DevTools 토글 */
|
|
41
|
+
toggle: () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Initialization
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
let isInitialized = false;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Mandu Kitchen DevTools 초기화
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { initManduKitchen } from '@mandu/core/devtools';
|
|
56
|
+
*
|
|
57
|
+
* // 앱 시작 시 초기화
|
|
58
|
+
* const kitchen = initManduKitchen({
|
|
59
|
+
* position: 'bottom-right',
|
|
60
|
+
* features: {
|
|
61
|
+
* errorOverlay: true,
|
|
62
|
+
* networkMonitor: true,
|
|
63
|
+
* },
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // 나중에 정리
|
|
67
|
+
* kitchen.destroy();
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function initManduKitchen(config: DevToolsConfig = {}): KitchenInstance {
|
|
71
|
+
// Production 환경에서는 noop 반환
|
|
72
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') {
|
|
73
|
+
return createNoopInstance();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 브라우저 환경이 아니면 noop 반환
|
|
77
|
+
if (typeof window === 'undefined') {
|
|
78
|
+
return createNoopInstance();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 이미 초기화되었으면 기존 인스턴스 반환
|
|
82
|
+
if (isInitialized) {
|
|
83
|
+
console.warn('[Mandu Kitchen] Already initialized. Call destroy() first to reinitialize.');
|
|
84
|
+
return createInstance();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 비활성화 설정이면 noop 반환
|
|
88
|
+
if (config.enabled === false) {
|
|
89
|
+
return createNoopInstance();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 초기화 시작
|
|
93
|
+
try {
|
|
94
|
+
// 1. Hook 초기화
|
|
95
|
+
initializeHook();
|
|
96
|
+
|
|
97
|
+
// 2. Error Catcher 초기화
|
|
98
|
+
if (config.features?.errorOverlay !== false) {
|
|
99
|
+
initializeErrorCatcher();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 3. Network Proxy 초기화
|
|
103
|
+
if (config.features?.networkMonitor !== false) {
|
|
104
|
+
initializeNetworkProxy({
|
|
105
|
+
bodyPolicy: {
|
|
106
|
+
collectBody: config.network?.collectBody ?? false,
|
|
107
|
+
optInPolicy: {
|
|
108
|
+
maxBytes: config.network?.bodyMaxBytes ?? 10_000,
|
|
109
|
+
applyPIIFilter: true,
|
|
110
|
+
applySecretFilter: true,
|
|
111
|
+
allowedContentTypes: ['application/json', 'text/plain', 'text/event-stream'],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 4. Persistence 초기화
|
|
118
|
+
if (config.persistence?.enabled !== false) {
|
|
119
|
+
const persistence = initializePersistence(config.persistence);
|
|
120
|
+
|
|
121
|
+
// 저장된 이벤트 복원
|
|
122
|
+
const savedEvents = persistence.loadEvents();
|
|
123
|
+
if (savedEvents.length > 0) {
|
|
124
|
+
const stateManager = getStateManager(config);
|
|
125
|
+
for (const event of savedEvents) {
|
|
126
|
+
stateManager.handleEvent(event);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 5. v1.1: Worker Manager 초기화 (백그라운드, 실패해도 계속)
|
|
132
|
+
initializeWorkerManager().catch((err) => {
|
|
133
|
+
console.warn('[Mandu Kitchen] Worker initialization failed, using main thread fallback:', err);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 6. v1.1: AI Context Builder 초기화
|
|
137
|
+
const contextBuilder = getContextBuilder({ config });
|
|
138
|
+
|
|
139
|
+
// 7. UI 마운트
|
|
140
|
+
mountKitchen(config);
|
|
141
|
+
|
|
142
|
+
isInitialized = true;
|
|
143
|
+
|
|
144
|
+
console.log('[Mandu Kitchen] DevTools v1.1 initialized 🥟');
|
|
145
|
+
|
|
146
|
+
return createInstance();
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('[Mandu Kitchen] Initialization failed:', error);
|
|
149
|
+
return createNoopInstance();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* DevTools 정리
|
|
155
|
+
*/
|
|
156
|
+
export function destroyManduKitchen(): void {
|
|
157
|
+
if (!isInitialized) return;
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// UI 언마운트
|
|
161
|
+
unmountKitchen();
|
|
162
|
+
|
|
163
|
+
// v1.0 모듈 정리
|
|
164
|
+
destroyErrorCatcher();
|
|
165
|
+
destroyNetworkProxy();
|
|
166
|
+
destroyPersistence();
|
|
167
|
+
|
|
168
|
+
// v1.1 모듈 정리
|
|
169
|
+
destroyWorkerManager();
|
|
170
|
+
resetContextBuilder();
|
|
171
|
+
destroyMCPConnector();
|
|
172
|
+
|
|
173
|
+
isInitialized = false;
|
|
174
|
+
|
|
175
|
+
console.log('[Mandu Kitchen] DevTools destroyed');
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('[Mandu Kitchen] Cleanup failed:', error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ============================================================================
|
|
182
|
+
// Instance Factories
|
|
183
|
+
// ============================================================================
|
|
184
|
+
|
|
185
|
+
function createInstance(): KitchenInstance {
|
|
186
|
+
return {
|
|
187
|
+
destroy: destroyManduKitchen,
|
|
188
|
+
|
|
189
|
+
getState: () => getStateManager().getState(),
|
|
190
|
+
|
|
191
|
+
reportError: (error: Error | string) => {
|
|
192
|
+
const stateManager = getStateManager();
|
|
193
|
+
const message = typeof error === 'string' ? error : error.message;
|
|
194
|
+
const stack = typeof error === 'string' ? undefined : error.stack;
|
|
195
|
+
|
|
196
|
+
stateManager.addError({
|
|
197
|
+
id: `manual-${Date.now()}`,
|
|
198
|
+
type: 'runtime',
|
|
199
|
+
severity: 'error',
|
|
200
|
+
message,
|
|
201
|
+
stack,
|
|
202
|
+
timestamp: Date.now(),
|
|
203
|
+
url: window.location.href,
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
open: () => getStateManager().open(),
|
|
208
|
+
close: () => getStateManager().close(),
|
|
209
|
+
toggle: () => getStateManager().toggle(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function createNoopInstance(): KitchenInstance {
|
|
214
|
+
return {
|
|
215
|
+
destroy: () => {},
|
|
216
|
+
getState: () => ({} as any),
|
|
217
|
+
reportError: () => {},
|
|
218
|
+
open: () => {},
|
|
219
|
+
close: () => {},
|
|
220
|
+
toggle: () => {},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ============================================================================
|
|
225
|
+
// Auto-initialization (optional)
|
|
226
|
+
// ============================================================================
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 자동 초기화 (script 태그로 로드 시)
|
|
230
|
+
*
|
|
231
|
+
* HTML에서 사용:
|
|
232
|
+
* <script src="mandu-kitchen.js" data-auto-init data-position="bottom-left"></script>
|
|
233
|
+
*/
|
|
234
|
+
export function autoInit(): void {
|
|
235
|
+
if (typeof document === 'undefined') return;
|
|
236
|
+
|
|
237
|
+
// DOMContentLoaded 이후에 실행
|
|
238
|
+
if (document.readyState === 'loading') {
|
|
239
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
240
|
+
checkAndInit();
|
|
241
|
+
});
|
|
242
|
+
} else {
|
|
243
|
+
checkAndInit();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function checkAndInit(): void {
|
|
248
|
+
// data-auto-init 속성이 있는 script 태그 찾기
|
|
249
|
+
const script = document.querySelector('script[data-mandu-kitchen-auto-init]');
|
|
250
|
+
if (!script) return;
|
|
251
|
+
|
|
252
|
+
const config: DevToolsConfig = {};
|
|
253
|
+
|
|
254
|
+
// data 속성에서 설정 읽기
|
|
255
|
+
const position = script.getAttribute('data-position');
|
|
256
|
+
if (position) {
|
|
257
|
+
config.position = position as DevToolsConfig['position'];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const theme = script.getAttribute('data-theme');
|
|
261
|
+
if (theme) {
|
|
262
|
+
config.theme = theme as DevToolsConfig['theme'];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
initManduKitchen(config);
|
|
266
|
+
}
|