Turso
快速开始
使用 Turso 蓝图为现有 Flue 项目添加持久化托管数据库存储。在终端或你选择的编码智能体中运行以下命令:
flue add database turso
概述
Turso 蓝图会安装 @flue/libsql 和 @libsql/client,在源代码根目录创建 db.ts,并在项目已有环境文档时更新它。它使用 libSQL 适配器和 Turso 的数据库 URL 和认证令牌:
import { libsql } from '@flue/libsql';
import { createClient, type ResultSet } from '@libsql/client';
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});
const toRows = (rs: ResultSet) =>
rs.rows.map((row) => Object.fromEntries(rs.columns.map((column) => [column, row[column]])));
export default libsql({
query: async (text, params = []) => toRows(await client.execute({ sql: text, args: params })),
transaction: async (fn) => {
const tx = await client.transaction('write');
// ...
},
close: () => client.close(),
});Flue 在构建时发现适配器并将其连接到生成的 Node 服务器。启动时,它会创建或验证所需的 flue_* 表。规范的智能体对话、不可变附件和已接受的提交随后会在托管的 Turso 中在进程替换后得以保留。副本可以共享持久状态,但每个智能体实例仍然需要一个活动的 Node 所有者。应用业务数据仍由应用自行管理。此蓝图仅适用于 Node 目标,因为 Cloudflare 部署使用 Durable Object SQLite。
配置
| 变量 | 用途 |
|---|---|
TURSO_DATABASE_URL | 必需 — 数据库的 libsql:// URL。 |
TURSO_AUTH_TOKEN | 必需 — 数据库的认证令牌。 |
createClient 在运行时读取这些值 — 它们不会被烘焙到构建中。对于本地开发,vite dev 会加载项目 .env 文件,而 flue run --env <file> 会加载任何 .env 格式的文件。在生产环境中,请从你平台的密钥存储中提供它们。
Turso 是托管的复制 libSQL。蓝图会安装 @flue/libsql 和官方的 @libsql/client,并在源代码根目录创建一个使用 Turso 配置包装客户端的 db.ts — 它是与 flue add database libsql 相同的适配器,指向 Turso 数据库。Flue 在构建时发现 db.ts 并将其连接到生成的 Node 服务器。
@flue/libsql 是一个 Node.js 适配器。Cloudflare 目标会自动使用 Durable Object SQLite,并在构建时拒绝 db.ts 文件,因此本指南适用于 Node 部署。有关每个目标如何存储状态的完整信息,请参阅数据库。
创建数据库
使用 Turso CLI 创建数据库和认证令牌:
turso db create flue-agents
turso db show --url flue-agents # → TURSO_DATABASE_URL (libsql://…)
turso db tokens create flue-agents # → TURSO_AUTH_TOKEN
import { libsql } from '@flue/libsql';
import { createClient, type ResultSet } from '@libsql/client';
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});
const toRows = (rs: ResultSet) =>
rs.rows.map((row) => Object.fromEntries(rs.columns.map((column) => [column, row[column]])));
export default libsql({
query: async (text, params = []) => toRows(await client.execute({ sql: text, args: params })),
transaction: async (fn) => {
const tx = await client.transaction('write');
try {
const result = await fn({
query: async (text, params = []) => toRows(await tx.execute({ sql: text, args: params })),
});
await tx.commit();
return result;
} catch (error) {
await tx.rollback();
throw error;
} finally {
tx.close();
}
},
close: () => client.close(),
});Turso 在服务器端序列化写入,因此没有嵌入式文件并发问题。运行器形状(query、transaction、close)和 ResultSet 映射在 libSQL 指南中有解释。
嵌入式副本
为了降低读取延迟,Turso 支持嵌入式副本 — 一个与远程数据库保持同步的本地 SQLite 文件,因此读取访问本地磁盘,写入转发到 Turso。将 url 指向本地文件并添加 syncUrl:
const client = createClient({
url: 'file:flue-replica.db',
syncUrl: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});db.ts 的其余部分保持不变。当读取延迟很重要时使用此功能;上面的普通远程客户端是默认设置。
迁移
适配器的 migrate() 钩子会在生成的 Node 服务器启动时自动运行。它会幂等地创建 Flue 的 flue_* 表并标记格式版本,因此首次启动时会配置新数据库,重启时会重用现有数据库。没有单独的迁移命令需要运行,由较新 Flue 版本写入的数据库会拒绝启动,而不是损坏状态。
存储内容
Flue 数据库存储运行时状态,而不是整个应用。
由 Flue 存储:
- 规范的智能体对话流和压缩记录;
- 不可变附件负载;
- 已接受的直接提示和
dispatch(...)提交; - 持久化提交声明、租约和结算记录。
不由 Flue 存储:
- 沙盒文件和已安装的依赖项;
- 外部 API 副作用;
- 应用拥有的业务数据,除非你自己的工具存储它;
- 提供商凭证或密钥。
有关恢复如何使用提交状态的信息,请参阅持久性, 有关确切适配器契约的信息,请参阅数据持久化 API。
何时选择 Turso
当你想要托管的复制 SQLite 而不运行服务器,并且可选地使用嵌入式副本进行低延迟读取时,请选择 Turso。对于本地文件或你自己运营的 libSQL 服务器,请通过 libSQL 指南使用相同的适配器。对于支持进程或主机替换的外部持久化存储,请参阅 @flue/postgres。Node 仍然需要每个智能体实例一个活动所有者。