store
store 提供应用作用域、版本化的持久化键值存储。宿主负责持久化、并发冲突和账户同步;guest 决定值的格式、索引和领域语义。
基本示例
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const current = await host.store.get('settings/theme');
const settings = current
? JSON.parse(decoder.decode(current.value))
: { theme: 'system' };
await host.store.put(
'settings/theme',
encoder.encode(JSON.stringify({ ...settings, theme: 'dark' })),
current?.version,
);
传入 expectedVersion 可以防止两个窗口静默覆盖彼此。
适用场景
- 设置、草稿、进度和小型结构化数据。
- guest 数据库的页、日志或索引块。
- 可通过应用账户在设备间同步的密文值。
SQL、查询规划、全文索引、CRDT 和业务 schema 属于 L2。大媒体文件或无限追加日志需要后续专门的对象/流能力,不能挤进 KV。
能力声明
{
"capabilities": [
"host:store.get",
"host:store.put",
"host:store.delete",
"host:store.list",
"host:store.deletePrefix"
]
}
读、写、列举和批量删除逐方法声明。
Reference
- store.get():读取值和当前版本。
- store.put():创建或条件更新。
- store.delete():条件删除单个键。
- store.list():分页列举键与元数据。
- store.deletePrefix():原子或明确分批删除一个前缀。
数据模型
StoreEntry {
key: bounded-string
value: Bytes
version: u64
updatedAt?: coarse-time
}
键是规范化 UTF-8 字符串。/ 只是普通字符的约定分隔符,不对应宿主路径。值是无类型字节;getText、putJSON 等便利方法应由 SDK 提供。
分页与并发示例
let cursor: string | undefined;
do {
const page = await host.store.list('documents/', cursor);
for (const item of page.items) renderDocumentRow(item.key, item.version);
cursor = page.cursor;
} while (cursor);
解决乐观并发冲突:
async function increment(key: string) {
for (let attempt = 0; attempt < 3; attempt++) {
const old = await host.store.get(key);
const next = encodeNumber((old ? decodeNumber(old.value) : 0) + 1);
try {
return await host.store.put(key, next, old?.version);
} catch (error) {
if (error.code !== 'conflict') throw error;
}
}
throw new Error('too much contention');
}
原生 WASM 示例
uint8_t buffer[4096];
StoreGetResult r = host_store_get("settings/theme", byte_sink(buffer, sizeof(buffer)));
if (r.found) decode_settings(buffer, r.written, r.version);
超过当前 sink 的值返回 required 或可继续读取的明确结果,不能截断后伪装成功。
一致性与同步
put和单键delete对一个键线性化;相同expectedVersion只能有一个成功。list的 cursor 是不透明、有限期值;guest 不解析也不持久化。- 多设备同步可以延迟,但冲突不能靠最后写入静默吞掉版本条件。
- 平台服务只持有端到端加密后的值;键名和大小等元数据泄露必须在隐私说明中披露。
安全与预算
- 信任档位:green。
- 数据按 appId 隔离;任何调用都不能覆盖 namespace。
- 预算覆盖键长、值大小、键数、总容量、分页大小、在途调用和时间窗写入量。
deletePrefix必须显示实际删除数量,并受单次和时间窗预算限制。- 错误、日志和遥测不得记录值内容。
错误与测试
特有错误包括 conflict、quota-exceeded、invalid-key、cursor-expired 和 sink-too-small。一致性测试至少覆盖首次写入、条件更新、并发写、删除竞态、分页稳定性、空前缀、配额、跨应用隔离、同步重放和密文不可读性。