import type { BladeClient } from "../blade-client"; import { AgentSession } from "./agent-session"; import type { ConnectionStatus } from "./state"; export interface SessionConnectOptions { /** * 在会话进入事件路由后、历史加载与房间订阅开始前同步执行。 * 适合安装不能漏掉 bootstrap 回放事件的监听器。 */ setup?: (session: AgentSession) => void; } /** * 每个 BladeClient 一个:管理一条 Socket.IO 连接,按 session_id 把事件 * 路由给各 AgentSession 实例。多会话共享连接、状态互不干扰。 */ export declare class SessionHub { private readonly client; private readonly sessions; private readonly bootstrapPending; /** 每个会话当前有多少方持有(connect 一次 +1,dispose 一次 -1)。 */ private readonly holdCounts; private connection; private readonly connectionListeners; private bound; private hasConnected; private readonly authBusyReconnect; constructor(client: BladeClient); /** 当前 Socket.IO 连接状态。 */ getConnection(): ConnectionStatus; /** 订阅连接状态变化。 */ onConnectionChange(listener: (status: ConnectionStatus) => void): () => void; /** * 取得(或复用)一个会话的 AgentSession,并完成历史加载 + 房间订阅。 * * 每次调用都算一份持有,调用方用完必须 `dispose()` 归还。复用同一实例时 * 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类"连两次 * 只释放一次"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。 */ connect(sessionId: string, options?: SessionConnectOptions): Promise; /** 已有实例则返回,不触发网络请求。 */ peek(sessionId: string): AgentSession | undefined; /** 手动重连(例如登录态变化后)。 */ reconnect(): void; /** 断开连接(不清理 session 实例)。 */ disconnect(): void; /** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */ disposeAll(): void; /** * @internal 底层 socket 被换掉时由 BladeClient 调用(如 setBaseUrl)。 * 事件监听器绑在旧 socket 实例上,换新实例后必须重绑,否则所有 * turn:* / chat:* 事件都会静默丢弃。 */ _handleSocketReplaced(): void; private runtimeFor; /** 记一份持有。 */ private hold; /** * 归还一份持有;还剩别的持有者时返回 false,让 AgentSession 保持可用。 * 归零才退订房间并从路由表移除。 */ private release; /** 不管还有几方持有都立即释放(启动失败、切换身份)。 */ private forceRelease; private ensureConnected; private setConnection; /** 事件带 session_id 时精确路由;缺省时按当前唯一活跃会话兜底。 */ private route; private ensureBound; private routeArtifact; }