import { type LoginOptions, type LoginResult, type TokenStorageMode } from "./auth-login"; import { type BladeFetchInit, type HttpMethod } from "./rest"; import { AuthResource } from "./resources/auth"; import { HeadlessResource } from "./resources/headless"; import { ComputersResource } from "./resources/computers"; import { ModelsResource } from "./resources/models"; import { SessionsResource } from "./resources/sessions"; import { PluginsResource } from "./resources/plugins"; import { ChatGroupsResource } from "./resources/chat-groups"; import { SiteVisitsResource } from "./resources/site-visits"; import { SessionHub } from "./session/hub"; import { type TypedSocket } from "./socket"; export interface BladeClientOptions { /** 后端地址,如 "https://blade.example.com"。浏览器里传空字符串则使用当前域名。 */ baseUrl: string; /** * 访问令牌(PAT)。不传时按 cookie 会话模式工作; * 浏览器场景也可以不传,改用 client.auth.login() 弹窗登录。 */ token?: string | (() => string | null | undefined); /** * Socket.IO 专用令牌。第一方应用可在 REST 继续使用 cookie 刷新的同时, * 把 cookie 换得的短期令牌只用于实时连接;不传时复用 token。 */ socketToken?: string | (() => string | null | undefined); /** login() 取得的令牌存放位置,默认 "local"(localStorage,刷新页面不掉登录)。 */ tokenStorage?: TokenStorageMode; /** Host-owned command transport; event subscriptions stay on the normal socket. */ commandTransport?: (event: string, payload: Record, send: () => Promise>) => Promise>; fetchImpl?: typeof fetch; onRefreshSuccess?: () => void | Promise; } export declare class BladeClient { private refreshPromise; private socketInstance; private readonly socketReplacementListeners; /** login() / setToken() 热挂载的令牌,优先级高于构造参数。 */ private runtimeToken; readonly options: BladeClientOptions; readonly auth: AuthResource; readonly headless: HeadlessResource; readonly computers: ComputersResource; readonly models: ModelsResource; readonly sessions: SessionsResource; /** 按用户读取的插件目录与图标;没有会话时也能用。 */ readonly plugins: PluginsResource; readonly chatGroups: ChatGroupsResource; /** * 全站访问统计:匿名读写,不带 bearer 也不触发登录刷新。 * 只有内置 Web 的同源页面使用,第三方宿主页面不会被自动统计。 */ readonly siteVisits: SiteVisitsResource; /** 实时会话中枢:client.sessions.connect() 内部使用,一般不直接访问。 */ readonly hub: SessionHub; constructor(options: BladeClientOptions); /** * 弹窗授权登录:用户在弹出的授权页点击"许可授权"后自动取得 PAT, * REST 与 Socket.IO 立即生效。只在浏览器可用。 */ login(options?: LoginOptions): Promise; /** 退出登录:清除 login() 存储的令牌并断开实时连接。 */ logoutToken(): void; /** 热挂载访问令牌(null 表示清除)。会重建 Socket.IO 连接以携带新凭证。 */ setToken(token: string | null): void; /** 当前是否持有访问令牌(不代表令牌一定有效)。 */ hasToken(): boolean; /** * 当前访问令牌(PAT),未登录时为 null。 * * SDK 只封装会话相关接口;其余长尾接口对照后端 Swagger(`/docs`) * 用原生 fetch 自行调用,把本令牌填入 Authorization 头即可: * * ```ts * fetch(`${baseUrl}/api/memories/search?q=xxx`, { * headers: { Authorization: `Bearer ${client.token}` }, * }) * ``` * * 安全约束:该令牌只应发往 baseUrl 同源接口,不要附加到第三方域名的请求上。 */ get token(): string | null; setBaseUrl(baseUrl: string): void; /** 底层 Socket.IO 实例因后端地址变化而被替换时通知高级集成层。 */ onSocketReplaced(listener: () => void): () => void; socket(): TypedSocket; requestCommand(event: string, payload: Record, timeoutMs: number): Promise>; json(method: HttpMethod, path: string, body?: unknown): Promise; jsonFromInit(path: string, init?: RequestInit): Promise; text(method: HttpMethod, path: string): Promise; textFromInit(path: string, init?: RequestInit): Promise; responseFromInit(path: string, init?: RequestInit): Promise; blob(method: HttpMethod, path: string): Promise; formData(method: HttpMethod, path: string, form: FormData, options?: { expectOk?: boolean; onUploadProgress?: (progress: UploadProgress) => void; }): Promise; fetch(method: HttpMethod, path: string, init?: BladeFetchInit, isRetry?: boolean): Promise; buildAuthedUrl(path: string): string; private buildHeaders; private buildUrl; private baseUrlWithTrailingSlash; private isSameBackendUrl; private shouldRefreshFor401; private hasExplicitBearerToken; /** * 等一次令牌刷新,但调用方中止请求时不再等下去。 * * 刷新本身是共享的(`refreshPromise`,别的请求也在等它),这里只是让这次已被取消的 * 请求尽早结束——否则它会一直挂在调用方(定位)的串行队列里,用户改选的新目标要等到 * 刷新结束才轮得到。 */ private tryRefreshUnlessAborted; private tryRefresh; private resolveTokenForUrl; private resolveRestToken; private resolveSocketToken; private resolveToken; private formDataWithUploadProgress; } export interface UploadProgress { loaded: number; total?: number; percent?: number; }