mirror of
https://github.com/Darkatse/TauriTavern.git
synced 2026-10-18 23:33:05 +00:00
140 lines
5.7 KiB
Markdown
140 lines
5.7 KiB
Markdown
# `window.__TAURITAVERN__.api.extension.store` — API 参考
|
||
|
||
TauriTavern 为第三方扩展提供的**全局**持久化能力,可选KV JSON 与 Blob 两种数据形态。
|
||
|
||
数据存储在 `data_root/_tauritavern/extension-store/` 下,可随数据根目录一起备份/迁移/清理。
|
||
|
||
## 0. 快速上手
|
||
|
||
```js
|
||
await (window.__TAURITAVERN__?.ready ?? window.__TAURITAVERN_MAIN_READY__);
|
||
const store = window.__TAURITAVERN__.api.extension.store;
|
||
```
|
||
|
||
### KV JSON 存储
|
||
|
||
```js
|
||
await store.setJson({ namespace: 'my-ext', key: 'settings', value: { enabled: true } });
|
||
const settings = await store.getJson({ namespace: 'my-ext', key: 'settings' });
|
||
|
||
const maybeSettings = await store.tryGetJson({ namespace: 'my-ext', key: 'settings' });
|
||
if (!maybeSettings.found) {
|
||
// Use in-code defaults; write only when the user changes settings.
|
||
}
|
||
```
|
||
|
||
### JSON 多表(额外 json / table)
|
||
|
||
> 不提供 `table` 时默认使用主表 `main`。
|
||
|
||
```js
|
||
await store.setJson({
|
||
namespace: 'my-ext',
|
||
table: 'index',
|
||
key: 'v1',
|
||
value: { lastId: 42 },
|
||
});
|
||
|
||
const tables = await store.listTables({ namespace: 'my-ext' });
|
||
```
|
||
|
||
### Blob 存储
|
||
|
||
```js
|
||
await store.setBlob({
|
||
namespace: 'my-ext',
|
||
key: 'icon.png',
|
||
data: myBlob, // Blob | ArrayBuffer | Uint8Array | base64 string
|
||
});
|
||
|
||
const blob = await store.getBlob({ namespace: 'my-ext', key: 'icon.png' });
|
||
```
|
||
|
||
大文件可用 `getBlobStream()` 逐块读取;提前停止时应取消流:
|
||
|
||
```js
|
||
const stream = await store.getBlobStream({ namespace: 'my-ext', key: 'archive.bin' });
|
||
await stream.pipeTo(destination); // destination 是调用方的 WritableStream
|
||
```
|
||
|
||
## 1. KV JSON 方法
|
||
|
||
所有 KV 方法都支持可选 `table` 字段:
|
||
|
||
- 省略:使用默认主表 `main`
|
||
- 指定:将数据写入对应 table
|
||
|
||
### 什么时候用 KV JSON?
|
||
|
||
建议绝大多数情况下使用KV JSON,把它当作“扩展的结构化数据存储”:
|
||
|
||
- 扩展设置(settings / feature flags)
|
||
- 索引、映射表、状态快照(index / map / progress)
|
||
- 需要 `updateJson()` 深度合并对象的场景
|
||
|
||
| 方法 | 返回值 | 说明 |
|
||
| --- | --- | --- |
|
||
| `getJson({ namespace, key, table? })` | `Promise<any>` | 读取 JSON 值 |
|
||
| `tryGetJson({ namespace, key, table? })` | `Promise<{ found: boolean; value?: any }>` | 可选读取;key 不存在时返回 `{ found: false }`,其他错误仍抛出 |
|
||
| `setJson({ namespace, key, value, table? })` | `Promise<void>` | 写入 JSON 值(覆盖) |
|
||
| `updateJson({ namespace, key, value, table? })` | `Promise<void>` | 合并更新:对象会深度合并;非对象直接替换 |
|
||
| `renameKey({ namespace, key, newKey, table? })` | `Promise<void>` | 重命名 key |
|
||
| `deleteJson({ namespace, key, table? })` | `Promise<void>` | 删除 key |
|
||
| `listKeys({ namespace, table? })` | `Promise<string[]>` | 列出 table 下所有 key |
|
||
| `listTables({ namespace })` | `Promise<string[]>` | 列出现有 table(KV 与 Blob 的 union) |
|
||
| `deleteTable({ namespace, table })` | `Promise<void>` | 删除 table(同时删除该 table 下的 KV 与 Blob) |
|
||
|
||
兼容:`updateJSON()` 是 `updateJson()` 的别名;`updateKey()` 是 `renameKey()` 的别名。
|
||
|
||
## 2. Blob 方法
|
||
|
||
### 什么时候用 Blob?
|
||
|
||
存大型文件时,需要时再用:
|
||
|
||
- 图片/音频/压缩包/模型文件等二进制
|
||
- 体积较大、不希望浪费 JSON 格式化算力的内容(例如大段纯文本缓存)
|
||
- 需要直接喂给 Web API 的场景(返回值是 `Blob`,可 `URL.createObjectURL()`)
|
||
|
||
| 方法 | 返回值 | 说明 |
|
||
| --- | --- | --- |
|
||
| `getBlob({ namespace, key, table? })` | `Promise<Blob>` | 读取 blob(文件类型 mimeType 基于 key 文件扩展名猜测) |
|
||
| `getBlobStream({ namespace, key, table? })` | `Promise<ReadableStream<Uint8Array>>` | 按消费速度读取原始字节;取消会关闭 reader |
|
||
| `setBlob({ namespace, key, data, table? })` | `Promise<void>` | 写入 blob,允许空内容 |
|
||
| `deleteBlob({ namespace, key, table? })` | `Promise<void>` | 删除 blob |
|
||
| `listBlobKeys({ namespace, table? })` | `Promise<string[]>` | 列出 table 下所有 blob key |
|
||
|
||
## 3. 命名规则(namespace / table / key)
|
||
|
||
- 仅允许字符:`[A-Za-z0-9_.-]`
|
||
- 不能为空
|
||
- 不能以 `.` 开头
|
||
- `.` / `..` 不被允许
|
||
|
||
## 4. `table` (多表)的语义
|
||
|
||
`table` 是**逻辑分组**:方便把同一扩展的不同数据域分开放、以及一键清理某个分组(`deleteTable`)。
|
||
|
||
当前实现中:
|
||
|
||
- **每个 `(namespace, table, key)` 都是一个独立文件**
|
||
- `KV JSON`:`.../kv/<table>/<key>.json`
|
||
- `Blob`:`.../blobs/<table>/<key>`(原样文件名,不强制扩展名)
|
||
|
||
示例(以 `my-ext` 为例):
|
||
|
||
- `setJson({ namespace: 'my-ext', key: 'settings', value })`
|
||
- 存储在`data_root/_tauritavern/extension-store/my-ext/kv/main/settings.json`
|
||
- `setJson({ namespace: 'my-ext', table: 'index', key: 'v1', value })`
|
||
- 存储在`data_root/_tauritavern/extension-store/my-ext/kv/index/v1.json`
|
||
- `setBlob({ namespace: 'my-ext', key: 'icon.png', data })`
|
||
- 存储在`data_root/_tauritavern/extension-store/my-ext/blobs/main/icon.png`
|
||
|
||
小型整体状态可以使用固定 key;持续增长的数据应拆成多个 key,按需读取。
|
||
|
||
## 5. 读写边界
|
||
|
||
- 写入保存调用时快照,以单文件原子替换发布;失败不暴露部分内容,不承诺断电持久化。页面重载前应等待需要确认的写入完成。
|
||
- 并发修改按发布顺序生效;`updateJson()` 的读取、合并和发布作为一次原子更新。删除不取消在途写入,没有跨 key 事务。
|
||
- 已打开的读取保持原文件版本,不受后续覆盖或删除影响。
|
||
- `getJson()` / `getBlob()` 返回完整值;JSON 写入和 base64 输入仍有整份数据的内存成本。大型二进制优先使用 Blob 写入和 `getBlobStream()` 读取。
|