Web SDK 参考
查阅 @trove/plugin-sdk 的请求、类型化服务、事件、取消和连接生命周期。
核对日期:2026 年 9 月 11 日
本页目录
安装与连接#
本参考对应 SDK 0.0.1-alpha.1 与 Bridge 协议 v1。SDK 由 CLI 本地套件提供;新项目用 trove new,已有项目用 接入向导。
import { host } from "@trove/plugin-sdk";
await host.ready();
console.log(host.context);
ready() 返回 Promise<void>,同一个 transport 共享连接;每次调用也会自动等待就绪。导入是惰性的,默认 Host 调用和 context 读取需要在 Trove WebView 中进行。
| Context 字段 | 含义 |
|---|---|
curioId、curioVersion | Curio ID 与 Manifest 版本 |
instanceId | 当前 UI 实例 |
apiVersion | 1 |
mode | "development" 或 "production" |
Context 只读,由 Host 绑定调用方身份。
请求与服务客户端#
底座能力用 host.xxx;跨插件先按 Curio ID 获取引用,再直接调用方法。以下示例需要生成的类型、私有处理函数及已安装的示例提供者:
import { host } from "@trove/plugin-sdk";
import { createClient as createDevice } from "./generated/backend.js";
const { text } = await host.clipboard.readText();
await host.storage.set({ key: "draft", value: text });
// Optional private client; its name belongs to your application.
const device = createDevice();
const local = await device.uppercase({ text: "hello" });
const TextTools = await host.curios.get("dev.example.text-tools");
console.log((await TextTools.uppercase({ text: local.text })).text);
内部 UI ↔ Backend 的组织由作者决定。device、api、backend 都是可选的应用变量名,不是协议规定。可选的私有生成客户端路由到 @self;原有 HTTP/WebSocket 或应用自己的抽象也可保留,见内部通信边界。
无业务参数的方法省略 {},最后一个参数是 CallOptions。生成类型来自 Contract,但 TypeScript 不能代替运行时验证,默认 Host 没有对任意业务载荷开启完整 JSON Schema 校验。
超时与取消#
CallOptions 接受 timeoutMs?: number 与 signal?: AbortSignal,放在方法最后一个参数;无业务参数的方法只接收 options。默认期限来自 Contract,未声明时 30 秒;文件对话框为 5 分钟。显式超时范围为 1–2,147,483,647 ms,Host 仍可施加上限。
import { host } from "@trove/plugin-sdk";
const controller = new AbortController();
const request = host.runtime.getHostInfo({
timeoutMs: 5_000,
signal: controller.signal,
});
// Connect controller.abort() to a cancel button or component cleanup.
console.log(await request);
一次调用的总预算包含连接、冷启动和执行,反向调用继承剩余预算。超时、取消、断线会结束等待;取消后台执行是协作式的,不会撤销已完成的副作用,也不会自动重放请求。
事件订阅与清理#
本例使用 服务指南 中带 progress 主题的 Contract;提供方必须实现事件:
import { createClient } from "./generated/text-tools.js";
const curio = createClient();
const controller = new AbortController();
const subscription = await curio.events.progress(
{ taskId: "preview" },
event => console.info(event.progress),
{ signal: controller.signal },
);
// Release when the owning screen or task is finished.
await subscription.close();
console.log((await subscription.closed).code);
TroveSubscription 包含 id、幂等的 close(): Promise<void> 和 closed: Promise<{ code: string; message?: string }>。closed 表达订阅结束原因,与业务 payload 分开;关闭、取消或连接结束时完成。
AbortSignal 可以取消建立过程,也可以关闭已建立的订阅。组件卸载时 abort 或 close,避免异步建立后泄漏。共享单例不应随每个组件卸载而断开;需要独立连接的测试用 自定义 transport。
结构化错误#
import { host, TroveError } from "@trove/plugin-sdk";
try {
await host.runtime.getHostInfo();
} catch (error) {
if (error instanceof TroveError) {
console.error(error.code, error.message, error.retryable, error.traceId);
} else {
console.error(error);
}
}
TroveError 继承 Error,含 code、message、可选 data、retryable(默认 false)和可选 traceId。根据稳定 code 判断错误;为用户展示恢复步骤,使用 trace ID 关联调试输出。retryable 不会自动触发重试。
自定义客户端与测试#
业务入口导出 host、createHost、TroveError 和公共类型。动态协议工具与测试适配器单独从 @trove/plugin-sdk/transport 导入:
import { createHost } from "@trove/plugin-sdk";
import { createMockBridge, createTransport } from "@trove/plugin-sdk/transport";
const transport = createTransport({
bridge: createMockBridge({
"host.clipboard.readText": () => ({ text: "test text" }),
}),
});
const host = createHost(transport);
try {
console.log((await host.clipboard.readText()).text);
} finally {
transport.disconnect();
}
createTransport({ bridge?, context?, onListenerError? }) 创建独立连接;可传给 createHost 或生成的 createClient。disconnect 会拒绝 pending 请求、释放订阅,已断开的 transport 不能复活。TroveBridge 的 connect/send/disconnect 与协议 v1 供自定义适配器使用。Mock 的限制见 测试指南。
从 SDK 0.1 迁移#
trove kit
npm install
trove generate
trove check
按项目实际包管理器执行 install。仅有 Host 调用、没有 bindings 的 UI-only 项目可跳过 generate。
| 旧用法 | 新用法 |
|---|---|
trove.call("host.clipboard", "readText", {}) | host.clipboard.readText() |
trove.self.call("uppercase", params) | 生成私有 client 后 backend.uppercase(params) |
trove.service(serviceId).call("uppercase", params) | await host.curios.get(curioId) 后 curio.uppercase(params) |
createTroveClient / 主入口 Mock 导入 | transport 子入口的 createTransport / createMockBridge |
getPaths().logs 与磁盘日志 | 当前运行的调试控制台与 dev 终端 |
Host、SDK 与 Rust Kit 当前统一保持 0.0.1-alpha.1。套件以内容摘要区分同版本的新构建,更新后重新安装依赖、生成、构建和打包。选择私有客户端时补充 contract 与 bindings;添加 bindings.services[].curio 可得到 ID 推导。不要为更新 SDK 修改 Curio ID,已有安装数据保持原身份。Rust 是合约源;TypeScript 仅作为可选的生成客户端,不是另一份手写合约。
旧 serviceId 与新 curioId 不能混用。例如服务 dev.example.text-tools.files 的拥有者是 dev.example.text-tools,应获取 host.curios.get("dev.example.text-tools"),再访问 files 成员。仅当服务 ID 等于 Curio ID 时才直接挂根方法。已有的独立生成客户端仍按服务 ID 路由。
Curio 引用与生命周期#
| 方法 | 语义 |
|---|---|
has(id, options?) | 是否在当前 Host 的安装或开发注册表中;禁用时也为 true |
status(id, options?) | 返回快照,不启动;缺失时 state 为 not-installed |
get(id, options?) | 检查后构造公开能力引用,不启动,不开 UI |
start(id, options?) | 检查并启动公开 Backend,等待 ready,返回状态,不开 UI |
所有方法都是异步的。CurioStatus 包括 id、installed、enabled、hasBackend、version(缺失时 null)与 state。state 为 not-installed / disabled / stopped / starting / running / failed / cooldown。状态随时可能变化,has/status 不能取代真正调用的错误处理。
import { host } from "@trove/plugin-sdk";
if (await host.curios.has("dev.example.text-tools")) {
const snapshot = await host.curios.status("dev.example.text-tools");
console.log(snapshot.state, snapshot.enabled);
await host.curios.start("dev.example.text-tools", { timeoutMs: 10_000 });
}
引用不拥有后端进程,没有需要逐个销毁的底层连接。变量可自由命名和组合,也可在组件间复用;按任务释放各自的订阅即可。后端重启后,后续调用重新经过 Host 路由;进行中的失败调用不会重放,旧订阅不会自动恢复。安装新版本后建议重新 get 获取新的能力描述,并检查版本要求。
公开提供者的已安装窗口关闭时,Backend 保持独立运行;配置 idleTimeoutMs 可在无调用/订阅后回收,默认 0 不启用空闲回收。Host 退出、禁用、卸载会结束提供者。关闭开发窗口会结束该开发会话,行为不同。调用方不能通过丢弃引用停止其他插件正在使用的进程。