export declare const LEGACY_AUTH_RETRY_TTL_MS: number; interface EditorConnectionOptions { port: number; host?: string; reconnect?: boolean; reconnectInterval?: number; maxReconnectInterval?: number; connectTimeout?: number; requestTimeout?: number; maxReconnectAttempts?: number; secret?: string; authTimeout?: number; } export declare class EditorConnection { private readonly options; private ws; private requestId; private pending; private notificationHandlers; private reconnectTimer; private connected; private reconnectEnabled; private connectAttempt; private connectGeneration; /** 3A (2026-09-19 安全加固批3): 明文 auth 降级记忆——auth_begin 收到旧端 error 响应后 * 置 true,本实例后续连接直接走 legacyPlaintextAuth(免每次探测)。 * 批4-T2: 配套 _legacyAuthSince 时间戳,TTL 过期后下次连接重试 CR(成功即复位)。 */ private _useLegacyAuth; private _legacyAuthSince; private disconnectHandlers; private reconnectHandlers; /** I-04: Handlers called specifically when reconnect attempts are exhausted (not on normal disconnect). */ private reconnectExhaustedHandlers; /** Track dropped notify() calls so callers can detect stale scene-tree state */ private _droppedNotifications; /** Guard against duplicate fireDisconnect() calls */ private _disconnectFired; /** * A-3 (2026-08-14 finding :932): auth 失败(exhaustion)已 fire 标记。 * 去重:同一轮"auth 耗尽"只 fire 一次 reconnectExhausted handlers(对齐 I-04 * "exactly once" 不变量),下次成功连接时复位。 */ private _authExhaustedFired; /** * Backward-compatible setter: converts a direct assignment like * `conn.onDisconnect = fn` into the multicast Set pattern. */ get onDisconnect(): (() => void) | null; set onDisconnect(fn: (() => void) | null); get onReconnect(): (() => void) | null; set onReconnect(fn: (() => void) | null); /** Add a handler invoked when the editor disconnects. */ addOnDisconnectHandler(handler: () => void): void; /** Remove a previously added disconnect handler. */ removeOnDisconnectHandler(handler: () => void): void; /** Add a handler invoked when the editor reconnects. */ addOnReconnectHandler(handler: () => void): void; /** Remove a previously added reconnect handler. */ removeOnReconnectHandler(handler: () => void): void; /** I-04: Add a handler invoked when reconnect attempts are exhausted (distinct from normal disconnect). */ addOnReconnectExhaustedHandler(handler: () => void): void; removeOnReconnectExhaustedHandler(handler: () => void): void; private fireDisconnect; private fireReconnect; /** * I-04/A-3: fire reconnectExhausted handlers。 * 2026-08-06 审查 P2:迭代前 Array.from 快照 + try/catch 容错(对齐 fireDisconnect/fireReconnect), * 防第一个 handler 调 disconnect() 触发 reconnectExhaustedHandlers.clear() 致后续 handler 静默丢失。 */ private fireReconnectExhausted; private readonly host; private readonly shouldReconnect; private readonly reconnectBaseMs; private readonly maxReconnectMs; private readonly connectTimeoutMs; private readonly requestTimeoutMs; private readonly authTimeoutMs; private reconnectAttempt; private readonly maxReconnectAttempts; private readonly editorSecret; private authenticated; private authFailureCount; private authFailed; private authLockoutUntil; constructor(options: EditorConnectionOptions); connect(): Promise; private setupMessageHandler; request(method: string, params?: Record, options?: { timeoutMs?: number; }): Promise; /** * Send a fire-and-forget notification to the editor plugin. * * NOTE: This is currently unused but retained as a future-facing API. * When adopting it for critical state changes (e.g. scene-tree mutations), * consider using request() instead to guarantee delivery, or check * droppedNotifications > 0 after a batch of notify calls and trigger * a full scene-tree refresh if any were lost. */ notify(method: string, params?: Record): void; /** Number of notify() calls that failed to send since last check */ get droppedNotifications(): number; /** Reset the dropped notification counter (call after consuming the value) */ resetDroppedNotifications(): void; onNotification(method: string, handler: (params: unknown) => void): void; offNotification(method: string, handler?: (params: unknown) => void): void; startOperation(timeoutSec: number): Promise; endOperation(): Promise; /** 3A (2026-09-19 安全加固批3): challenge-response 握手编排。 * * 防假监听者(H3):本机恶意进程先绑 9090/9081 可收到旧协议主动发送的明文 secret; * proof 模式下 secret 永不上线路,对端只能收到 HMAC(对单次 challenge 有效)——拿不到 * secret 本身,无法连真插件横向复用。 * * 降级矩阵(兼容矩阵的关键风险控制): * - 实例记忆 _useLegacyAuth=true 且未过 TTL → 直接明文(旧端已确认,免每次探测) * - 批4-T2: 降级记忆 TTL(LEGACY_AUTH_RETRY_TTL_MS)过期 → 下次连接重试 CR, * 成功即复位记忆(插件升级后免重启恢复 proof 模式);再降级则重置 TTL。 * - auth_begin 收到 JSON-RPC error 响应(err.code 为 number,对端至少是真 JSON-RPC * 服务端——旧插件回 -32001 后 close)→ 记忆降级 + warn。 * [已知残余面]协议感知的假监听者可伪造 -32001 诱降级收 secret——localhost 明文 * 模型下不可根除,设 GODOT_MCP_EDITOR_REQUIRE_CR_AUTH=true 硬锁可拒一切降级。 * - 探测超时(哑占位者不回应)→ **不降级**直接 fail(secret 不上线)。 * - GODOT_MCP_EDITOR_REQUIRE_CR_AUTH=true → 非成功 challenge 路径一律 fail。 */ private performAuth; /** challenge-response 握手主体(auth_begin → challenge → HMAC proof)。 * 可降级的失败(error 响应/无 challenge 的 result 响应)抛错挂 crFallback=true; * 超时/断连/proof 阶段失败不挂(不可降级)。 */ private challengeResponseAuth; /** 强制 challenge-response 模式(高安全 opt-in):拒绝一切明文降级。 */ private requireCrAuth; /** 旧明文 auth 握手(id=-1,单发 secret)——proof 模式探测失败后的降级路径,原 performAuth 逻辑原样保留。 */ private legacyPlaintextAuth; private scheduleReconnect; disconnect(): void; /** * Reset reconnect state so that a subsequent `connect()` can re-enable * reconnection. This is useful after max-reconnect-attempts was reached * and you want to retry later. */ resetReconnectState(): void; /** * 手动触发重连:重置耗尽状态(reconnectEnabled/attempt)并启动后台重连循环。 * 用于 manage_tools(reconnect) 在 connect 一次性失败后,让编辑器恢复时自动连上, * 避免用户须反复手动调 reconnect 或重启 MCP 服务端(反馈 reconnecting 卡死)。 */ requestReconnect(): void; /** * B8: 连接活性语义说明。 * 仅反映 ws 'open'/'close' 事件后的 connected flag, 非TCP 实时活性—— * TCP 半开(对端 accept 不响应不 close)时此方法仍返回 true。 * 实时活性检测见 HealthMonitor 心跳(health-monitor.ts startHeartbeat + ping)。 */ isConnected(): boolean; } export {};