开发者文档/接口参考

Web SDK 参考

查阅 @trove/plugin-sdk 的请求、类型化服务、事件、取消和连接生命周期。

核对日期:2026 年 9 月 11 日

本页目录

安装与连接#

本参考对应 SDK 0.0.1-alpha.1 与 Bridge 协议 v1。SDK 由 CLI 本地套件提供;新项目用 trove new,已有项目用 接入向导。

ts
import { host } from "@trove/plugin-sdk";

await host.ready();
console.log(host.context);

ready() 返回 Promise<void>,同一个 transport 共享连接;每次调用也会自动等待就绪。导入是惰性的,默认 Host 调用和 context 读取需要在 Trove WebView 中进行。

Context 字段含义
curioId、curioVersionCurio ID 与 Manifest 版本
instanceId当前 UI 实例
apiVersion1
mode"development" 或 "production"

Context 只读,由 Host 绑定调用方身份。

请求与服务客户端#

底座能力用 host.xxx;跨插件先按 Curio ID 获取引用,再直接调用方法。以下示例需要生成的类型、私有处理函数及已安装的示例提供者:

ts
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 仍可施加上限。

ts
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;提供方必须实现事件:

ts
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。

结构化错误#

ts
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 导入:

ts
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 迁移#

sh
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 不能取代真正调用的错误处理。

ts
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 退出、禁用、卸载会结束提供者。关闭开发窗口会结束该开发会话,行为不同。调用方不能通过丢弃引用停止其他插件正在使用的进程。