@aiao/rxdb-plugin-sync 0.0.0-stage → 0.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -2
  3. package/dist/SyncManager.d.ts +426 -0
  4. package/dist/SyncManager.d.ts.map +1 -0
  5. package/dist/branch-change-id.d.ts +31 -0
  6. package/dist/branch-change-id.d.ts.map +1 -0
  7. package/dist/branch-materialization-source.d.ts +22 -0
  8. package/dist/branch-materialization-source.d.ts.map +1 -0
  9. package/dist/branch-utils.d.ts +40 -0
  10. package/dist/branch-utils.d.ts.map +1 -0
  11. package/dist/bulk-sync.d.ts +117 -0
  12. package/dist/bulk-sync.d.ts.map +1 -0
  13. package/dist/cascade-blocking.d.ts +38 -0
  14. package/dist/cascade-blocking.d.ts.map +1 -0
  15. package/dist/check-repository-updates.d.ts +47 -0
  16. package/dist/check-repository-updates.d.ts.map +1 -0
  17. package/dist/cleanup-expired.d.ts +56 -0
  18. package/dist/cleanup-expired.d.ts.map +1 -0
  19. package/dist/dependency-graph.d.ts +128 -0
  20. package/dist/dependency-graph.d.ts.map +1 -0
  21. package/dist/get-all-repository-sync-status.d.ts +58 -0
  22. package/dist/get-all-repository-sync-status.d.ts.map +1 -0
  23. package/dist/get-repository-sync-status.d.ts +68 -0
  24. package/dist/get-repository-sync-status.d.ts.map +1 -0
  25. package/dist/index.d.ts +39 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +3773 -0
  28. package/dist/plugin.d.ts +74 -0
  29. package/dist/plugin.d.ts.map +1 -0
  30. package/dist/pull-ancestor-changes.d.ts +41 -0
  31. package/dist/pull-ancestor-changes.d.ts.map +1 -0
  32. package/dist/pull-batch.d.ts +16 -0
  33. package/dist/pull-batch.d.ts.map +1 -0
  34. package/dist/pull-conflict-utils.d.ts +43 -0
  35. package/dist/pull-conflict-utils.d.ts.map +1 -0
  36. package/dist/pull-repository.d.ts +55 -0
  37. package/dist/pull-repository.d.ts.map +1 -0
  38. package/dist/pull-round.d.ts +41 -0
  39. package/dist/pull-round.d.ts.map +1 -0
  40. package/dist/pull.d.ts +16 -0
  41. package/dist/pull.d.ts.map +1 -0
  42. package/dist/push-branch.d.ts +22 -0
  43. package/dist/push-branch.d.ts.map +1 -0
  44. package/dist/push-repository.d.ts +79 -0
  45. package/dist/push-repository.d.ts.map +1 -0
  46. package/dist/push.d.ts +14 -0
  47. package/dist/push.d.ts.map +1 -0
  48. package/dist/query-cache-outbox.d.ts +120 -0
  49. package/dist/query-cache-outbox.d.ts.map +1 -0
  50. package/dist/sync-branches.d.ts +81 -0
  51. package/dist/sync-branches.d.ts.map +1 -0
  52. package/dist/sync-listeners.d.ts +20 -0
  53. package/dist/sync-listeners.d.ts.map +1 -0
  54. package/dist/sync-manager.utils.d.ts +36 -0
  55. package/dist/sync-manager.utils.d.ts.map +1 -0
  56. package/dist/sync-repository.d.ts +64 -0
  57. package/dist/sync-repository.d.ts.map +1 -0
  58. package/dist/topological-sort.d.ts +126 -0
  59. package/dist/topological-sort.d.ts.map +1 -0
  60. package/package.json +60 -3
  61. package/src/SyncManager.ts +690 -0
  62. package/src/branch-change-id.ts +70 -0
  63. package/src/branch-materialization-source.ts +445 -0
  64. package/src/branch-utils.ts +74 -0
  65. package/src/bulk-sync.ts +349 -0
  66. package/src/cascade-blocking.ts +61 -0
  67. package/src/check-repository-updates.ts +143 -0
  68. package/src/cleanup-expired.ts +285 -0
  69. package/src/dependency-graph.ts +324 -0
  70. package/src/get-all-repository-sync-status.ts +115 -0
  71. package/src/get-repository-sync-status.ts +237 -0
  72. package/src/index.ts +58 -0
  73. package/src/plugin.ts +132 -0
  74. package/src/pull-ancestor-changes.ts +61 -0
  75. package/src/pull-batch.ts +386 -0
  76. package/src/pull-conflict-utils.ts +284 -0
  77. package/src/pull-repository.ts +700 -0
  78. package/src/pull-round.ts +103 -0
  79. package/src/pull.ts +204 -0
  80. package/src/push-branch.ts +62 -0
  81. package/src/push-repository.ts +1541 -0
  82. package/src/push.ts +106 -0
  83. package/src/query-cache-outbox.ts +939 -0
  84. package/src/sync-branches.ts +276 -0
  85. package/src/sync-listeners.ts +309 -0
  86. package/src/sync-manager.utils.ts +48 -0
  87. package/src/sync-repository.ts +307 -0
  88. package/src/topological-sort.ts +246 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aiao Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,82 @@
