存储 / 事件 / 受限文件写
存储 / 事件 / 受限文件写
Section titled “存储 / 事件 / 受限文件写”插件的数据与系统边界:持久化 KV、配置快照、全量凭据、Tauri 事件订阅、 原生对话框与受安全约束的文件写。
持久化存储(ctx.storage)
Section titled “持久化存储(ctx.storage)”插件私有 KV,落在 config.json 的 settings.pluginSettings.<pluginId>,
随宿主配置同步落盘。同步读写:
storage: { get<T>(key: string, fallback: T): T; set(key: string, value: unknown): void;}const token = ctx.storage.get("token", "");ctx.storage.set("token", "…");要点:
- 每个插件的存储互不可见(按 pluginId 分桶)。
- 卸载插件时持久化状态保留在
pluginSettings里,重装后可恢复 (目录与授权会被删除,见 信任模型与安全边界)。
配置快照(ctx.config)
Section titled “配置快照(ctx.config)”配置同步类插件可以通过 ctx.config 导出/导入宿主完整配置:
config: { export(): Promise<string>; // 当前完整配置快照(JSON 字符串) import(json: string): Promise<void>; // 应用快照并立即落盘}// 导出const snapshot = await ctx.config.export();
// 导入(例如从 WebDAV/S3 下载回来的配置)await ctx.config.import(snapshot);要点:
- 需要 L1
process能力(ctx.config与全量 vault 共用同一把信任锁)。 - 导出内容包含 hosts / settings / pluginSettings / layouts。
- 导入会复用启动时的迁移/归一化逻辑,更新当前运行中的 store 并立即
store_write一次,避免被后续防抖写覆盖。 - 插件自身的数据也可以继续用
ctx.storage;ctx.config面向“整机配置 备份/恢复”场景。
全量凭证(ctx.vault 批量)
Section titled “全量凭证(ctx.vault 批量)”ctx.vault 除按 id 读写外,还提供全量备份/恢复:
vault: { // 按 id(无能力门禁) get(id: string): Promise<string | null>; set(id: string, secret: string): Promise<void>; delete(id: string): Promise<void>;
// 批量(需要 L1 `process`) list(): Promise<string[]>; export(): Promise<Record<string, string>>; import(entries: Record<string, string>): Promise<void>; // 整体替换}const allSecrets = await ctx.vault.export();// 上传到远端前建议先加密。await ctx.vault.import(allSecrets);import 是整体替换语义:传入 map 中不存在的旧条目会被删除,配合
export 可做完整恢复。
事件订阅(ctx.events)
Section titled “事件订阅(ctx.events)”订阅 Tauri 事件。事件名必须在白名单前缀内,白名单外的订阅会被拒绝 并打印错误:
pty:// sshch:// serial:// ssh:// transfer://fs-progress:// tray:// forward:// proc://(流式进程 chunk/exit 事件)events: { listen(event: string, cb: (payload: unknown) => void): Disposer;}// 订阅某主机隧道变更(forward://changed 由 ctx.tunnels.onChanged 封装,// 一般直接用 tunnels.onChanged 即可)const off = ctx.events.listen("forward://changed", (payload) => { // payload: { sessionId?, hostId? }});事件名与负载没有统一的 schema(由各后端会话约定),使用前先确认对应
API 是否已有封装(如 tunnels.onChanged、terminal.onOutput、
ProcessHandle.onData 都已包装好,优先用它们)。
原生对话框(ctx.dialog)
Section titled “原生对话框(ctx.dialog)”用于「导出结果到本地文件」一类的流程:
dialog: { pickSavePath(opts?: { defaultName?: string; extensions?: string[] }): Promise<string | null>; pickFile(opts?: { extensions?: string[] }): Promise<string | null>; pickDirectory(): Promise<string | null>;}pickSavePath:弹「另存为」对话框;取消返回null。选中的路径会在 本次会话内被fs.writeText授权可写。pickFile:弹「打开文件」对话框;extensions是可选扩展名白名单 (不含前导点、小写,如["tar"]);取消返回null。官方 Docker 插件的 load image 对话框用。pickDirectory:弹「选择目录」对话框;取消返回null。适合让用户 指定本地同步/备份目录。
受限文件写(ctx.fs)
Section titled “受限文件写(ctx.fs)”fs: { writeText(path: string, content: string): Promise<void>; // UTF-8 文本}安全约束:fs.writeText 不做任意路径写——只允许写入本次会话内
经 ctx.dialog.pickSavePath 返回的路径(宿主在 context 内记录已授权
路径集合),防止插件乱写文件系统。取消对话框(返回 null)或未授权
路径都会抛错:
const path = await ctx.dialog.pickSavePath({ defaultName: "batch-result.txt" });if (!path) return; // 用户取消await ctx.fs.writeText(path, content); // 仅此路径可写完整示例:导出结果到本地文件
Section titled “完整示例:导出结果到本地文件”async function exportResults(rows) { const content = rows.map((r) => r.join(",")).join("\n"); const path = await ctx.dialog.pickSavePath({ defaultName: "result.csv" }); if (!path) return; try { await ctx.fs.writeText(path, content); ctx.ui.toast.success({ title: "已导出", description: path }); } catch (e) { ctx.ui.toast.error({ title: "导出失败", description: String(e) }); }}