@aiao/rxdb-adapter-electron 0.0.26 → 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.
- package/README.md +122 -21
- package/dist/RxDBAdapterElectron.d.ts +27 -1
- package/dist/RxDBAdapterElectron.d.ts.map +1 -1
- package/dist/electron-sqlite-host.d.ts.map +1 -1
- package/dist/host.d.ts +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +46 -40
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -6
- package/dist/node-sqlite-engine.d.ts +10 -0
- package/dist/node-sqlite-engine.d.ts.map +1 -1
- package/dist/pglite/RxDBAdapterElectronPGlite.d.ts +53 -1
- package/dist/pglite/RxDBAdapterElectronPGlite.d.ts.map +1 -1
- package/dist/pglite/desktop-pglite-client.d.ts +27 -1
- package/dist/pglite/desktop-pglite-client.d.ts.map +1 -1
- package/dist/pglite/desktop-pglite-results.d.ts +14 -0
- package/dist/pglite/desktop-pglite-results.d.ts.map +1 -0
- package/dist/pglite/electron-pglite-backup-error.d.ts +32 -0
- package/dist/pglite/electron-pglite-backup-error.d.ts.map +1 -0
- package/dist/pglite/pglite-adapter.interface.d.ts +12 -0
- package/dist/pglite/pglite-adapter.interface.d.ts.map +1 -1
- package/dist/pglite/restore-electron-pglite-database.d.ts +68 -0
- package/dist/pglite/restore-electron-pglite-database.d.ts.map +1 -0
- package/dist/pglite-host/electron-pglite-host.d.ts +47 -32
- package/dist/pglite-host/electron-pglite-host.d.ts.map +1 -1
- package/dist/pglite-host/pglite-host-data-dir.d.ts +75 -0
- package/dist/pglite-host/pglite-host-data-dir.d.ts.map +1 -0
- package/dist/pglite-host/pglite-host-lock.d.ts +48 -0
- package/dist/pglite-host/pglite-host-lock.d.ts.map +1 -0
- package/dist/pglite-host/pglite-host-restore.d.ts +38 -0
- package/dist/pglite-host/pglite-host-restore.d.ts.map +1 -0
- package/dist/pglite-host/pglite-host-runtime.d.ts +90 -0
- package/dist/pglite-host/pglite-host-runtime.d.ts.map +1 -0
- package/dist/pglite-host.d.ts +2 -2
- package/dist/pglite-host.d.ts.map +1 -1
- package/dist/pglite-host.js +643 -120
- package/dist/pglite.d.ts +2 -0
- package/dist/pglite.d.ts.map +1 -1
- package/dist/pglite.js +341 -65
- package/package.json +13 -10
- package/src/RxDBAdapterElectron.ts +40 -1
- package/src/electron-sqlite-host.ts +3 -0
- package/src/host.ts +1 -0
- package/src/index.ts +1 -0
- package/src/node-sqlite-engine.ts +20 -1
- package/src/pglite/RxDBAdapterElectronPGlite.ts +80 -5
- package/src/pglite/desktop-pglite-client.ts +111 -17
- package/src/pglite/desktop-pglite-results.ts +24 -0
- package/src/pglite/electron-pglite-backup-error.ts +128 -0
- package/src/pglite/pglite-adapter.interface.ts +14 -0
- package/src/pglite/restore-electron-pglite-database.ts +429 -0
- package/src/pglite-host/electron-pglite-host.ts +409 -160
- package/src/pglite-host/pglite-host-data-dir.ts +224 -0
- package/src/pglite-host/pglite-host-lock.ts +154 -0
- package/src/pglite-host/pglite-host-restore.ts +460 -0
- package/src/pglite-host/pglite-host-runtime.ts +166 -0
- package/src/pglite-host.ts +7 -0
- package/src/pglite.ts +9 -0
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ if (isDesktopPgliteRequestKind(kind)) return pglite.handle(target, request);
|
|
|
191
191
|
return sqlite.handle(target, request);
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
-
SQLite 那支是**兜底分支**(「不是 handshake/open/version/close 的」一律当 `execute`),所以漏判一族的后果不是报错,而是一条 PGlite 请求被顺着 SQL 路径跑一遍。两层因此都要有:分派判据用协议包导出的 `isDesktopPgliteRequestKind`(`/pglite-host`)与 `isDesktopHostFileRequestKind`(`/host`),不要在接线处自己列 `kind` 名单——那份名单必然随协议版本漂移;闭集守卫则是应用侧自己的几行(协议未导出 SQLite 族谓词),负责把三族之外的 `kind` 挡在兜底分支之前。
|
|
194
|
+
SQLite 那支是**兜底分支**(「不是 handshake/open/version/close/mute 的」一律当 `execute`),所以漏判一族的后果不是报错,而是一条 PGlite 请求被顺着 SQL 路径跑一遍。两层因此都要有:分派判据用协议包导出的 `isDesktopPgliteRequestKind`(`/pglite-host`)与 `isDesktopHostFileRequestKind`(`/host`),不要在接线处自己列 `kind` 名单——那份名单必然随协议版本漂移;闭集守卫则是应用侧自己的几行(协议未导出 SQLite 族谓词),负责把三族之外的 `kind` 挡在兜底分支之前。
|
|
195
195
|
|
|
196
196
|
> 把 PGlite 接进来不会让只用 SQLite 的会话变重:示例里的 PGlite 通道工厂是**惰性调用**的,没有 `pg.*` 请求就不会启动那条 worker 线程、也不会加载 PostgreSQL WASM。
|
|
197
197
|
|
|
@@ -217,29 +217,36 @@ SQLite 那支是**兜底分支**(「不是 handshake/open/version/close 的」
|
|
|
217
217
|
|
|
218
218
|
程序分支请读 `error.code`,不要匹配消息文本(消息以 `[code] ` 前缀开头,仅便于日志检索)。原始原因通过 `cause` 原样透传。
|
|
219
219
|
|
|
220
|
-
| code | 含义
|
|
221
|
-
| ---------------------------- |
|
|
222
|
-
| `unsupported_runtime_engine` | 存储 `engine` 不在能力矩阵内(例如把 PGlite data directory 递给 SQLite 协议)
|
|
223
|
-
| `invalid_database_name` | 逻辑库名非法,或试图越出应用作用域
|
|
224
|
-
| `host_unavailable` | renderer 拿不到 host(未注入 transport / preload 未暴露)
|
|
225
|
-
| `session_closed` | 会话已断开后继续使用
|
|
226
|
-
| `protocol_violation` | 请求或响应不符合协议形状
|
|
227
|
-
| `open_failed` | 打开数据库失败,`cause` 保留原始原因
|
|
228
|
-
| `permission_denied` | 路径无权限,或语句被 SQLite 授权器拒绝(`ATTACH` / `VACUUM INTO` 等)
|
|
229
|
-
| `database_corrupted` | 目标文件不是可用的 SQLite 数据库
|
|
230
|
-
| `statement_failed` | SQL 本身执行失败(语法、约束等)
|
|
231
|
-
| `host_internal_error` | host 自身出错,属于缺陷而非调用方问题
|
|
232
|
-
| `database_busy` | 另一个连接(通常是另一个窗口)正持有冲突的锁,重试即可,数据无损
|
|
233
|
-
| `file_not_found` | 目标文件或目录不存在;renderer 侧据此还原成 `NotFoundError`
|
|
234
|
-
| `invalid_file_path` | 路径逃出存储根,或指向的类型与操作不符
|
|
235
|
-
| `disk_full` | 磁盘空间或配额耗尽(ENOSPC / EDQUOT)
|
|
236
|
-
| `write_aborted` | 写入令牌已失效(会话关闭、已提交或已丢弃),目标保持写入前的内容
|
|
237
|
-
| `transaction_not_found` | 事务 ID 未知、已结束,或不属于本会话;该事务一条语句都没执行
|
|
238
|
-
| `transaction_unavailable` | 等不到 PGlite 连接(另一个事务仍持有),或开启该事务的 `begin` 已超时
|
|
220
|
+
| code | 含义 |
|
|
221
|
+
| ---------------------------- | ---------------------------------------------------------------------------------------- |
|
|
222
|
+
| `unsupported_runtime_engine` | 存储 `engine` 不在能力矩阵内(例如把 PGlite data directory 递给 SQLite 协议) |
|
|
223
|
+
| `invalid_database_name` | 逻辑库名非法,或试图越出应用作用域 |
|
|
224
|
+
| `host_unavailable` | renderer 拿不到 host(未注入 transport / preload 未暴露) |
|
|
225
|
+
| `session_closed` | 会话已断开后继续使用 |
|
|
226
|
+
| `protocol_violation` | 请求或响应不符合协议形状 |
|
|
227
|
+
| `open_failed` | 打开数据库失败,`cause` 保留原始原因 |
|
|
228
|
+
| `permission_denied` | 路径无权限,或语句被 SQLite 授权器拒绝(`ATTACH` / `VACUUM INTO` 等) |
|
|
229
|
+
| `database_corrupted` | 目标文件不是可用的 SQLite 数据库 |
|
|
230
|
+
| `statement_failed` | SQL 本身执行失败(语法、约束等) |
|
|
231
|
+
| `host_internal_error` | host 自身出错,属于缺陷而非调用方问题 |
|
|
232
|
+
| `database_busy` | 另一个连接(通常是另一个窗口)正持有冲突的锁,重试即可,数据无损 |
|
|
233
|
+
| `file_not_found` | 目标文件或目录不存在;renderer 侧据此还原成 `NotFoundError` |
|
|
234
|
+
| `invalid_file_path` | 路径逃出存储根,或指向的类型与操作不符 |
|
|
235
|
+
| `disk_full` | 磁盘空间或配额耗尽(ENOSPC / EDQUOT) |
|
|
236
|
+
| `write_aborted` | 写入令牌已失效(会话关闭、已提交或已丢弃),目标保持写入前的内容 |
|
|
237
|
+
| `transaction_not_found` | 事务 ID 未知、已结束,或不属于本会话;该事务一条语句都没执行 |
|
|
238
|
+
| `transaction_unavailable` | 等不到 PGlite 连接(另一个事务仍持有),或开启该事务的 `begin` 已超时 |
|
|
239
|
+
| `restore_in_progress` | 目标正被同一 host 上的一次恢复独占,普通连接被拒绝;新的恢复与清理照常报 `database_busy` |
|
|
240
|
+
| `restore_incomplete` | 目标留有未完成恢复的标记,须先清理再连接或重新恢复 |
|
|
241
|
+
| `target_not_empty` | 恢复目标已经含有数据库内容,恢复拒绝覆盖 |
|
|
242
|
+
| `cleanup_pending` | 恢复失败后的清理本身也失败,目标保持可判别的未完成状态 |
|
|
243
|
+
| `unsupported_operation` | host 没有启用该操作,例如创建 PGlite host 时没有传 `backup` |
|
|
239
244
|
|
|
240
245
|
`file_not_found` / `invalid_file_path` / `disk_full` / `write_aborted` 来自文件宿主(`createElectronFileHost`,供 `@aiao/rxdb-plugin-storage/desktop` 使用),SQLite 侧用不到。
|
|
241
246
|
|
|
242
|
-
|
|
247
|
+
`transaction_not_found` / `transaction_unavailable` 只出现在 PGlite 路径上:PGlite 的事务靠显式事务 ID 串联多次 IPC,SQLite 侧没有这个概念。`transaction_unavailable` 的超时预算由 `DESKTOP_PGLITE_DEFAULT_BEGIN_TIMEOUT_MS` 给出,上限是 `DESKTOP_PGLITE_MAX_BEGIN_TIMEOUT_MS`。
|
|
248
|
+
|
|
249
|
+
最后五个码来自 PGlite host 的备份与恢复(US-217),同样只出现在 PGlite 路径上;其中 `restore_in_progress` 也会落到恢复期间同一 host 上的连接尝试。备份、恢复与清理本身不会把它们原样抛给调用方,而是归一成 `RxDBBackupError`,对照见「备份与恢复 → PGlite」。
|
|
243
250
|
|
|
244
251
|
错误码是**契约的一部分**:新增只能追加,不得复用或改写既有含义。
|
|
245
252
|
|
|
@@ -283,6 +290,100 @@ PGlite 的 WASM 在**调用线程上同步**跑完整条查询:实测一条 2
|
|
|
283
290
|
|
|
284
291
|
而且要搬就得**整个 host 一起搬**,不能只把 PGlite 放过去:`ElectronPgliteRuntime.transaction` 收的是一个回调,回调过不了线程边界(和它过不了 IPC 边界是同一个原因)。host 搬过去之后,线程边界上流动的就只剩 `DesktopPgliteRequest` / `DesktopPgliteResponse` 这类纯数据。示例见下。
|
|
285
292
|
|
|
293
|
+
## 备份与恢复
|
|
294
|
+
|
|
295
|
+
两族都能把整个库写成一份 `.rxdb-backup` 归档流,再恢复进一个**空的、未连接的**目标。两端都逐块流式处理,不会把整个库读进内存;兼容性在写入目标的第一个字节之前判定;失败一律抛可判别的 `RxDBBackupError`(按 `error.code` 分支,`isRxDBBackupError()` 可做类型收窄),不会报告成功。
|
|
296
|
+
|
|
297
|
+
> **外部文件不在备份范围内。** 归档只含数据库本身,结果与 manifest 的 `scope` 恒为 `{ database: 'included', externalFiles: 'excluded' }`。`@aiao/rxdb-plugin-storage/desktop` 放在文件宿主根目录里的文件须另行备份与恢复。
|
|
298
|
+
|
|
299
|
+
输入流与输出流由调用方提供(`ReadableStream<Uint8Array>` / `WritableStream<Uint8Array>`):本包不弹文件选择器,也不替 renderer 授权任意路径。写到哪里、从哪里读由宿主应用决定,例如在 preload 里暴露一条只能读写应用备份目录的通道。
|
|
300
|
+
|
|
301
|
+
| 族 | 备份 | 恢复 | 清理未完成的恢复 |
|
|
302
|
+
| ------ | ---------------------- | ------------------------------------------------------- | ------------------------------------------------ |
|
|
303
|
+
| SQLite | `adapter.backup(sink)` | `adapter.restore(source)`:adapter 已注册,实例尚未连接 | `adapter.cleanupIncompleteRestore()` |
|
|
304
|
+
| PGlite | `adapter.backup(sink)` | `restoreElectronPGliteDatabase(source, target)` | `cleanupIncompleteElectronPGliteRestore(target)` |
|
|
305
|
+
|
|
306
|
+
归档只恢复进**同一个 adapter**:`sqlite-electron` 的归档不能恢复进 `sqlite-tauri` 或浏览器里的 SQLite,`pglite-electron` 的归档也不能恢复进浏览器 PGlite,反之亦然,都报 `incompatible_archive`。
|
|
307
|
+
|
|
308
|
+
### SQLite
|
|
309
|
+
|
|
310
|
+
实现与浏览器端的四个 SQLite 适配器共用,归档格式、兼容性判定、中断与清理语义见 [`@aiao/rxdb-adapter-sqlite-core` 的「备份与恢复」](https://github.com/aiao-io/rxdb/tree/main/packages/rxdb-adapter-sqlite-core#备份与恢复)。桌面端多出来的只有三点:
|
|
311
|
+
|
|
312
|
+
- **WAL**:库文件以 WAL 模式运行。备份是一个读事务里的逻辑转储,快照边界前已提交、还没 checkpoint 回主文件的数据也在归档里,不会出现「只复制主文件、漏掉 WAL」。
|
|
313
|
+
- **独占**:同一库文件可能被别的窗口、别的进程打开,Web Lock 挡不住它们。恢复与清理在检查目标是否为空之前,就让自己那条连接拿到 SQLite 的文件级独占锁,并一直持有到恢复完成或失败清理结束。库文件此刻开在任何别的连接上都报 `target_busy`(`details.field` 为 `storage`);恢复期间别的进程也打不开它——Web Lock 管不到的连接在初始化时立刻报 `database_busy`。
|
|
314
|
+
- **FTS5**:host 以 defensive 模式运行 SQLite,改不了虚表的影子表。含 FTS5 等虚表的库备份与恢复都报 `unsupported_combination`,不会产出一份自己恢复不了的归档。
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// 备份:sink 由宿主应用提供
|
|
318
|
+
const adapter = await rxdb.getAdapter(ELECTRON_ADAPTER_NAME);
|
|
319
|
+
const result = await adapter.backup(sink);
|
|
320
|
+
|
|
321
|
+
// 恢复:target 已注册 adapter,但尚未 connect
|
|
322
|
+
const restored = await target.getAdapter(ELECTRON_ADAPTER_NAME);
|
|
323
|
+
await restored.restore(source);
|
|
324
|
+
await target.connect(ELECTRON_ADAPTER_NAME);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
> 线协议 v2 为备份与恢复新增了请求 kind:SQLite 族的 `mute`(恢复写入期间静音变更事件),PGlite 族的 `pg.engine`、`pg.backup.*` 与 `pg.restore.*`(以协议包的 `isDesktopPgliteRequestKind` 为准)。宿主应用若像「共用一条 IPC 通道时的分派」那样自己维护了请求 kind 的闭集守卫(示例应用在主进程与 preload 里各有一份),每一份都要加上,否则请求被守卫以 `protocol_violation` 挡下:SQLite 恢复在写入目标之前报 `io_error`,`cause` 就是那条 `protocol_violation`;PGlite 的备份与恢复报 `unsupported_combination`(`details.field` 为 `protocolVersion`)。
|
|
328
|
+
|
|
329
|
+
### PGlite
|
|
330
|
+
|
|
331
|
+
特权侧要显式开启:`createElectronPgliteHost` 不传 `backup` 时 host 只提供连接,备份与恢复请求一律报 `unsupported_operation`,renderer 侧表现为 `unsupported_combination`。
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { createElectronPgliteHost } from '@aiao/rxdb-adapter-electron/pglite-host';
|
|
335
|
+
import { PGlite } from '@electric-sql/pglite';
|
|
336
|
+
import { join } from 'node:path';
|
|
337
|
+
|
|
338
|
+
const dataDirectoryOf = (name: string): string => join(root, name);
|
|
339
|
+
|
|
340
|
+
const host = createElectronPgliteHost({
|
|
341
|
+
createRuntime: async name => new PGlite(dataDirectoryOf(name)),
|
|
342
|
+
postNotify: message => port.postMessage({ op: 'notify', message }),
|
|
343
|
+
backup: {
|
|
344
|
+
// 必须就是 createRuntime 为同一个名字打开的目录
|
|
345
|
+
resolveDataDirectory: dataDirectoryOf,
|
|
346
|
+
// 不落盘的探针,用来回答引擎版本;与 createRuntime 用同一份 PGlite、同一组扩展
|
|
347
|
+
createProbeRuntime: async () => new PGlite(),
|
|
348
|
+
// 影响数据兼容性的扩展,没有就传空数组
|
|
349
|
+
extensions: []
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
renderer 侧的备份在 adapter 上;恢复目标还没连接,没有 adapter 可调,所以恢复与清理是 `/pglite` 入口导出的两个函数:
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
import {
|
|
358
|
+
ELECTRON_PGLITE_ADAPTER_NAME,
|
|
359
|
+
RxDBAdapterElectronPGlite,
|
|
360
|
+
restoreElectronPGliteDatabase
|
|
361
|
+
} from '@aiao/rxdb-adapter-electron/pglite';
|
|
362
|
+
|
|
363
|
+
// 备份
|
|
364
|
+
const result = await adapter.backup(sink);
|
|
365
|
+
|
|
366
|
+
// 恢复:options 必须与之后连接时交给 adapter 的完全相同,数据目录名、传输层都按它判定
|
|
367
|
+
const restoreTarget = { rxdb: target, options: { dataDirectoryName: 'restored-pgdata' } };
|
|
368
|
+
await restoreElectronPGliteDatabase(source, restoreTarget);
|
|
369
|
+
target.adapter(ELECTRON_PGLITE_ADAPTER_NAME, async db => new RxDBAdapterElectronPGlite(db, restoreTarget.options));
|
|
370
|
+
await target.connect(ELECTRON_PGLITE_ADAPTER_NAME);
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
要点:
|
|
374
|
+
|
|
375
|
+
- **一致性**:快照由 host 取,它在本会话那条唯一的连接上挂起一个空事务并 `CHECKPOINT`,写出期间别的窗口改不动文件,归档对应一个已提交事务边界。等连接空闲的上限是 adapter 的 `beginTimeout`,另一个窗口长期占着事务时报 `lock_timeout`。
|
|
376
|
+
- **内存**:数据块不超过 64 KiB,一块对应一条 IPC 消息,按 renderer 的读取节奏逐块拉取,host 不预读。输出流有背压时整条链路跟着停,内存占用与库大小无关。
|
|
377
|
+
- **独占**:`backup` 开启后,每个数据目录旁边都有一把跨进程的目录锁,另一个进程里的 host 也不例外。同一目录上并发的恢复只有一个能赢(`target_busy`);恢复期间,同一 host 上的连接尝试报 `restore_in_progress`,另一个进程里的 host 报 `database_busy`。
|
|
378
|
+
- **先校验后写入**:adapter、PostgreSQL 大版本、扩展(目标 host 必须全部提供)、系统表与变更编码版本、实体结构指纹、加密认证域全部在写入之前判定(`incompatible_archive` / `auth_domain_mismatch`)。host 与 renderer 的线协议版本不一致时,在触碰目标之前报 `unsupported_combination`(`details.field` 为 `protocolVersion`)。
|
|
379
|
+
- **中断**:host 在写入第一个文件之前持久化一个未完成标记,完整性核对、启动校验与逐一 fsync 都通过后才删除它。窗口或进程在恢复中途退出后,连接与再次恢复都报 `restore_incomplete`,用 `cleanupIncompleteElectronPGliteRestore(target)` 清理后即可重新恢复;清理失败时报 `cleanup_pending`。清理只删带标记的目录,一个正常的库永远不会被它删掉。
|
|
380
|
+
- **加密库**:加解密在 renderer 里做,host 只经手密文。归档里只有密文与 keyring 元数据,不含口令与密钥;恢复后的库保持锁定,用原口令 `unlock()`。
|
|
381
|
+
- **错误**:host 的桌面错误码不会漏到调用方手里,一律归一成 `RxDBBackupError`,原始错误在 `cause`:`database_busy` → `target_busy`;`restore_in_progress` / `restore_incomplete` / `target_not_empty` / `cleanup_pending` → 同名码(这四个连同 `target_busy` 说的都是目录此刻的状态,`details.field` 为 `dataDirectoryName`);`protocol_violation` → `unsupported_combination`(`details.field` 为 `protocolVersion`);`unsupported_operation` / `unsupported_runtime_engine` / `invalid_database_name` → `unsupported_combination`;`disk_full` → `storage_full`;`transaction_unavailable` → `lock_timeout`;`session_closed` → `invalid_state`;`database_corrupted` 在恢复时是 `corrupt_archive`,在备份时是 `io_error`;其余一律 `io_error`。
|
|
382
|
+
|
|
383
|
+
### 输出流报「磁盘满」
|
|
384
|
+
|
|
385
|
+
`ipcRenderer.invoke` 在 reject 时把错误压平成一条消息,`code: 'ENOSPC'` 这类字段过不了 IPC。经 IPC 写文件的输出流遇到磁盘满或配额耗尽时,请在 renderer 侧以 `new DOMException(message, 'QuotaExceededError')` reject,备份才会报 `storage_full` 而不是笼统的 `io_error`。
|
|
386
|
+
|
|
286
387
|
## 完整示例
|
|
287
388
|
|
|
288
389
|
参考 [dev-rxdb-electron](https://github.com/aiao-io/rxdb/tree/main/apps/dev-rxdb-electron):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RxDB } from '@aiao/rxdb';
|
|
2
|
-
import { RxDBAdapterSqliteBase } from '@aiao/rxdb-adapter-sqlite-core';
|
|
2
|
+
import { RxDBAdapterSqliteBase, SqliteBackupStorage, SqliteClientLike } from '@aiao/rxdb-adapter-sqlite-core';
|
|
3
3
|
import { DesktopSqliteClient, DesktopOptions } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
4
4
|
import { ADAPTER_NAME } from './electron-adapter.interface.js';
|
|
5
5
|
/**
|
|
@@ -26,6 +26,32 @@ export declare class RxDBAdapterElectron extends RxDBAdapterSqliteBase {
|
|
|
26
26
|
*/
|
|
27
27
|
constructor(rxdb: RxDB, options?: DesktopOptions);
|
|
28
28
|
protected createClient(): Promise<DesktopSqliteClient>;
|
|
29
|
+
/**
|
|
30
|
+
* 桌面库是应用数据目录里的一个库文件,备份与恢复都按它支持。
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* `storageKey` 用库文件名而不是 `dbName`:配了同一个 `databaseName` 的两个实例打开的是同一个文件,
|
|
34
|
+
* 必须争同一把锁;同名实例恢复到另一个 `databaseName`(新的数据位置)则与原库互不相干。
|
|
35
|
+
*
|
|
36
|
+
* @returns 持久化存储后端,`label` 为 `file`
|
|
37
|
+
*/
|
|
38
|
+
protected backupStorage(): SqliteBackupStorage;
|
|
39
|
+
/**
|
|
40
|
+
* Electron host 以 defensive 模式运行 SQLite,改不了影子表。
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* host 在特权主进程里执行 renderer 透传的 SQL;defensive 挡住直接改写影子表、`writable_schema` 这类
|
|
44
|
+
* 能把库文件改坏的操作,不能为了恢复而关掉。含 FTS5 等虚表的库因此不在 Electron 的备份矩阵里。
|
|
45
|
+
*
|
|
46
|
+
* @returns 恒为 `false`
|
|
47
|
+
*/
|
|
48
|
+
protected shadowTablesWritable(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* 别的窗口、别的进程可能开着同一个库文件,Web Lock 挡不住它们:恢复与清理前先让这条连接独占库文件。
|
|
51
|
+
*
|
|
52
|
+
* @returns 独占库文件的连接
|
|
53
|
+
*/
|
|
54
|
+
protected createRestoreTargetClient(): Promise<SqliteClientLike>;
|
|
29
55
|
}
|
|
30
56
|
declare module '@aiao/rxdb' {
|
|
31
57
|
interface RxDBAdapters {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RxDBAdapterElectron.d.ts","sourceRoot":"","sources":["../src/RxDBAdapterElectron.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"RxDBAdapterElectron.d.ts","sourceRoot":"","sources":["../src/RxDBAdapterElectron.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACxH,OAAO,EAEL,mBAAmB,EAInB,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,qBAAa,mBAAoB,SAAQ,qBAAqB;;IAkB1D,QAAQ,CAAC,OAAO,EAAE,cAAc;IAdlC,SAAkB,IAAI,EAAE,MAAM,CAAgB;IAE9C,oCAAoC;IACpC,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;;OAIG;gBAED,IAAI,EAAE,IAAI,EACD,OAAO,GAAE,cAAmB;cASd,YAAY,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAQrE;;;;;;;;OAQG;cACgB,aAAa,IAAI,mBAAmB;IAIvD;;;;;;;;OAQG;cACgB,oBAAoB,IAAI,OAAO;IAIlD;;;;OAIG;cACgB,yBAAyB,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAG1E;AAED,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,YAAY;QACpB,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;KACrC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-sqlite-host.d.ts","sourceRoot":"","sources":["../src/electron-sqlite-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAIL,KAAK,6BAA6B,EAElC,KAAK,mBAAmB,EACzB,MAAM,6CAA6C,CAAC;AAmDrD,4CAA4C;AAC5C,MAAM,WAAW,yBAAyB;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,mBAAmB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/D,mDAAmD;IACnD,QAAQ,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,IAAI,CAAC;IACtE;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,gCAAgC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,yBAAyB;AACzB,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvD,0BAA0B;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,yBAAyB;IACzB,QAAQ,IAAI,IAAI,CAAC;CAClB;AA4BD;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"electron-sqlite-host.d.ts","sourceRoot":"","sources":["../src/electron-sqlite-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAIL,KAAK,6BAA6B,EAElC,KAAK,mBAAmB,EACzB,MAAM,6CAA6C,CAAC;AAmDrD,4CAA4C;AAC5C,MAAM,WAAW,yBAAyB;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,mBAAmB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/D,mDAAmD;IACnD,QAAQ,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,IAAI,CAAC;IACtE;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,gCAAgC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,yBAAyB;AACzB,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvD,0BAA0B;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,yBAAyB;IACzB,QAAQ,IAAI,IAAI,CAAC;CAClB;AA4BD;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CA6I/F"}
|
package/dist/host.d.ts
CHANGED
|
@@ -15,5 +15,5 @@ export { createElectronFileHost, type ElectronFileHost, type ElectronFileHostOpt
|
|
|
15
15
|
export { NodeSqliteEngine, type NodeSqliteEngineOptions } from './node-sqlite-engine.js';
|
|
16
16
|
export { RxDBAdapterDesktopError, type RxDBAdapterDesktopErrorCode } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
17
17
|
export { assertDesktopSqliteStorage, assertValidDesktopDatabaseName, isDesktopPgliteDirectoryStorage, isDesktopSqliteFileStorage, type DesktopPgliteDirectoryStorage, type DesktopSqliteFileStorage, type DesktopStorage } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
18
|
-
export { DESKTOP_HOST_MAX_BINDINGS, DESKTOP_HOST_MAX_BLOB_BYTES, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, DESKTOP_HOST_MAX_SQL_LENGTH, DESKTOP_HOST_PROTOCOL_VERSION, isDesktopHostFileRequestKind, parseDesktopHostFileRequest, parseDesktopHostRequest, type DesktopHostChangeEventMessage, type DesktopHostCloseRequest, type DesktopHostExecuteRequest, type DesktopHostFileEntry, type DesktopHostFileReadResult, type DesktopHostFileRequest, type DesktopHostFileResponse, type DesktopHostFileStat, type DesktopHostHandshakeRequest, type DesktopHostHandshakeResult, type DesktopHostOpenRequest, type DesktopHostOpenResult, type DesktopHostRequest, type DesktopHostResponse, type DesktopHostVersionRequest } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
18
|
+
export { DESKTOP_HOST_MAX_BINDINGS, DESKTOP_HOST_MAX_BLOB_BYTES, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, DESKTOP_HOST_MAX_SQL_LENGTH, DESKTOP_HOST_PROTOCOL_VERSION, isDesktopHostFileRequestKind, parseDesktopHostFileRequest, parseDesktopHostRequest, type DesktopHostChangeEventMessage, type DesktopHostCloseRequest, type DesktopHostExecuteRequest, type DesktopHostFileEntry, type DesktopHostFileReadResult, type DesktopHostFileRequest, type DesktopHostFileResponse, type DesktopHostFileStat, type DesktopHostHandshakeRequest, type DesktopHostHandshakeResult, type DesktopHostMuteRequest, type DesktopHostOpenRequest, type DesktopHostOpenResult, type DesktopHostRequest, type DesktopHostResponse, type DesktopHostVersionRequest } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
19
19
|
//# sourceMappingURL=host.d.ts.map
|
package/dist/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC/B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEtH,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAKzF,OAAO,EAAE,uBAAuB,EAAE,KAAK,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAExH,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,iCAAiC,EACjC,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC/B,MAAM,6CAA6C,CAAC"}
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC/B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEtH,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAKzF,OAAO,EAAE,uBAAuB,EAAE,KAAK,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAExH,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,iCAAiC,EACjC,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC/B,MAAM,6CAA6C,CAAC"}
|
package/dist/host.js
CHANGED
|
@@ -208,30 +208,31 @@ var H = "rxdb_desktop_notify", _e = "rxdb_desktop_notify", ve = [
|
|
|
208
208
|
#c;
|
|
209
209
|
#l;
|
|
210
210
|
#u = !1;
|
|
211
|
+
#d = !1;
|
|
211
212
|
constructor(t, n) {
|
|
212
213
|
this.#e = t, this.#t = n.dbName, this.#n = n.onChange, this.#r = s("batchTimeout", n.batchTimeout, e, { allowZero: !0 });
|
|
213
214
|
}
|
|
214
215
|
static open(e) {
|
|
215
216
|
let n;
|
|
216
217
|
try {
|
|
217
|
-
n = new ie(e.filePath);
|
|
218
|
+
n = new ie(e.filePath, { defensive: !0 });
|
|
218
219
|
} catch (t) {
|
|
219
220
|
throw new g(U(t, "open_failed"), `failed to open desktop database ${e.dbName}: ${W(t)}`, { cause: t });
|
|
220
221
|
}
|
|
221
222
|
try {
|
|
222
223
|
let i = new r(n, e);
|
|
223
|
-
return i.#
|
|
224
|
+
return i.#f(e.cacheSizeKb ?? t), i;
|
|
224
225
|
} catch (t) {
|
|
225
226
|
throw n.close(), new g(U(t, "open_failed"), `failed to initialize desktop database ${e.dbName}: ${W(t)}`, { cause: t });
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
execute(e, t = []) {
|
|
229
|
-
this.#
|
|
230
|
+
this.#p();
|
|
230
231
|
let n = performance.now(), r = V(e);
|
|
231
232
|
if (r.length > 1 && t.length > 0) throw new g("protocol_violation", `multi statement scripts cannot carry bindings, got ${t.length} for SQL "${e}"`);
|
|
232
|
-
this.#
|
|
233
|
-
let { results: i, rowsAffected: a } = this.#
|
|
234
|
-
return this.#
|
|
233
|
+
this.#E();
|
|
234
|
+
let { results: i, rowsAffected: a } = this.#h(r, t);
|
|
235
|
+
return this.#E(), {
|
|
235
236
|
sql: e,
|
|
236
237
|
rowsAffected: a,
|
|
237
238
|
elapsed: performance.now() - n,
|
|
@@ -239,32 +240,35 @@ var H = "rxdb_desktop_notify", _e = "rxdb_desktop_notify", ve = [
|
|
|
239
240
|
};
|
|
240
241
|
}
|
|
241
242
|
version() {
|
|
242
|
-
this.#
|
|
243
|
-
let [e] = this.#
|
|
243
|
+
this.#p();
|
|
244
|
+
let [e] = this.#m("SELECT sqlite_version()", []);
|
|
244
245
|
return String(e?.rows[0]?.[0]);
|
|
245
246
|
}
|
|
247
|
+
setChangeEventsMuted(e) {
|
|
248
|
+
this.#p(), this.#u = e;
|
|
249
|
+
}
|
|
246
250
|
close() {
|
|
247
|
-
if (!this.#
|
|
248
|
-
this.#
|
|
251
|
+
if (!this.#d) {
|
|
252
|
+
this.#d = !0, this.#C();
|
|
249
253
|
try {
|
|
250
|
-
this.#
|
|
254
|
+
this.#k(), this.#e.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
251
255
|
} finally {
|
|
252
256
|
this.#c = void 0, this.#l = void 0, this.#e.close();
|
|
253
257
|
}
|
|
254
258
|
}
|
|
255
259
|
}
|
|
256
|
-
#
|
|
260
|
+
#f(e) {
|
|
257
261
|
this.#e.setAuthorizer((e, t) => Se(e, t) ? w.SQLITE_DENY : w.SQLITE_OK), this.#e.function(H, {
|
|
258
262
|
deterministic: !1,
|
|
259
263
|
directOnly: !1,
|
|
260
264
|
useBigIntArguments: !0,
|
|
261
265
|
varargs: !1
|
|
262
|
-
}, (e, t, n) => (this.#
|
|
266
|
+
}, (e, t, n) => (this.#x(...Te(e, t, n)), null)), this.#e.exec(a(e, !0)), this.#E();
|
|
263
267
|
}
|
|
264
|
-
#
|
|
265
|
-
if (this.#
|
|
268
|
+
#p() {
|
|
269
|
+
if (this.#d) throw new g("session_closed", `desktop database ${this.#t} is already closed`);
|
|
266
270
|
}
|
|
267
|
-
#
|
|
271
|
+
#m(e, t) {
|
|
268
272
|
try {
|
|
269
273
|
let n = this.#e.prepare(e);
|
|
270
274
|
n.setReturnArrays(!0), n.setReadBigInts(!0);
|
|
@@ -274,54 +278,55 @@ var H = "rxdb_desktop_notify", _e = "rxdb_desktop_notify", ve = [
|
|
|
274
278
|
rows: r.map(ke)
|
|
275
279
|
}] : [];
|
|
276
280
|
} catch (t) {
|
|
277
|
-
throw this.#
|
|
281
|
+
throw this.#_(e, t);
|
|
278
282
|
}
|
|
279
283
|
}
|
|
280
|
-
#
|
|
284
|
+
#h(e, t) {
|
|
281
285
|
let n = [], r = 0;
|
|
282
286
|
for (let i of e) {
|
|
283
|
-
let e = this.#
|
|
284
|
-
r += this.#
|
|
287
|
+
let e = this.#y(), a = this.#m(i, t);
|
|
288
|
+
r += this.#g(i, e), n.length === 0 && n.push(...a);
|
|
285
289
|
}
|
|
286
290
|
return {
|
|
287
291
|
results: n,
|
|
288
292
|
rowsAffected: r
|
|
289
293
|
};
|
|
290
294
|
}
|
|
291
|
-
#h(e, t) {
|
|
292
|
-
return o(e) || this.#v() === t ? 0 : this.#_();
|
|
293
|
-
}
|
|
294
295
|
#g(e, t) {
|
|
295
|
-
return
|
|
296
|
+
return o(e) || this.#y() === t ? 0 : this.#v();
|
|
296
297
|
}
|
|
297
|
-
#_() {
|
|
298
|
-
return
|
|
298
|
+
#_(e, t) {
|
|
299
|
+
return new g(U(t, "statement_failed"), `desktop database ${this.#t} failed for SQL "${e}": ${W(t)}`, { cause: t });
|
|
299
300
|
}
|
|
300
301
|
#v() {
|
|
301
|
-
return this.#
|
|
302
|
+
return this.#c ??= this.#b("SELECT changes()"), G(this.#c);
|
|
303
|
+
}
|
|
304
|
+
#y() {
|
|
305
|
+
return this.#l ??= this.#b("SELECT total_changes()"), G(this.#l);
|
|
302
306
|
}
|
|
303
|
-
#
|
|
307
|
+
#b(e) {
|
|
304
308
|
let t = this.#e.prepare(e);
|
|
305
309
|
return t.setReturnArrays(!0), t;
|
|
306
310
|
}
|
|
307
|
-
#
|
|
311
|
+
#x(e, t, n) {
|
|
312
|
+
if (this.#u) return;
|
|
308
313
|
let r = `${e} ${t}`, i = this.#a.get(r);
|
|
309
314
|
i ? i.rowIds.push(n) : this.#a.set(r, {
|
|
310
315
|
type: e,
|
|
311
316
|
tableName: t,
|
|
312
317
|
rowIds: [n]
|
|
313
|
-
}), this.#
|
|
314
|
-
}
|
|
315
|
-
#x() {
|
|
316
|
-
this.#o && clearTimeout(this.#o), this.#o = q(() => this.#S(), this.#r), this.#s ??= q(() => this.#S(), n);
|
|
318
|
+
}), this.#S();
|
|
317
319
|
}
|
|
318
320
|
#S() {
|
|
319
|
-
this.#C(), this.#
|
|
321
|
+
this.#o && clearTimeout(this.#o), this.#o = q(() => this.#C(), this.#r), this.#s ??= q(() => this.#C(), n);
|
|
320
322
|
}
|
|
321
323
|
#C() {
|
|
322
|
-
this.#
|
|
324
|
+
this.#w(), this.#T();
|
|
323
325
|
}
|
|
324
326
|
#w() {
|
|
327
|
+
this.#o && clearTimeout(this.#o), this.#s && clearTimeout(this.#s), this.#o = void 0, this.#s = void 0;
|
|
328
|
+
}
|
|
329
|
+
#T() {
|
|
325
330
|
if (this.#a.size === 0) return;
|
|
326
331
|
let e = [...this.#a.values()];
|
|
327
332
|
this.#a.clear();
|
|
@@ -338,24 +343,24 @@ var H = "rxdb_desktop_notify", _e = "rxdb_desktop_notify", ve = [
|
|
|
338
343
|
console.error(`[NodeSqliteEngine] change event listener failed for ${r}:`, e);
|
|
339
344
|
}
|
|
340
345
|
}
|
|
341
|
-
#
|
|
346
|
+
#E() {
|
|
342
347
|
if (this.#i.size === i.size) return;
|
|
343
348
|
let e = [...i], t = e.map(() => "?").join(", "), n = this.#e.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (${t})`);
|
|
344
349
|
n.setReturnArrays(!0);
|
|
345
350
|
let r = n.all(...e);
|
|
346
|
-
for (let [e] of r) this.#i.has(e) || (this.#
|
|
351
|
+
for (let [e] of r) this.#i.has(e) || (this.#O(e), this.#D(e));
|
|
347
352
|
}
|
|
348
|
-
#
|
|
353
|
+
#D(e) {
|
|
349
354
|
this.#e.isTransaction || this.#i.add(e);
|
|
350
355
|
}
|
|
351
|
-
#
|
|
356
|
+
#O(e) {
|
|
352
357
|
let t = K(e), n = Ae(e);
|
|
353
358
|
for (let { type: r, event: i, row: a } of ve) {
|
|
354
359
|
let o = K(`${_e}$${e}$${i}`);
|
|
355
360
|
this.#e.exec(`CREATE TEMP TRIGGER IF NOT EXISTS ${o} AFTER ${i} ON ${t} BEGIN SELECT ${H}(${r}, ${n}, ${a}.rowid); END;`);
|
|
356
361
|
}
|
|
357
362
|
}
|
|
358
|
-
#
|
|
363
|
+
#k() {
|
|
359
364
|
this.#e.isTransaction && this.#e.exec("ROLLBACK");
|
|
360
365
|
}
|
|
361
366
|
}, je = "desktop-sqlite://app-scope", Y = "BEGIN IMMEDIATE;", Me = "BEGIN EXCLUSIVE;", Ne = 5e3, Pe = 1, Fe = 100, Ie = (e) => new Promise((t) => {
|
|
@@ -438,6 +443,7 @@ function ze(e) {
|
|
|
438
443
|
kind: "version",
|
|
439
444
|
result: r(e.sessionId).version()
|
|
440
445
|
};
|
|
446
|
+
case "mute": return r(e.sessionId).setChangeEventsMuted(e.muted), { kind: "mute" };
|
|
441
447
|
case "execute": return s(e);
|
|
442
448
|
default: throw new g("protocol_violation", `unsupported request kind: ${String(e.kind)}`);
|
|
443
449
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -18,5 +18,5 @@ export { DEFAULT_DATABASE_SUFFIX as DESKTOP_DEFAULT_DATABASE_SUFFIX, type Deskto
|
|
|
18
18
|
export { RxDBAdapterDesktopError, type RxDBAdapterDesktopErrorCode } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
19
19
|
export { DESKTOP_HOST_TRANSPORT_KEY, DesktopSqliteClient, resolveDesktopHostTransport, type DesktopHostTransport, type DesktopSqliteClientOptions } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
20
20
|
export { assertDesktopSqliteStorage, assertValidDesktopDatabaseName, isDesktopPgliteDirectoryStorage, isDesktopSqliteFileStorage, type DesktopPgliteDirectoryStorage, type DesktopSqliteFileStorage, type DesktopStorage } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
21
|
-
export { DESKTOP_HOST_MAX_BINDINGS, DESKTOP_HOST_MAX_BLOB_BYTES, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, DESKTOP_HOST_MAX_SQL_LENGTH, DESKTOP_HOST_PROTOCOL_VERSION, assertDesktopHostResponse, parseDesktopHostChangeEvent, parseDesktopHostHandshakeResult, parseDesktopHostOpenResult, type DesktopHostChangeEventMessage, type DesktopHostCloseRequest, type DesktopHostExecuteRequest, type DesktopHostFileEntry, type DesktopHostFileLockMode, type DesktopHostFileReadResult, type DesktopHostFileRequest, type DesktopHostFileResponse, type DesktopHostFileStat, type DesktopHostHandshakeRequest, type DesktopHostHandshakeResult, type DesktopHostOpenRequest, type DesktopHostOpenResult, type DesktopHostRequest, type DesktopHostResponse, type DesktopHostVersionRequest } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
21
|
+
export { DESKTOP_HOST_MAX_BINDINGS, DESKTOP_HOST_MAX_BLOB_BYTES, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, DESKTOP_HOST_MAX_SQL_LENGTH, DESKTOP_HOST_PROTOCOL_VERSION, assertDesktopHostResponse, parseDesktopHostChangeEvent, parseDesktopHostHandshakeResult, parseDesktopHostOpenResult, type DesktopHostChangeEventMessage, type DesktopHostCloseRequest, type DesktopHostExecuteRequest, type DesktopHostFileEntry, type DesktopHostFileLockMode, type DesktopHostFileReadResult, type DesktopHostFileRequest, type DesktopHostFileResponse, type DesktopHostFileStat, type DesktopHostHandshakeRequest, type DesktopHostHandshakeResult, type DesktopHostMuteRequest, type DesktopHostOpenRequest, type DesktopHostOpenResult, type DesktopHostRequest, type DesktopHostResponse, type DesktopHostVersionRequest } from '@aiao/rxdb-adapter-sqlite-core/desktop-host';
|
|
22
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EACL,uBAAuB,IAAI,+BAA+B,EAC1D,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,uBAAuB,EAAE,KAAK,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAExH,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,EACnB,2BAA2B,EAC3B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAChC,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,iCAAiC,EACjC,2BAA2B,EAC3B,6BAA6B,EAC7B,yBAAyB,EACzB,2BAA2B,EAC3B,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC/B,MAAM,6CAA6C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EACL,uBAAuB,IAAI,+BAA+B,EAC1D,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,uBAAuB,EAAE,KAAK,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAExH,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,EACnB,2BAA2B,EAC3B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAChC,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,iCAAiC,EACjC,2BAA2B,EAC3B,6BAA6B,EAC7B,yBAAyB,EACzB,2BAA2B,EAC3B,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC/B,MAAM,6CAA6C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
import { RxDBAdapterSqliteBase as e } from "@aiao/rxdb-adapter-sqlite-core";
|
|
2
|
-
import { DEFAULT_DATABASE_SUFFIX as t, DEFAULT_DATABASE_SUFFIX as n, DESKTOP_HOST_MAX_BINDINGS as r, DESKTOP_HOST_MAX_BLOB_BYTES as i, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES as a, DESKTOP_HOST_MAX_SQL_LENGTH as o, DESKTOP_HOST_PROTOCOL_VERSION as s, DESKTOP_HOST_TRANSPORT_KEY as c, DesktopSqliteClient as l, DesktopSqliteClient as u, RxDBAdapterDesktopError as d, assertDesktopHostResponse as f, assertDesktopSqliteStorage as p, assertValidDesktopDatabaseName as m, assertValidDesktopDatabaseName as h,
|
|
2
|
+
import { DEFAULT_DATABASE_SUFFIX as t, DEFAULT_DATABASE_SUFFIX as n, DESKTOP_HOST_MAX_BINDINGS as r, DESKTOP_HOST_MAX_BLOB_BYTES as i, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES as a, DESKTOP_HOST_MAX_SQL_LENGTH as o, DESKTOP_HOST_PROTOCOL_VERSION as s, DESKTOP_HOST_TRANSPORT_KEY as c, DesktopSqliteClient as l, DesktopSqliteClient as u, RxDBAdapterDesktopError as d, assertDesktopHostResponse as f, assertDesktopSqliteStorage as p, assertValidDesktopDatabaseName as m, assertValidDesktopDatabaseName as h, connectDesktopRestoreTarget as g, isDesktopPgliteDirectoryStorage as _, isDesktopSqliteFileStorage as v, parseDesktopHostChangeEvent as y, parseDesktopHostHandshakeResult as b, parseDesktopHostOpenResult as x, resolveDesktopHostTransport as S, resolveDesktopHostTransport as C } from "@aiao/rxdb-adapter-sqlite-core/desktop-host";
|
|
3
3
|
//#region src/electron-adapter.interface.ts
|
|
4
|
-
var
|
|
4
|
+
var w = "sqlite-electron", T = class extends e {
|
|
5
5
|
options;
|
|
6
6
|
#e;
|
|
7
|
-
|
|
7
|
+
#t;
|
|
8
|
+
name = w;
|
|
8
9
|
get databaseName() {
|
|
9
10
|
return this.#e;
|
|
10
11
|
}
|
|
11
12
|
constructor(e, n = {}) {
|
|
12
|
-
super(e, n), this.options = n, this.#e = n.databaseName ?? `${e.config.dbName}${t}`, h(this.#e)
|
|
13
|
+
super(e, n), this.options = n, this.#e = n.databaseName ?? `${e.config.dbName}${t}`, h(this.#e), this.#t = `${this.name}:file:${this.#e}`;
|
|
13
14
|
}
|
|
14
15
|
async createClient() {
|
|
15
|
-
return u.connect(this.options.transport ??
|
|
16
|
+
return u.connect(this.options.transport ?? C(), {
|
|
16
17
|
engine: "sqlite",
|
|
17
18
|
databaseName: this.#e
|
|
18
19
|
}, { batchTimeout: this.options.batchTimeout });
|
|
19
20
|
}
|
|
21
|
+
backupStorage() {
|
|
22
|
+
return {
|
|
23
|
+
kind: "persistent",
|
|
24
|
+
label: "file",
|
|
25
|
+
storageKey: this.#t
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
shadowTablesWritable() {
|
|
29
|
+
return !1;
|
|
30
|
+
}
|
|
31
|
+
createRestoreTargetClient() {
|
|
32
|
+
return g(() => this.createClient(), this.#t);
|
|
33
|
+
}
|
|
20
34
|
};
|
|
21
35
|
//#endregion
|
|
22
|
-
export { n as DESKTOP_DEFAULT_DATABASE_SUFFIX, r as DESKTOP_HOST_MAX_BINDINGS, i as DESKTOP_HOST_MAX_BLOB_BYTES, a as DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, o as DESKTOP_HOST_MAX_SQL_LENGTH, s as DESKTOP_HOST_PROTOCOL_VERSION, c as DESKTOP_HOST_TRANSPORT_KEY, l as DesktopSqliteClient,
|
|
36
|
+
export { n as DESKTOP_DEFAULT_DATABASE_SUFFIX, r as DESKTOP_HOST_MAX_BINDINGS, i as DESKTOP_HOST_MAX_BLOB_BYTES, a as DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, o as DESKTOP_HOST_MAX_SQL_LENGTH, s as DESKTOP_HOST_PROTOCOL_VERSION, c as DESKTOP_HOST_TRANSPORT_KEY, l as DesktopSqliteClient, w as ELECTRON_ADAPTER_NAME, d as RxDBAdapterDesktopError, T as RxDBAdapterElectron, f as assertDesktopHostResponse, p as assertDesktopSqliteStorage, m as assertValidDesktopDatabaseName, _ as isDesktopPgliteDirectoryStorage, v as isDesktopSqliteFileStorage, y as parseDesktopHostChangeEvent, b as parseDesktopHostHandshakeResult, x as parseDesktopHostOpenResult, S as resolveDesktopHostTransport };
|
|
@@ -69,6 +69,16 @@ export declare class NodeSqliteEngine {
|
|
|
69
69
|
* @returns 形如 `3.50.4` 的版本串
|
|
70
70
|
*/
|
|
71
71
|
version(): string;
|
|
72
|
+
/**
|
|
73
|
+
* 暂停 / 恢复变更事件采集。
|
|
74
|
+
*
|
|
75
|
+
* @remarks
|
|
76
|
+
* 恢复整库时静音(US-217):恢复写进去的系统表行不是新变更。静音前已经攒下的批次不丢,
|
|
77
|
+
* 照常按定时器发出——它们记录的是静音前真实发生的写入。
|
|
78
|
+
*
|
|
79
|
+
* @param muted - `true` 时触发器报上来的变更直接丢弃,不入批也不派发
|
|
80
|
+
*/
|
|
81
|
+
setChangeEventsMuted(muted: boolean): void;
|
|
72
82
|
/**
|
|
73
83
|
* 断开连接并释放文件句柄。
|
|
74
84
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-sqlite-engine.d.ts","sourceRoot":"","sources":["../src/node-sqlite-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EASL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAEzB,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AAKxC,yCAAyC;AACzC,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAyJD;;;;;;GAMG;AACH,qBAAa,gBAAgB;;
|
|
1
|
+
{"version":3,"file":"node-sqlite-engine.d.ts","sourceRoot":"","sources":["../src/node-sqlite-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EASL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAEzB,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AAKxC,yCAAyC;AACzC,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAyJD;;;;;;GAMG;AACH,qBAAa,gBAAgB;;IAiB3B,OAAO;IASP;;;;;;;;;;OAUG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,uBAAuB,GAAG,gBAAgB;IA6B/D;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,SAAS,oBAAoB,EAAO,GAAG,YAAY;IAkBlF;;;;OAIG;IACH,OAAO,IAAI,MAAM;IAMjB;;;;;;;;OAQG;IACH,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAK1C;;;;;;;;;;;;OAYG;IACH,KAAK,IAAI,IAAI;CAwRd"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RxDB } from '@aiao/rxdb';
|
|
1
|
+
import { RxDB, RxDBBackupOptions, RxDBBackupResult } from '@aiao/rxdb';
|
|
2
2
|
import { RxDBAdapterPGlite, IPGliteClient } from '@aiao/rxdb-adapter-pglite';
|
|
3
3
|
import { ADAPTER_NAME, ElectronPGliteOptions } from './pglite-adapter.interface.js';
|
|
4
4
|
/**
|
|
@@ -29,12 +29,64 @@ export declare class RxDBAdapterElectronPGlite extends RxDBAdapterPGlite {
|
|
|
29
29
|
* @throws {@link RxDBAdapterDesktopError} 逻辑数据目录名越出应用作用域时抛 `invalid_database_name`
|
|
30
30
|
*/
|
|
31
31
|
constructor(rxdb: RxDB, options?: ElectronPGliteOptions);
|
|
32
|
+
/**
|
|
33
|
+
* 把 host 上的整个数据目录写成一份可恢复的归档(US-217)。
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* 快照由 host 取:它在本会话那条唯一的连接上挂起一个空事务并 `CHECKPOINT`,写出期间别的窗口、
|
|
37
|
+
* 别的会话都改不动文件,归档因此对应一个已提交事务边界,快照边界前 WAL 里已提交的数据也都
|
|
38
|
+
* 已落进数据文件。数据块按 renderer 的读取节奏逐块过 IPC,host 不预读,内存占用与库大小无关。
|
|
39
|
+
*
|
|
40
|
+
* 与浏览器端的差异:
|
|
41
|
+
* - 等连接空闲的上限是构造参数里的 `beginTimeout`,不是 `options.lockTimeoutMs`(后者只管本
|
|
42
|
+
* adapter 内部队列的排队)。另一个窗口长期占着事务时报 `lock_timeout`。
|
|
43
|
+
* - manifest 的元数据(引擎版本、系统表版本)在快照开始之前读取,这两次读取与普通语句一样排在
|
|
44
|
+
* 别的窗口的事务后面。
|
|
45
|
+
* - 主进程创建 host 时没有传 `backup` 选项(未接入 US-217)时报 `unsupported_combination`,
|
|
46
|
+
* 此时不获取输出流的 writer,也不 abort 它。
|
|
47
|
+
*
|
|
48
|
+
* 任何失败都归一成 {@link RxDBBackupError}:桌面错误码按
|
|
49
|
+
* {@link toElectronPGliteBackupError} 的映射表转换,host 不可达等其余失败报 `io_error`,
|
|
50
|
+
* 原始错误留在 `cause` 上。
|
|
51
|
+
*
|
|
52
|
+
* @param sink - 输出流;成功时被 close,快照开始后的失败会 abort 它
|
|
53
|
+
* @param options - 取消信号与排队时限
|
|
54
|
+
* @returns 结束标记(条目数、字节数、SHA-256)、manifest 与范围;输出流 close 已完成
|
|
55
|
+
* @throws RxDBBackupError `unsupported_combination` / `lock_timeout` / `aborted` / `invalid_state` /
|
|
56
|
+
* `io_error` / `storage_full`
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* // sink 由宿主应用提供:沙箱里的 renderer 没有 node:fs,常见做法是 preload 暴露一条
|
|
61
|
+
* // 只能写进应用备份目录的 WritableStream
|
|
62
|
+
* const result = await adapter.backup(sink);
|
|
63
|
+
* console.log(result.sha256);
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
backup(sink: WritableStream<Uint8Array>, options?: RxDBBackupOptions): Promise<RxDBBackupResult>;
|
|
32
67
|
/**
|
|
33
68
|
* 建出转发到主进程的客户端。
|
|
34
69
|
*
|
|
35
70
|
* @returns 尚未 `init()` 的桌面客户端;基类随后用 `rxdb.config.dbName` 初始化它
|
|
36
71
|
*/
|
|
37
72
|
protected createClient(): IPGliteClient;
|
|
73
|
+
/**
|
|
74
|
+
* 备份 manifest 记录的存储后端:host 上的一棵数据目录。
|
|
75
|
+
*
|
|
76
|
+
* @returns 固定为 `directory`
|
|
77
|
+
*/
|
|
78
|
+
protected backupStorage(): string;
|
|
79
|
+
/**
|
|
80
|
+
* 备份 manifest 记录的扩展名:host 运行时实际加载的那一组(已去重、排序)。
|
|
81
|
+
*
|
|
82
|
+
* @remarks
|
|
83
|
+
* renderer 侧的 PGlite 选项全部为空,只有 host 知道每个实例装了哪些扩展;恢复时目标 host 必须
|
|
84
|
+
* 全部提供。host 未启用备份时 `pg.engine` 报 `unsupported_operation`,于是在排队、取 writer 之前
|
|
85
|
+
* 就拒绝。
|
|
86
|
+
*
|
|
87
|
+
* @returns 扩展名
|
|
88
|
+
*/
|
|
89
|
+
protected backupExtensions(): Promise<readonly string[]>;
|
|
38
90
|
}
|
|
39
91
|
declare module '@aiao/rxdb' {
|
|
40
92
|
interface RxDBAdapters {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RxDBAdapterElectronPGlite.d.ts","sourceRoot":"","sources":["../../src/pglite/RxDBAdapterElectronPGlite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"RxDBAdapterElectronPGlite.d.ts","sourceRoot":"","sources":["../../src/pglite/RxDBAdapterElectronPGlite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAUlF,OAAO,EAAE,YAAY,EAA4B,KAAK,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEnH;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,yBAA0B,SAAQ,iBAAiB;;IAGrD,IAAI,EAAE,MAAM,CAAgB;IAErC,qCAAqC;IACrC,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED;;;;OAIG;gBACS,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,qBAA0B;IAU3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACY,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQnH;;;;OAIG;cACgB,YAAY,IAAI,aAAa;IAShD;;;;OAIG;cACgB,aAAa,IAAI,MAAM;IAI1C;;;;;;;;;OASG;cACsB,gBAAgB,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;CASxE;AAED,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,YAAY;QACpB,CAAC,YAAY,CAAC,EAAE,yBAAyB,CAAC;KAC3C;CACF"}
|