1
- # Temporary Holding Version
1
+ # @aiao/rxdb-plugin-sync
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Implements: [US-025 核心插件化外移](https://github.com/aiao-io/rxdb/blob/main/requirements/stories/core/US-025-core-plugin-extraction.md)
4
+
5
+ 推拉同步、冲突落地与仓库依赖序。装上它,`rxdb.syncManager` 才存在。
6
+
7
+ 核心 `@aiao/rxdb` 保留的是**原语**:`RxDBSync` 水位表、变更编解码、冲突模型(`ConflictResolution` / `RxDBConflictError`)与同步资格判定。搬进本包的是**消费者**:整库与单仓库两个粒度的 push / pull / sync、冲突落地、依赖拓扑序、过期清理与 QueryCache 出站队列。
8
+
9
+ ## 安装
10
+
11
+ ```bash
12
+ pnpm add @aiao/rxdb @aiao/rxdb-plugin-history @aiao/rxdb-plugin-sync
13
+ ```
14
+
15
+ `@aiao/rxdb-plugin-history` 不是可选的:本包声明 `inject: ['plugin:history']`。
16
+
17
+ ## 使用
18
+
19
+ ```typescript
20
+ import { RxDB, SyncType } from '@aiao/rxdb';
21
+ import { rxDBPluginHistory } from '@aiao/rxdb-plugin-history';
22
+ import { rxDBPluginSync } from '@aiao/rxdb-plugin-sync';
23
+
24
+ const rxdb = new RxDB({
25
+ dbName: 'notes',
26
+ entities: [Note],
27
+ sync: { type: SyncType.Full, local: { adapter: 'wa-sqlite' }, remote: { adapter: 'supabase' } }
28
+ });
29
+
30
+ // 传工厂函数本身,不要调用它;两句 use() 的先后随意——宿主按 inject 拓扑排序
31
+ rxdb.use(rxDBPluginHistory).use(rxDBPluginSync).adapter('wa-sqlite' /* … */);
32
+
33
+ await rxdb.connect('wa-sqlite');
34
+
35
+ await rxdb.syncManager.sync();
36
+ await rxdb.syncManager.pushRepository('public', 'note');
37
+ ```
38
+
39
+ `use()` 必须早于 `connect()`——`connect()` 内部就会调 `init()`。
40
+
41
+ `connect()` 返回之前本包的 `install()` 一定跑完,这一点比没有 `inject` 的插件更值得留意:声明了依赖的插件**不在** `init()` 里安装,它要等历史插件装好、状态转 `active`,宿主再对齐一趟才轮到它。`rxdb.init()` 之后紧接着读 `rxdb.syncManager` 会读到 `undefined`,那不是缺陷而是时序——`connect()` 是这条链的静止点。
42
+
43
+ ## 主要能力
44
+
45
+ | 分组 | 入口 |
46
+ | -------- | --------------------------------------------------------------------------------------------- |
47
+ | 推拉 | `push()` / `pull()` / `sync()` / `pushRepository()` / `pullRepository()` / `syncRepository()` |
48
+ | 批量 | `bulkSync()` / `getRepositoryDependencyGraph()` / `getRepositorySyncOrder()` |
49
+ | 仓储状态 | `getRepositorySyncStatus()` / `getAllRepositorySyncStatus()` / `checkRepositoryUpdates()` |
50
+ | 分支 | `syncBranches()` |
51
+ | 计数 | `refreshPullableCount()` |
52
+ | 清理 | `cleanupExpired()` |
53
+
54
+ 水位线是 `RxDBSync.lastPushedChangeId`,push 与 QueryCache 出站共用同一条——两者都在把本地变更送去远端,各记一条水位会让「已推到哪」在同一张表上有两个答案。
55
+
56
+ ## 与历史插件的关系
57
+
58
+ 单向:本包 `inject: ['plugin:history']`,历史包不认识本包。耦合只走一张窄接口(`SyncHistoryBridge`)——一次往返结束时 undo 边界要作废、待拉计数要结算,而那些状态的主人在历史侧。
59
+
60
+ 两件事的生命周期本就不同,所以它们各自成包:撤销重做要在第一条 `rxdb_change` 之前就位(历史插件因此**不**声明任何 `inject`),推拉同步则只在配了远端时才有意义。
61
+
62
+ ## 与 QueryCache 插件的关系
63
+
64
+ 只有 `import type { QueryCacheRemoteAdapter }`,**不产生** `inject` 运行期依赖。装了本包、没装 `@aiao/rxdb-plugin-querycache` 且没有 QueryCache 实体的工作区照常运行。
65
+
66
+ ## 没装插件时
67
+
68
+ `rxdb.syncManager` **不存在**(读到 `undefined`),核心不给一个什么都不做的空壳。
69
+
70
+ 只装了本包、忘了装历史插件时,本包停在 `waiting` 永远装不上——依赖来源尘埃落定后宿主会点名一次:
71
+
72
+ ```
73
+ [RxDB] Plugin 'sync' is not installed: unsatisfied dependencies [plugin:history]
74
+ ```
75
+
76
+ `syncState` 面板上的待拉数由本包维护:远端适配器在实时订阅恢复后发 `syncState.requestPullableRefresh()`,本包接住它并调 `refreshPullableCount()`。没装本包,那个读数就是无人维护——这正是实情,不是零。
77
+
78
+ ## 连接纪元
79
+
80
+ 插件声明 `lifecycle: 'scoped'`,三处宿主改动全部登记在 `install(scope)` 收到的作用域上,`disconnectAll()` 时逆序释放,宿主不调用 `destroy()`:`SyncManager` 实例本身(`destroy()` 随它撤掉 `connected$` 自动回推订阅与远端事件监听)、`rxdb.syncManager` 槽位、`syncState.bindPullableRefresh()` 跳板。释放走逆拓扑序,本包先于历史插件撤销。
81
+
82
+ 重新 `connect()` 装的是一个全新的管理器,而不是复活上一纪元那个——后者指向的事件总线已经拆了。
@@ -0,0 +1,426 @@
1
+ import { PullOptions, PullResult, PushOptions, PushResult, RxDB, SyncResult } from '@aiao/rxdb';
2
+ import { PushInFlightRegistry, SyncHistoryBridge } from '@aiao/rxdb-plugin-history';
3
+ import { BulkSyncOptions, BulkSyncResult } from './bulk-sync.js';
4
+ import { CheckRepositoryUpdatesResult } from './check-repository-updates.js';
5
+ import { CleanupExpiredOptions, CleanupExpiredResult } from './cleanup-expired.js';
6
+ import { DependencyGraph, RepositoryIdentifier } from './dependency-graph.js';
7
+ import { GetAllRepositorySyncStatusFilter } from './get-all-repository-sync-status.js';
8
+ import { RepositorySyncStatus } from './get-repository-sync-status.js';
9
+ import { PullRepositoryOptions, PullRepositoryResult } from './pull-repository.js';
10
+ import { PushRepositoryOptions, PushRepositoryResult } from './push-repository.js';
11
+ import { SyncBranchesResult } from './sync-branches.js';
12
+ import { SyncRepositoryOptions, SyncRepositoryResult } from './sync-repository.js';
13
+ import { SortDirection } from './topological-sort.js';
14
+ /**
15
+ * 同步管理器
16
+ *
17
+ * 负责整库与单仓库两个粒度的推拉同步:
18
+ * - `pull` / `push` / `sync`:整库
19
+ * - `pullRepository` / `pushRepository` / `syncRepository` / `bulkSync`:按仓库
20
+ * - `getRepositorySyncStatus` / `checkRepositoryUpdates` / `cleanupExpired`:状态与清理
21
+ * - `getRepositoryDependencyGraph` / `getRepositorySyncOrder`:依赖图与同步顺序
22
+ *
23
+ * @remarks
24
+ * US-025 阶段 D 之前这些入口挂在 `@aiao/rxdb-plugin-history` 的 `VersionManager` 上。
25
+ * 切开的理由是两件事的生命周期本就不同:撤销重做要在第一条 `rxdb_change` 之前就位,
26
+ * 推拉同步则只在配了远端时才有意义。
27
+ *
28
+ * 切开之后仍有一条**单向**耦合:一次同步往返结束时 undo 边界要作废、待拉计数要结算,
29
+ * 而那些状态的主人是历史侧。它经 {@link SyncHistoryBridge} 这一张窄接口相遇 ——
30
+ * 本插件 `inject: ['plugin:history']`,历史插件则对本包一无所知。
31
+ */
32
+ export declare class SyncManager {
33
+ #private;
34
+ readonly rxdb: RxDB;
35
+ readonly history: SyncHistoryBridge;
36
+ /**
37
+ * 「哪些变更此刻正在飞往远端」的登记处。
38
+ *
39
+ * @remarks
40
+ * push 与 undo 唯一的会合点,实例的主人在历史侧(`rxdb.versionManager.pushInFlight`)。
41
+ * 两边读的必须是同一个,见 `PushInFlightRegistry`:push 在远端往返之前认领区间,
42
+ * undo 把认领区间当成已推 —— 各持一份,往返窗口内的一次撤销就会造成永久分叉。
43
+ *
44
+ * @internal
45
+ */
46
+ get pushInFlight(): PushInFlightRegistry;
47
+ /**
48
+ * 本地分支激活代际:每次分支切换开始与提交各加一。
49
+ *
50
+ * @remarks
51
+ * 推送在规划时记下它,回执提交事务里再比一次。只比分支 id 不够:远端往返期间
52
+ * main→feature→main 之后 id 又对上了,但 main 的业务投影已经被切走又切回重建过。
53
+ * 开始与提交都加一,是为了让「规划时恰好撞上一次进行中的切换」也被识别出来。
54
+ *
55
+ * 只覆盖本实例内的切换;跨标签页的切换由提交事务里读到的持久化 active 分支兜住
56
+ * (A→B→A 在跨标签页时不可见,属已知限制)。
57
+ *
58
+ * @internal
59
+ */
60
+ get branchSwitchGeneration(): number;
61
+ /**
62
+ * @param rxdb - 宿主实例
63
+ * @param history - 历史侧借来的那一小块面,由 `rxdb.versionManager.syncBridge` 提供
64
+ */
65
+ constructor(rxdb: RxDB, history: SyncHistoryBridge);
66
+ /** 装上 connected$ 自动回推与远端事件计数两条链路 */
67
+ init(): void;
68
+ /** 拆掉 {@link init} 装上的全部监听与订阅 */
69
+ destroy(): void;
70
+ /** 取本地适配器上的系统表仓库 */
71
+ getLocalRepositories(): Promise<{
72
+ branchRepository: import('@aiao/rxdb').LocalRxDBBranchRepository;
73
+ changeRepository: import('@aiao/rxdb').LocalRxDBChangeRepository;
74
+ adapter: import('@aiao/rxdb').LocalRxDBAdapter;
75
+ }>;
76
+ /** 取远端适配器上的系统表仓库 */
77
+ getRemoteRepositories(): Promise<{
78
+ branchRepository: import('@aiao/rxdb').RemoteRxDBBranchRepository;
79
+ changeRepository: import('@aiao/rxdb').RemoteRxDBChangeRepository;
80
+ adapter: import('@aiao/rxdb').RemoteRxDBAdapter;
81
+ }>;
82
+ /**
83
+ * 取当前分支;没有激活分支时激活(或新建)`main`。
84
+ *
85
+ * @remarks
86
+ * 同步链路里每条远端事件都要调它(`sync-listeners` 的 `filterByBranch`),
87
+ * 热路径不开事务,见 `getCurrentBranch`。
88
+ */
89
+ getCurrentBranch(): Promise<import('@aiao/rxdb').RxDBBranch>;
90
+ /**
91
+ * 从远程同步所有分支信息到本地
92
+ *
93
+ * 远程新分支 → 在本地创建(local: false, remote: true)
94
+ * 本地已有的远程分支 → 更新 remote 标记为 true
95
+ * 纯本地分支 → 不受影响
96
+ *
97
+ * @returns 同步结果
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const result = await rxdb.syncManager.syncBranches();
102
+ * console.log(`新增 ${result.created},更新 ${result.updated}`);
103
+ * ```
104
+ */
105
+ syncBranches(): Promise<SyncBranchesResult>;
106
+ /**
107
+ * 从远程拉取变更并应用到本地数据库
108
+ *
109
+ * 当 autoSync=false 时,会先应用 Realtime 缓存的变更,再拉取远程变更。
110
+ *
111
+ * @param options - 可选配置
112
+ * @returns 拉取结果
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * // 基本用法
117
+ * const result = await rxdb.syncManager.pull();
118
+ * console.log(`Pulled ${result.pulled} changes`);
119
+ *
120
+ * // 拉取所有数据
121
+ * const result = await rxdb.syncManager.pull({ fetchAll: true });
122
+ * ```
123
+ */
124
+ pull(options?: PullOptions): Promise<PullResult>;
125
+ /**
126
+ * 将本地未同步的变更推送到远程数据库
127
+ *
128
+ * 推送时会自动:
129
+ * 1. 查询 lastPushedChangeId 之后的新变更
130
+ * 2. 过滤已撤销的变更(revertChangeId != null)
131
+ * 3. 压缩变更(INSERT→DELETE 丢弃,INSERT→UPDATE* 合并为 INSERT)
132
+ * 4. 批量推送到远程
133
+ * 5. 更新 lastPushedChangeId 和 lastPushedAt
134
+ *
135
+ * @param options - 可选配置
136
+ * @returns 推送结果
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * // 基本用法
141
+ * const result = await rxdb.syncManager.push();
142
+ * console.log(`Pushed ${result.pushed} changes`);
143
+ *
144
+ * // 自定义批量大小
145
+ * const result = await rxdb.syncManager.push({ batchSize: 500 });
146
+ * ```
147
+ */
148
+ push(options?: PushOptions): Promise<PushResult>;
149
+ /**
150
+ * 执行完整的同步操作(先 pull 再 push)
151
+ *
152
+ * 推荐在重连后使用此方法,确保:
153
+ * 1. 先获取远程最新变更(避免覆盖他人数据)
154
+ * 2. 再推送本地变更
155
+ *
156
+ * @param options - 可选配置
157
+ * @returns 同步结果(包含 pull 和 push 结果)
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * // 基本用法
162
+ * const result = await rxdb.syncManager.sync();
163
+ * console.log(`Pulled ${result.pullResult.pulled}, Pushed ${result.pushResult.pushed}`);
164
+ * ```
165
+ */
166
+ sync(options?: {
167
+ pull?: PullOptions;
168
+ push?: PushOptions;
169
+ }): Promise<SyncResult>;
170
+ /**
171
+ * 拉取指定 Repository 的远程变更
172
+ *
173
+ * 提供实体类型级别的精细同步控制,支持级联同步以自动拉取关联实体。
174
+ *
175
+ * @param namespace - 实体命名空间(如 "public")
176
+ * @param entity - 实体名称(如 "Todo")
177
+ * @param options - 拉取选项
178
+ * @returns 拉取结果
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * // 拉取 Todo 并级联拉取依赖
183
+ * const result = await rxdb.syncManager.pullRepository('public', 'Todo', {
184
+ * includeRelated: true // 默认:若 Todo 有外键则自动拉取 User
185
+ * });
186
+ *
187
+ * // 不级联拉取
188
+ * const result = await rxdb.syncManager.pullRepository('public', 'Todo', {
189
+ * includeRelated: false // 仅拉取 Todo,可能引发外键错误
190
+ * });
191
+ * ```
192
+ */
193
+ pullRepository(namespace: string, entity: string, options?: PullRepositoryOptions): Promise<PullRepositoryResult>;
194
+ /**
195
+ * 推送指定 Repository 的本地变更
196
+ *
197
+ * 提供实体类型级别的精细同步控制,支持级联同步以自动推送依赖实体。
198
+ *
199
+ * @param namespace - 实体命名空间(如 "public")
200
+ * @param entity - 实体名称(如 "User")
201
+ * @param options - 推送选项
202
+ * @returns 推送结果
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * // 推送 User 并级联推送依赖方
207
+ * const result = await rxdb.syncManager.pushRepository('public', 'User', {
208
+ * includeRelated: true // 默认:若 Post 引用 User 则自动推送 Post
209
+ * });
210
+ *
211
+ * // 不级联推送
212
+ * const result = await rxdb.syncManager.pushRepository('public', 'User', {
213
+ * includeRelated: false // 仅推送 User,依赖数据可能不完整
214
+ * });
215
+ * ```
216
+ */
217
+ pushRepository(namespace: string, entity: string, options?: PushRepositoryOptions): Promise<PushRepositoryResult>;
218
+ /**
219
+ * 同步指定 Repository(先 pull 再 push)
220
+ *
221
+ * 将单个 Repository 的 pull 和 push 合并为一次操作,保证正确的执行顺序。
222
+ * 推荐在需要确保特定实体类型数据一致性时使用。
223
+ *
224
+ * @param namespace - 实体命名空间(如 "public")
225
+ * @param entity - 实体名称(如 "Todo")
226
+ * @param options - 同步选项(分别配置 pull 和 push)
227
+ * @returns 同步结果(包含 pull 和 push 结果)
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * // 基本用法
232
+ * const result = await rxdb.syncManager.syncRepository('public', 'Todo');
233
+ * console.log(`Pulled ${result.pullResult.pulled}, Pushed ${result.pushResult.pushed}`);
234
+ *
235
+ * // 自定义 pull 和 push 选项
236
+ * const result = await rxdb.syncManager.syncRepository('public', 'Todo', {
237
+ * pull: { limit: 500, fetchAll: true },
238
+ * push: { batchSize: 100 }
239
+ * });
240
+ * ```
241
+ */
242
+ syncRepository(namespace: string, entity: string, options?: SyncRepositoryOptions): Promise<SyncRepositoryResult>;
243
+ /**
244
+ * 清理不再满足过滤条件的本地过期数据
245
+ *
246
+ * 用于 SyncType.Filter 场景,删除不满足 filter 条件的本地数据
247
+ * 例如:清理超过 30 天的订单数据
248
+ *
249
+ * @param namespace - 实体命名空间
250
+ * @param entity - 实体名称
251
+ * @param options - 清理选项
252
+ * @returns 清理结果
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
257
+ * const { removed } = await rxdb.syncManager.cleanupExpired('public', 'Order', {
258
+ * filter: {
259
+ * combinator: 'and',
260
+ * rules: [{ field: 'updatedAt', operator: '>=', value: thirtyDaysAgo }]
261
+ * }
262
+ * });
263
+ * console.log(`Removed ${removed} expired records`);
264
+ * ```
265
+ */
266
+ cleanupExpired(namespace: string, entity: string, options?: CleanupExpiredOptions): Promise<CleanupExpiredResult>;
267
+ /**
268
+ * 检查远程是否有更新,不下载数据
269
+ *
270
+ * 仅查询远程有多少新变更,不实际拉取数据。
271
+ * 适用于显示「有 N 条远程更新」提示,节省带宽和时间。
272
+ *
273
+ * @param namespace - 实体命名空间(如 "public")
274
+ * @param entity - 实体名称(如 "Todo")
275
+ * @returns 更新检查结果
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * // 检查 Todo 是否有远程更新
280
+ * const result = await rxdb.syncManager.checkRepositoryUpdates('public', 'Todo');
281
+ * if (result.hasUpdates) {
282
+ * console.log(`有 ${result.pendingCount} 条更新可拉取`);
283
+ * // 用户点击「更新」按钮后再调用 pullRepository()
284
+ * }
285
+ * ```
286
+ */
287
+ checkRepositoryUpdates(namespace: string, entity: string): Promise<CheckRepositoryUpdatesResult>;
288
+ /**
289
+ * 获取单个 Repository 的同步状态
290
+ *
291
+ * 返回完整的同步状态信息,包括:
292
+ * - syncType(full/remote/local/disabled)
293
+ * - pushableCount(待推送的本地变更数)
294
+ * - pullableCount(可拉取的远程变更数)
295
+ * - 最近同步时间戳
296
+ *
297
+ * @param namespace - 实体命名空间(如 "public")
298
+ * @param entity - 实体名称(如 "Todo")
299
+ * @returns Repository 同步状态
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * const status = await rxdb.syncManager.getRepositorySyncStatus('public', 'Todo');
304
+ * console.log(`同步类型: ${status.syncType}`);
305
+ * console.log(`待推送: ${status.pushableCount},可拉取: ${status.pullableCount}`);
306
+ * ```
307
+ */
308
+ getRepositorySyncStatus(namespace: string, entity: string): Promise<RepositorySyncStatus>;
309
+ /**
310
+ * 获取所有 Repository 的同步状态
311
+ *
312
+ * 返回所有已注册实体的状态,支持可选过滤。
313
+ *
314
+ * @param filter - 可选过滤条件
315
+ * @returns Repository 同步状态数组
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * // 获取全部状态
320
+ * const statuses = await rxdb.syncManager.getAllRepositorySyncStatus();
321
+ *
322
+ * // 仅获取有待处理变更的 Repository
323
+ * const pending = await rxdb.syncManager.getAllRepositorySyncStatus({
324
+ * hasPendingChanges: true
325
+ * });
326
+ *
327
+ * // 仅获取已启用的全量同步 Repository
328
+ * const fullSync = await rxdb.syncManager.getAllRepositorySyncStatus({
329
+ * syncType: ['full'],
330
+ * enabled: true
331
+ * });
332
+ * ```
333
+ */
334
+ getAllRepositorySyncStatus(filter?: GetAllRepositorySyncStatusFilter): Promise<RepositorySyncStatus[]>;
335
+ /**
336
+ * 按各仓库持久化的远端水位线重新计算待拉变更数
337
+ *
338
+ * @returns 当前远端待拉变更总数
339
+ *
340
+ * @remarks
341
+ * 远程适配器在实时订阅恢复后调用。若刷新期间又收到实时事件,保留两者中的较大值,
342
+ * 避免把查询快照之后到达的通知覆盖掉。
343
+ */
344
+ refreshPullableCount(): Promise<number>;
345
+ /**
346
+ * 批量同步多个 Repository
347
+ *
348
+ * 在单次操作中同步多个 Repository,支持顺序或并发执行。
349
+ *
350
+ * @param options - 批量同步选项
351
+ * @returns 批量同步结果(包含成功/失败计数)
352
+ *
353
+ * @example
354
+ * ```typescript
355
+ * // 顺序同步所有已启用的 Repository
356
+ * const result = await rxdb.syncManager.bulkSync();
357
+ * console.log(`成功: ${result.succeeded},失败: ${result.failed}`);
358
+ *
359
+ * // 同步指定 Repository
360
+ * const result = await rxdb.syncManager.bulkSync({
361
+ * repositories: [
362
+ * { namespace: 'public', entity: 'Todo' },
363
+ * { namespace: 'public', entity: 'User' }
364
+ * ]
365
+ * });
366
+ *
367
+ * // 并发模式仅 pull
368
+ * const result = await rxdb.syncManager.bulkSync({
369
+ * concurrent: true,
370
+ * concurrency: 3,
371
+ * push: false
372
+ * });
373
+ *
374
+ * // 检查每项结果
375
+ * for (const item of result.results) {
376
+ * if (item.success) {
377
+ * console.log(`${item.repository.entity}: 已拉取 ${item.result?.pullResult.pulled ?? 0} 条`);
378
+ * } else {
379
+ * console.error(`${item.repository.entity}: ${item.error.message}`);
380
+ * }
381
+ * }
382
+ * ```
383
+ */
384
+ bulkSync(options?: BulkSyncOptions): Promise<BulkSyncResult>;
385
+ /**
386
+ * 获取所有 Repository 的依赖图
387
+ *
388
+ * 分析实体关系(MANY_TO_ONE、ONE_TO_ONE)以构建依赖图,
389
+ * 展示各 Repository 之间的依赖关系。
390
+ *
391
+ * @returns 包含依赖关系的依赖图
392
+ *
393
+ * @example
394
+ * ```typescript
395
+ * const graph = rxdb.syncManager.getRepositoryDependencyGraph();
396
+ *
397
+ * // 遍历依赖关系
398
+ * for (const [key, dep] of graph) {
399
+ * console.log(`${key} 依赖:`, dep.dependsOn);
400
+ * console.log(`${key} 被依赖:`, dep.requiredBy);
401
+ * }
402
+ * ```
403
+ */
404
+ getRepositoryDependencyGraph(): DependencyGraph;
405
+ /**
406
+ * 根据依赖关系获取 Repository 的同步顺序
407
+ *
408
+ * 通过拓扑排序确定基于依赖关系的正确同步顺序。
409
+ *
410
+ * @param direction - 排序方向:'pull'(父节点优先)或 'push'(子节点优先)
411
+ * @returns 有序的 Repository 列表
412
+ *
413
+ * @example
414
+ * ```typescript
415
+ * // 获取 pull 顺序(父节点优先)
416
+ * const pullOrder = rxdb.syncManager.getRepositorySyncOrder('pull');
417
+ * // [User, Todo, Comment]
418
+ *
419
+ * // 获取 push 顺序(子节点优先)
420
+ * const pushOrder = rxdb.syncManager.getRepositorySyncOrder('push');
421
+ * // [Comment, Todo, User]
422
+ * ```
423
+ */
424
+ getRepositorySyncOrder(direction: SortDirection): RepositoryIdentifier[];
425
+ }
426
+ //# sourceMappingURL=SyncManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncManager.d.ts","sourceRoot":"","sources":["../src/SyncManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { IRepository, RxDBChange } from '@aiao/rxdb';
2
+ /** 本模块只依赖 change 仓库的 `find`,用最小接口收窄,便于在事务 executor 上复用。 */
3
+ type ChangeFinder = Pick<IRepository<typeof RxDBChange>, 'find'>;
4
+ /**
5
+ * 本地分叉点 → 远端 change id。
6
+ *
7
+ * @param repository - 本地 `RxDBChange` 仓库
8
+ * @param localFromChangeId - 本地分支的 `fromChangeId`
9
+ * @returns 远端 id;分叉点尚未推送(`remoteId` 为空)时返回 `null`
10
+ * @throws RxDBError 本地压根不存在这条变更 —— 这是分支表与变更表已经不一致,不能猜
11
+ *
12
+ * @remarks
13
+ * 返回 `null` 表示「远端此刻确实不知道这个分叉点」,而不是「分叉点在根」。调用方要据此
14
+ * 决定是否在实体变更推送完成后重推一次分支,见 {@link pushBranch}。
15
+ */
16
+ export declare const toRemoteFromChangeId: (repository: ChangeFinder, localFromChangeId: number) => Promise<number | null>;
17
+ /**
18
+ * 远端分叉点 → 本地 change id。
19
+ *
20
+ * @param repository - 本地 `RxDBChange` 仓库(事务内请传 executor 作用域的那一份)
21
+ * @param remoteFromChangeId - 远端分支行上的 `fromChangeId`
22
+ * @returns 本地 id;对应的变更尚未拉到本地时返回 `null`
23
+ *
24
+ * @remarks
25
+ * 返回 `null` 时**不可**退化成 `null`/`0` 写进本地分支行:`find-switch-branch-step` 会把它
26
+ * 当「分叉于根」处理,切换分支时应用的区间从第一条变更起算。调用方应跳过该分支,
27
+ * 等分叉点变更拉到本地后的下一轮再建。
28
+ */
29
+ export declare const toLocalFromChangeId: (repository: ChangeFinder, remoteFromChangeId: number) => Promise<number | null>;
30
+ export {};
31
+ //# sourceMappingURL=branch-change-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-change-id.d.ts","sourceRoot":"","sources":["../src/branch-change-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,WAAW,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AACrE,2DAA2D;AAC3D,KAAK,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;AAcjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,YAAY,EACxB,mBAAmB,MAAM,KACxB,OAAO,CAAC,MAAM,GAAG,IAAI,CAMvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAC9B,YAAY,YAAY,EACxB,oBAAoB,MAAM,KACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAGvB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { BranchMaterializationSource } from '@aiao/rxdb';
2
+ import { SyncManager } from './SyncManager.js';
3
+ /**
4
+ * 造同步插件的分支物化来源。
5
+ *
6
+ * @param sm - 本纪元的同步管理器
7
+ * @returns 交给 `rxdb.branchMaterializationSource()` 登记的来源
8
+ *
9
+ * @remarks
10
+ * 各成员的调用时机由工作树插件决定,这里只守契约:
11
+ *
12
+ * - `freezeIntent` / `pages` 在任何事务之外跑,可以碰远端;
13
+ * - `resolveIntentDrift` / `projectPage` / `settle` 跑在切换事务里,只用传进来的执行器,
14
+ * 一次远端都不碰——绑在适配器上的仓库在那里会排在那笔事务自己后面,死锁。
15
+ *
16
+ * 投影**不区分**自己推上去的变更与别人的:metadata-only 分支在本地一行数据都没有,
17
+ * `pull` 跳过自己那份的前提(「本地已经有了」)在这里不成立。
18
+ *
19
+ * @internal
20
+ */
21
+ export declare const createSyncBranchMaterializationSource: (sm: SyncManager) => BranchMaterializationSource;
22
+ //# sourceMappingURL=branch-materialization-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-materialization-source.d.ts","sourceRoot":"","sources":["../src/branch-materialization-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAOL,KAAK,2BAA2B,EAqBjC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAsTpD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qCAAqC,GAAI,IAAI,WAAW,KAAG,2BA2EvE,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { EntityStaticType, RxDBBranch } from '@aiao/rxdb';
2
+ import { SyncManager } from './SyncManager.js';
3
+ /**
4
+ * 沿 `parentId` 向上走分支链所需的最小仓库能力。
5
+ *
6
+ * @remarks
7
+ * 写成结构化接口,是为了让绑在适配器上的本地仓库与事务执行器给出的仓库都接得住——
8
+ * 分支物化来源要在切换事务里按同一口径重算血缘,而绑在适配器上的仓库在那里会排在
9
+ * 那笔事务自己后面,死锁。
10
+ */
11
+ export interface BranchLineageReader {
12
+ /**
13
+ * 按条件查分支
14
+ *
15
+ * @param options - 查询选项
16
+ * @returns 命中的分支行
17
+ */
18
+ find(options: EntityStaticType<typeof RxDBBranch, 'findOptions'>): Promise<RxDBBranch[]>;
19
+ }
20
+ /**
21
+ * 获取当前分支及其所有祖先分支的 ID 列表
22
+ *
23
+ * @returns [currentBranch, parent, grandparent, ...] 例如 ['dev', 'main']
24
+ */
25
+ export declare function getAncestorBranchIds(sm: SyncManager, branchId: string): Promise<string[]>;
26
+ /**
27
+ * 用给定的分支仓库算 `branchId` 及其全部祖先——{@link getAncestorBranchIds} 的本体。
28
+ *
29
+ * @param branchRepository - 见 {@link BranchLineageReader}
30
+ * @param branchId - 起点分支
31
+ * @returns [branchId, parent, grandparent, ...]
32
+ *
33
+ * @remarks
34
+ * 拆出来给分支物化来源用:冻结意图时在事务外算一次,屏障里再用执行器的仓库算一次比对,
35
+ * 两处必须与 pull 同一口径,否则「范围变没变」的判定本身就在漂。
36
+ *
37
+ * @internal
38
+ */
39
+ export declare function ancestorBranchIdsFrom(branchRepository: BranchLineageReader, branchId: string): Promise<string[]>;
40
+ //# sourceMappingURL=branch-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-utils.d.ts","sourceRoot":"","sources":["../src/branch-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAkB,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,OAAO,UAAU,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC1F;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAI/F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE,mBAAmB,EACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBnB"}