@aiao/rxdb-plugin-workspace
v0.0.25
Published
RxDB Workspace 插件为**尚未入库的 NEW 实体草稿**提供本地恢复能力:草稿保存在内存和 IndexedDB 中,并通过 BroadcastChannel 同步同源标签页。刷新或重开页面后,草稿会自动恢复,可继续编辑、保存或丢弃。
Readme
@aiao/rxdb-plugin-workspace
RxDB Workspace 插件为尚未入库的 NEW 实体草稿提供本地恢复能力:草稿保存在内存和 IndexedDB 中,并通过 BroadcastChannel 同步同源标签页。刷新或重开页面后,草稿会自动恢复,可继续编辑、保存或丢弃。
范围:只覆盖 NEW 草稿。已存在实体的未保存 UPDATE、回滚到编辑前状态、DELETE 撤销均不在本插件范围内,详见「已知限制」。
当前语义
- 监听 NEW 事件并缓存完整草稿,不写主表。
- NEW 草稿的顶层属性后续变化会重新排队,恢复或跨标签页收到的 entity ref 也遵循同一规则。
entity.save()(CREATE)、REMOVE 或discard()会清理对应草稿。install()会自动读取 IndexedDB;已注册 EntityType 的草稿会恢复为 entity ref,尚未注册类型的草稿仍保留在list()中。首次读取失败会让readyreject,修复环境后可再次调用install()重试。list()返回基于structuredClone()的深快照,不与内部缓存共享嵌套引用;草稿含不可克隆值时同步抛DataCloneError。flush()是 IndexedDB 写入屏障。底层写入失败时会 reject 并恢复待写/待删集合,不会在后台无限重试;修复环境后再次显式调用即可重试。不可克隆草稿会以WorkspaceFlushError.cacheIds点名,其他可克隆草稿照常落盘。changes$在草稿、暂存状态或可观测错误变化时发出通知。corruptedEntries同时包含无法解码的 IndexedDB 记录和当前跨标签页同步错误;后者在同步恢复后自动清除。
安装
pnpm add @aiao/rxdb-plugin-workspace @aiao/rxdb使用
import { rxDBPluginWorkspace } from '@aiao/rxdb-plugin-workspace';
// db 已按所选 adapter 的文档完成配置。
db.use(rxDBPluginWorkspace, { autoSave: true });
db.init();
await db.workspace.ready;
// 新建实体即进入草稿缓存
const todo = new Todo({ title: '写文档' });
// 列出全部草稿(刷新后仍在)
const drafts = db.workspace.list();
// 保存到主表:草稿自动移出缓存
await todo.save();
// 或丢弃草稿
db.workspace.discard(drafts[0].cacheId);
await db.workspace.flush();autoSave 默认为 true。设为 false 后,事件仍会更新内存队列和跨标签页状态,但不会自动写 IndexedDB;调用方必须在需要持久化时执行 await db.workspace.flush()。
生命周期与单实例
一个 RxDB 实例在整个生命周期内只允许一个 workspace 实例:
- 对同一数据库重复调用
rxDBPluginWorkspace(db)会返回已安装实例,不会增加监听器。 - 直接重复调用内部构造函数(
new RxDBPluginWorkspace(db),未从包入口导出)会在注册监听器前抛错。 - 第一次安装时传入的 options 在该数据库生命周期内有效,后续重复 factory 调用不会替换配置。
destroy()会移除 RxDB/BroadcastChannel 监听器、关闭 channel、停止刷盘订阅并清空内存队列;它不会隐式执行flush()。destroy()对该RxDB实例是终态。需要重新安装时应创建新的RxDB实例。
正常使用应通过 db.use(rxDBPluginWorkspace, options) 让 RxDB 管理 install() 和 destroy()。
浏览器、SSR 与持久化边界
插件依赖浏览器的 crypto.randomUUID()、structuredClone() 和 IndexedDB;BroadcastChannel 可用时才启用跨标签页同步。因此不要在 SSR 渲染阶段构造插件,应在浏览器 hydration 后创建并初始化 RxDB。
IndexedDB 中的 workspace 数据是草稿副本,不是数据库事务日志。destroy()、浏览器清理站点数据或存储配额错误都可能使未刷盘数据丢失。关键流程必须显式 await flush()。
通信与数据安全
BroadcastChannel 不是鉴权或授权边界。任何同源执行上下文只要知道数据库名称,就可能向 workspace channel 发送 add/remove 消息。应用必须依赖可信 origin、CSP 和自身权限模型,不能把该通道当作安全控制。
草稿无法结构化克隆时,插件会保留本地草稿、跳过该次广播并通过 corruptedEntries / changes$ 报告,不会中断 RxDB 的后续事件监听器。
插件不会加密草稿,也不会过滤敏感字段。草稿会以应用提供的结构写入 IndexedDB,并可能通过同源 BroadcastChannel 传输。不要把不应落盘或不应暴露给同源脚本的数据放入 workspace 草稿。
已知限制
- 既有实体的未保存 UPDATE 暂存:未支持。 插件只为 NEW 草稿订阅其
EntityStatus.patches$;实体成功 CREATE 后就退出 workspace,之后的未保存 UPDATE 不在本插件范围内。 - 嵌套对象原地修改:不触发变更跟踪。 RxDB Entity Proxy 只拦截顶层属性赋值。
draft.meta.nested.value = 'x'不会重新排队;应构造新值并重新赋给顶层字段,例如draft.meta = { ...draft.meta, nested: { value: 'x' } }。 - 公开 restore/rollback:未支持。 NEW 草稿会在安装时自动恢复,但现有实体的回滚需要完整 base/inverse patch 数据模型,并依赖上述未保存 UPDATE 入口。
- DELETE 撤销:未支持。 REMOVE/CREATE 目前只负责清理 NEW 草稿,不保存被删实体快照。
因此当前包不能作为完整的 Git 式 entity workspace。需要既有实体 UPDATE 暂存或回滚的调用方应使用单独的数据模型,不应依赖本插件的 NEW 草稿缓存。
已移除 API
stagedChange() / unstageChange() / commit() / stagedCount 与 WorkspaceCacheEntry.staged 是早期 Git 式暂存流程的遗留导出,已在 0.0.24 删除。
这些 API 没有等价替代:它们承载的“既有实体 UPDATE 暂存 / 提交”能力本就不在本插件范围内(见上一节能力边界)。当前公开面只有 NEW 草稿缓存(list() / discard())、变更监听(changes$)与自动保存(autoSave / flush())。仍依赖旧暂存语义的调用方需要自建数据模型。
