运行时能力

Vault 加密小数据

用按 Plugin 隔离的 KV、文档和小型二进制对象保存加密状态。

Vault 是一项需要宿主显式启用的运行时能力,为每个 Plugin 提供相互隔离、加密持久化的 KV、文档和小型二进制对象。它适合保存 token、checkpoint、小配置和少量领域状态,但不能替代关系数据库或对象存储。

何时选择 Vault

数据选择
token、cursor、checkpoint、少量加密 JSONVault
需要 query、index、join、migration 的结构化数据数据库
大文件、用户上传和远端对象对象存储(仓库内 S3 预览
进程内/跨实例短期加速缓存(仓库内预览

Vault 只在 host 把 vault 配置为对象时安装;omitted 或 false 时没有 capability property、backend、preflight 或管理成本。

启用入口

需要使用 Vault 的宿主在启动配置中显式启用:

configure: () => ({
	vault: {},
})

配置对象承载 Vault 的 lifecycle 输入;导入某个 module 不会修改 Context plan。可以在无 Vault 宿主中运行的通用 Plugin 必须处理 capability absence;强依赖 Vault 的 Plugin 应在 init() 入口给出明确错误。

一个 namespace,三种视图

import { ,  } from '@pluxel/runtime'

@({ : 'Connector' })
export class  extends  {
	protected override async () {
		const  = this..
		if (!) throw new ('ConnectorPlugin requires host config vault: {}')
		const  = .()
		const  = .()
		const  = .().<{ : number; : number }>('cursors')
		const  = .().('client-certificate')

		await .('access-token', 'secret')
		await .('events', {
			: 42,
			: .(),
		})
		await .('certificate text')
		await .()
	}
}

namespace() 默认返回当前 Plugin owner 的稳定 namespace。不同 Plugin 即使使用同一个 key 或 collection name,也不会进入同一默认 namespace。

不要把 namespace().name 当业务 identity 或对外 API;它由 runtime owner address 派生。

KV

const vault = this.ctx.vault
if (!vault) throw new Error('This Plugin requires host config vault: {}')
const kv = vault.kv()

await kv.set('token', token)
const current = await kv.get<string>('token')
await kv.setMany({ cursor: '42', region: 'hk' })
const entries = await kv.entries<string>()

需要原子 read-modify-write 时使用 batch()

await kv.batch((tx) => {
	const current = Number(tx.get<number>('attempts') ?? 0)
	tx.set('attempts', current + 1)
})

batch callback 操作内存中的 copy-on-write transaction,不在其中执行网络请求或长时间异步工作。

Documents

const vault = this.ctx.vault
if (!vault) throw new Error('This Plugin requires host config vault: {}')
const profiles = vault.docs().collection<{ enabled: boolean; label?: string }>('profiles')

await profiles.set('default', { enabled: true })
await profiles.patch('default', { label: 'Primary' })
const profile = await profiles.get('default')
const all = await profiles.list()

documents 是按 ID 读取的小型 JSON records,没有 query planner、secondary index 或 migration engine。出现扫描、筛选、关联和 schema evolution 需求时迁移到数据库。

Blobs

const vault = this.ctx.vault
if (!vault) throw new Error('This Plugin requires host config vault: {}')
const blob = vault.blobs().open('oauth-state')

await blob.writeText(serialized)
const restored = await blob.readText()
await blob.remove()

blobs 保存在 Vault snapshot 管理的文件区域,适合小型加密字节。大对象、流式上传、range request 和跨服务共享使用对象存储。

describe().path 只用于 server-side diagnostics,不暴露到 browser contract 或业务 API。

跨 KV 与 documents 的原子更新

稳定 namespace facade 支持一次更新 KV 和 documents:

const vault = this.ctx.vault
if (!vault) throw new Error('This Plugin requires host config vault: {}')
const space = vault.namespace()

await space.batch((tx) => {
	tx.kv.set('cursor', 43)
	tx.docs.collection<{ processed: boolean }>('events').set('43', {
		processed: true,
	})
})

blob I/O 不进入这个 transaction。需要数据库级 durability、并发隔离或 outbox 时使用 database transaction。

Unlock 与失败语义

Vault 不在普通 Plugin 调用时偷偷 auto-unlock。host 在启动/preflight 阶段通过 host identity 或部署环境中的 age identity 解锁;若 storage 尚未 ready,Plugin 访问会 fail fast。

默认部署 identity 环境变量是 PLUXEL_VAULT_DEPLOY_IDENTITY,host 可通过 vault.deployIdentityEnv 改名。私钥不得写进普通 Plugin config、日志、Workbench DTO/API 或发行物。

vaultAdmin 是仅在 Vault enabled 时存在的 root-owned 宿主管理 API,用于 preflight、unlock、rekey 和 deploy recipient 管理。宿主读取前也必须检查 absence;业务 Plugin 只使用已检查的 ctx.vault,不调用 root admin API。

官方 @pluxel/auth 也是普通 Vault consumer。它只保存 password verifier、TOTP secret/last accepted counter,以及 confidential OIDC client secret;plaintext password、生成的 OTP、session token、OIDC state/nonce/PKCE 和 rate-limit state 都只存在于请求或有界的 generation memory。凭据更新会在 provider ready snapshot 切换前显式 flush()。因此使用 local account 或 confidential OIDC client 的 host 必须配置 vault: {} 并在 Plugin lifecycle 前完成正常 preflight。

Flush 与 durability

写入会进入内存状态并按 host debounce 策略持久化。需要在关键边界确认 snapshot 已落盘时调用:

const vault = this.ctx.vault
if (!vault) throw new Error('This Plugin requires host config vault: {}')
await vault.flush()

不要在每次高频状态变化后强制 flush;批量 checkpoint 或 shutdown 边界更合适。host 可通过 vault.flushDebounceMs 控制后台合并窗口。

安全检查

写入测试值并 flush() 后,正常停止并重启宿主,确认能读回相同值;再用另一个插件读取同名 key,确认默认 namespace 相互隔离。解锁失败应在宿主启动阶段处理,业务请求不会自动解锁。测试内容使用非敏感值,具体测试宿主见 测试插件

最后更新于

本页目录