@mandujs/core 0.20.1 → 0.20.3
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
package/src/bundler/dev.ts
CHANGED
|
@@ -559,7 +559,7 @@ export function generateHMRClientScript(port: number): string {
|
|
|
559
559
|
|
|
560
560
|
function connect() {
|
|
561
561
|
try {
|
|
562
|
-
ws = new WebSocket('ws://
|
|
562
|
+
ws = new WebSocket('ws://' + window.location.hostname + ':' + HMR_PORT);
|
|
563
563
|
|
|
564
564
|
ws.onopen = function() {
|
|
565
565
|
console.log('[Mandu HMR] Connected');
|
|
@@ -84,13 +84,29 @@ export type MCPConnectionStatus =
|
|
|
84
84
|
// Constants
|
|
85
85
|
// ============================================================================
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* #176: 런타임에 현재 페이지 호스트/포트에서 MCP WebSocket URL을 유추한다.
|
|
89
|
+
* Bun 번들러가 `typeof window`를 컴파일 시 dead-code 제거하므로
|
|
90
|
+
* 함수로 감싸서 런타임 평가를 보장한다.
|
|
91
|
+
*/
|
|
92
|
+
function resolveDefaultServerUrl(): string {
|
|
93
|
+
try {
|
|
94
|
+
// eslint-disable-next-line no-restricted-globals
|
|
95
|
+
if (globalThis.document && globalThis.location) {
|
|
96
|
+
return `ws://${globalThis.location.hostname}:${globalThis.location.port}/mcp`;
|
|
97
|
+
}
|
|
98
|
+
} catch { /* SSR / Node / Bun 환경 */ }
|
|
99
|
+
return 'ws://localhost:3333/mcp';
|
|
100
|
+
}
|
|
101
|
+
|
|
87
102
|
const DEFAULT_OPTIONS: Required<MCPConnectorOptions> = {
|
|
88
|
-
serverUrl: '
|
|
103
|
+
serverUrl: '', // connect() 시 resolveDefaultServerUrl()로 대체
|
|
89
104
|
connectionTimeout: 5000,
|
|
90
105
|
requestTimeout: 30000,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
// #175: MCP 서버가 없을 수 있으므로 기본 비활성화
|
|
107
|
+
autoReconnect: false,
|
|
108
|
+
reconnectInterval: 1000,
|
|
109
|
+
maxReconnectAttempts: 3,
|
|
94
110
|
};
|
|
95
111
|
|
|
96
112
|
// ============================================================================
|
|
@@ -142,7 +158,9 @@ export class MCPConnector {
|
|
|
142
158
|
}, this.options.connectionTimeout);
|
|
143
159
|
|
|
144
160
|
try {
|
|
145
|
-
|
|
161
|
+
// #176: 빈 serverUrl이면 런타임에서 현재 페이지 기준으로 유추
|
|
162
|
+
const url = this.options.serverUrl || resolveDefaultServerUrl();
|
|
163
|
+
this.ws = new WebSocket(url);
|
|
146
164
|
|
|
147
165
|
this.ws.onopen = () => {
|
|
148
166
|
clearTimeout(timeout);
|
|
@@ -377,10 +395,11 @@ export class MCPConnector {
|
|
|
377
395
|
private handleDisconnect(): void {
|
|
378
396
|
this.ws = null;
|
|
379
397
|
|
|
380
|
-
|
|
398
|
+
// #175: handleConnectionError에서 이미 reconnect 예약한 경우 중복 방지
|
|
399
|
+
if (this.options.autoReconnect && this.status !== 'disconnected' && !this.reconnectTimer) {
|
|
381
400
|
this.setStatus('error');
|
|
382
401
|
this.scheduleReconnect();
|
|
383
|
-
} else {
|
|
402
|
+
} else if (!this.reconnectTimer) {
|
|
384
403
|
this.setStatus('disconnected');
|
|
385
404
|
}
|
|
386
405
|
}
|
|
@@ -389,12 +408,18 @@ export class MCPConnector {
|
|
|
389
408
|
console.warn('[Mandu Kitchen] MCP connection error:', error.message);
|
|
390
409
|
this.setStatus('error');
|
|
391
410
|
|
|
392
|
-
if (this.options.autoReconnect) {
|
|
411
|
+
if (this.options.autoReconnect && !this.reconnectTimer) {
|
|
393
412
|
this.scheduleReconnect();
|
|
394
413
|
}
|
|
395
414
|
}
|
|
396
415
|
|
|
397
416
|
private scheduleReconnect(): void {
|
|
417
|
+
// #175: 기존 타이머 취소 (중복 방지)
|
|
418
|
+
if (this.reconnectTimer) {
|
|
419
|
+
clearTimeout(this.reconnectTimer);
|
|
420
|
+
this.reconnectTimer = null;
|
|
421
|
+
}
|
|
422
|
+
|
|
398
423
|
if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {
|
|
399
424
|
console.warn('[Mandu Kitchen] Max reconnection attempts reached');
|
|
400
425
|
this.setStatus('disconnected');
|
|
@@ -402,15 +427,21 @@ export class MCPConnector {
|
|
|
402
427
|
}
|
|
403
428
|
|
|
404
429
|
this.reconnectAttempts++;
|
|
430
|
+
// #175: exponential backoff (1s → 2s → 4s → ... → max 30s)
|
|
431
|
+
const delay = Math.min(
|
|
432
|
+
this.options.reconnectInterval * Math.pow(2, this.reconnectAttempts - 1),
|
|
433
|
+
30_000,
|
|
434
|
+
);
|
|
405
435
|
console.log(
|
|
406
|
-
`[Mandu Kitchen] Reconnecting in ${
|
|
436
|
+
`[Mandu Kitchen] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.options.maxReconnectAttempts})`
|
|
407
437
|
);
|
|
408
438
|
|
|
409
439
|
this.reconnectTimer = setTimeout(() => {
|
|
440
|
+
this.reconnectTimer = null;
|
|
410
441
|
this.connect().catch(() => {
|
|
411
442
|
// 에러는 handleConnectionError에서 처리됨
|
|
412
443
|
});
|
|
413
|
-
},
|
|
444
|
+
}, delay);
|
|
414
445
|
}
|
|
415
446
|
|
|
416
447
|
private async sendRequest<T>(method: string, params: unknown): Promise<T> {
|
package/src/runtime/ssr.ts
CHANGED
|
@@ -372,7 +372,7 @@ window.__MANDU_HMR_PORT__ = ${hmrPort};
|
|
|
372
372
|
|
|
373
373
|
function connect() {
|
|
374
374
|
try {
|
|
375
|
-
ws = new WebSocket('ws://
|
|
375
|
+
ws = new WebSocket('ws://' + window.location.hostname + ':${hmrPort}');
|
|
376
376
|
ws.onopen = function() {
|
|
377
377
|
console.log('[Mandu HMR] Connected');
|
|
378
378
|
reconnectAttempts = 0;
|
|
@@ -618,7 +618,7 @@ window.__MANDU_HMR_PORT__ = ${hmrPort};
|
|
|
618
618
|
|
|
619
619
|
function connect() {
|
|
620
620
|
try {
|
|
621
|
-
ws = new WebSocket('ws://
|
|
621
|
+
ws = new WebSocket('ws://' + window.location.hostname + ':${hmrPort}');
|
|
622
622
|
ws.onopen = function() {
|
|
623
623
|
console.log('[Mandu HMR] Connected');
|
|
624
624
|
reconnectAttempts = 0;
|