v0 → 1.0 升级
Aiao 目前处于 0.x 阶段(当前发布版本 0.0.25)。按 semver,0.x 期间次版本即可包含破坏性变更。本页说明 1.0 将稳定哪些内容,以及破坏性变更如何被追踪和公布。
版本策略、公开 API 范围与废弃周期见版本与 API 稳定性策略。
1.0 将稳定的范围
1.0 发布后,以下对外表面进入 semver 维护,破坏性变更只能随主版本发布:
- 核心:
@aiao/rxdb的实体装饰器、Repository/查询接口、RxDB生命周期 API - 适配器契约:
@aiao/rxdb-adapter-*的公开构造与选项类型 - 框架绑定:
@aiao/rxdb-{angular,react,vue}的 hooks / provider 公开 API(三端对称) - 插件契约:
@aiao/rxdb-plugin-*的注册入口与选项类型
不在稳定范围内的内容(内部实现、@internal 标注符号、未文档化导出)见稳定性策略。
破坏性变更如何追踪
- 每个公开包维护 API 基线快照(
requirements/api-baseline/<pkg>.json),记录导出符号表面。 - CI 在每次变更时对比基线:未声明的破坏性变更会导致检查失败。
- 确属破坏性的变更必须:更新基线、在 PR 中标注 breaking、并在本页补充升级说明。
0.x 期间的升级建议
在 1.0 之前:
- 锁定次版本:升级前查阅 CHANGELOG。
- 同步升级
@aiao/*:所有包共用同一发布版本号,避免混用不同版本。 - 对照兼容矩阵:确认 Node / 框架 / 适配器版本,见兼容矩阵。
- 跑通类型检查:本项目对公开类型做编译期契约测试;升级后先
tsc验证消费端。
升级步骤(通用)
# 1. 同步升级所有 @aiao/* 到目标版本
pnpm up "@aiao/*@latest"
# 2. 重新安装并构建
pnpm install
pnpm build
# 3. 运行类型检查与测试,确认无破坏
pnpm tsc --noEmit
若升级涉及数据结构变化,配合 Schema 迁移 编写一次性迁移脚本。
版本专属破坏性变更
1.0 正式发布时,本节将逐版本列出破坏性变更与对应迁移步骤。当前 0.x 阶段的变更记录见 CHANGELOG。
0.0.25 之后(未发布)
第 13 项与第 68 项改的是接口成员或函数参数。requirements/api-baseline/*.json 只按导出符号的名字和种类
(value / type / both)逐个比对,看不见这一类变化,所以在此手工登记。第 4、5 项是普通的导出移除,
基线已随提交更新(rxdb-plugin-querycache.json / rxdb.json),一并列在这里方便查阅。
第 1 项与第 58 项影响从 4 项动的是 0.0.25 升级的应用。第 20.0.25 之后才出现、还没有发布过的 API:
只从 0.0.25 升级的应用碰不到它们;跟着 main 开发、用过这些 API 的代码需要照下面改。
1. SwitchBranchOptions 新增必填成员 prepare
prepare 是切换事务内的前置钩子:适配器解析出目标分支之后、动第一行之前 await 它,抛出即回滚
整次切换。
直接调用 adapter.switchBranch() 的代码必须传入 prepare,否则编译期报错。不需要前置校验的
调用点显式传入哨兵实现:
import { SKIP_BRANCH_SWITCH_PREPARE } from '@aiao/rxdb';
// before
adapter.switchBranch({ branchId, actions });
// after
adapter.switchBranch({ branchId, actions, prepare: SKIP_BRANCH_SWITCH_PREPARE });
自行实现适配器 switchBranch() 的,要在切换事务内、解析出目标分支之后、改 activated /
重建触发器 / 套用 actions 之前,恰好调用一次 options.prepare({ executor, targetBranchId });
它抛出的错误原样上抛,不要 catch。
2. uninstallWorkingTreeCapture 去掉了 raw 参数
// before
function uninstallWorkingTreeCapture(target: WorkingTreeCaptureMountTarget, raw: RawWritePrimitives): void;
// after
function uninstallWorkingTreeCapture(target: WorkingTreeCaptureMountTarget): void;
调用方删掉第二个实参即可;卸载不再需要调用方回传原始写方法。
3. RxDBSystemContribution:assertBranchSwitchable 更名为 prepareBranchSwitch,另增两个必填方法
assertBranchSwitchable→prepareBranchSwitch。签名不变((context: RxDBBranchSwitchContext) => Promise<void>), 语义变了:以前在调用方另开的只读事务里、切换之前执行;现在由适配器经SwitchBranchOptions.prepare在切换事务内部回调,context.executor可写,写下的行与这次切换同生共死,抛出即回滚整次切换。 该落的只有切换本身必然带来的行(例如激活代际 +1),业务数据不在此列。- 新增两个必填方法:
takeOverBranchSwitch(context: RxDBBranchSwitchTakeoverContext): Promise<RxDBBranchSwitchTakeover>: 不接管的贡献方返回'not_applicable',主流程照常走普通切换settleBranchSwitchFailure(context: RxDBBranchSwitchFailureContext): Promise<void>: 没有诊断要落的贡献方返回一个已决 promise
贡献点(不计 capability / version / packageSpecifier 三个身份字段)从 7 个变为 9 个,全部必填。
自行实现 RxDBSystemContribution 的插件要完成更名并补齐两个新方法,结构类型检查会在编译期直接指出
缺失的成员。
4. @aiao/rxdb-plugin-querycache 收窄公开导出(移除 10 个根导出)
以下符号不再从包根导出:assertQueryCacheCapabilities、createQueryCachePrimary、
DEFAULT_QUERY_CACHE_SYNC_STALE_TIME、queryCacheFingerprint、QueryCacheFingerprintInput、
QueryCachePrimaryLocalAdapter、QueryCachePrimaryRepository、QueryCacheSyncMemo、
QueryCacheSyncResult、RxDBQueryCacheEngineFactory。它们是读路径的内部装配件,
rxdb.use(rxDBPluginQueryCache) 之后由插件自己装配,仓库内没有任何包外引用。
包根只保留 rxDBPluginQueryCache、RxDBPluginQueryCache、RxDBPluginQueryCacheOptions 与
QueryCacheEngine(实验档)。直接导入过被移除符号的代码,改为注册插件后经 rxdb 使用读路径。
读路径横跨 @aiao/rxdb-plugin-history、@aiao/rxdb-plugin-sync、@aiao/rxdb-plugin-querycache
三个包,只注册 querycache 一个会在 connect() 抛 RxDBMissingPluginError:
rxdb.use(rxDBPluginHistory);
rxdb.use(rxDBPluginSync);
rxdb.use(rxDBPluginQueryCache);
详见 QueryCache 读引擎拆包。
5. @aiao/rxdb 根入口不再导出九个实体内部函数
entity.utils 由 export * 改为具名导出,以下九个函数不再从包根导出:
setSafeObjectKey、setRuntimeObjectKey、setRuntimeObjectGetter、setSafeObjectWritableKey、setSafeObjectKeyLazyInitOnce:往实体类与实例上挂不可枚举元数据的Object.defineProperty包装fillDefaultValue、fillInitValue:实体构造期的填充步骤getNeedSaveEntities、getNeedRemoveEntities:保存/删除路径上递归收集关联实体的步骤
它们都没有公开替代。getEntityStatus(entity) 上仍有同名的 getNeedSaveEntities() /
getNeedRemoveEntities() 方法,但只看这一个实体的直接关系,不做被移除函数那样的递归收集与过滤,
不能原样替换。
6. 触发器 / 建表 SQL 生成函数不再默认写 main,branchId 改为必填
触发器把 branchId 烙成 SQL 字面量,决定这张表之后每一次写入记到哪条分支名下。以前生成函数在
调用方没给时顶上 'main',库停在别的分支时写错了也不报错,只有事后审计历史才看得出来。现在每个
调用点都要自己给出分支 id,新库建表就显式传 MAIN_BRANCH_ID:
@aiao/rxdb-adapter-sqlite-core的generate_table_trigger_sql(metadata, options):options.branchId由可选改为必填,运行时缺失即抛RxDBAdapterSqliteError。@aiao/rxdb-adapter-pglite的generate_trigger_sql(metadata, options):同上,缺失即抛RxdbAdapterPGliteError。@aiao/rxdb-adapter-sqlite-core的create_tables_sql:新增必填的第三个位置参数branchId, 原来的第三个参数entities顺延为第四个。
import { MAIN_BRANCH_ID } from '@aiao/rxdb';
// before
generate_table_trigger_sql(metadata, { resolveEntityMetadata });
create_tables_sql(adapter, EntityTypes, entities);
// after
generate_table_trigger_sql(metadata, { branchId: MAIN_BRANCH_ID, resolveEntityMetadata });
create_tables_sql(adapter, EntityTypes, MAIN_BRANCH_ID, entities);
库可能已经停在非 main 分支上时(例如给既有库补建实体表),要先在同一个事务里读出当前活动分支再传进来;
RxDBAdapterSqliteBase.createTables 就是这么做的。pglite 的 create_tables_sql /
create_tables_statements 签名不变:它们建表期仍按 main 生成,由 RxDBAdapterPGlite.createTables
在同一事务里按当前分支重挂。
7. getEntityMutations 的入参字段改为 camelCase
@aiao/rxdb 的 getEntityMutations(options) 两个入参字段改名,语义不变:
// before
getEntityMutations({ need_save_entities, need_remove_entities });
// after
getEntityMutations({ needSaveEntities, needRemoveEntities });
TS 调用方会在编译期报错。JS 调用方(以及绕过类型检查的调用点)得不到任何提示:旧键解构出
undefined,运行到遍历那一步抛 TypeError。入参类型现在以 EntityMutationsOptions 导出,需要单独
声明入参的代码直接引用它。
8. RxDB 接口不再声明 RxDBSync / RxDBMigration / RxDBChange / RxDBBranch 四个成员
@aiao/rxdb 以前用 declare module '@aiao/rxdb' 给 RxDB 接口增广了这四个成员(类型是同名系统实体类),
但运行时从来没有给它们赋过值:rxdb.RxDBChange 编译得过,读出来却是 undefined。这段增广已删除,
这样写的代码现在会在编译期报错。四个实体类一直从包根导出,改为直接导入:
// before
rxdb.RxDBChange; // 运行时是 undefined
// after
import { RxDBChange } from '@aiao/rxdb';