Supabase
快速开始
使用 Supabase 蓝图为现有 Flue 项目添加持久化共享 Postgres 存储。在终端或你选择的编码智能体中运行以下命令:
flue add database supabase
概述
Supabase 蓝图会安装 @flue/postgres 和 pg,添加匹配的 @types/pg 开发依赖,并在项目的源代码根目录创建事务安全的 db.ts。它使用项目现有的密钥约定,并在存在时更新现有的环境示例或环境文档。
主要生成的适配器为事务中的每个查询使用一个签出的 pg 客户端:
import { postgres } from '@flue/postgres';
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.SUPABASE_DATABASE_URL });
export default postgres({
query: async (text, params) => (await pool.query(text, params)).rows,
transaction: async (fn) => {
const client = await pool.connect();
// ...
},
close: () => pool.end(),
});Flue 在 Node 构建期间发现适配器,在服务器启动时运行其迁移,并在 Supabase 中持久化规范的智能体对话、不可变附件和已接受的提交,以便状态在进程替换后得以保留。副本可以共享持久状态,但每个智能体实例仍然需要一个活动的 Node 所有者。应用业务数据仍由应用自行管理。
配置
| 变量 | 用途 |
|---|---|
SUPABASE_DATABASE_URL | 必需 — 来自 Supabase 仪表板 > 连接 的连接字符串。 |
蓝图会安装现有的 @flue/postgres 适配器和 pg,并在源代码根目录创建 db.ts。没有 Supabase 特定的 Flue 包。Flue 在构建时发现该文件,并将其连接到生成的 Node 服务器。
此集成仅适用于 Node.js。Cloudflare 目标会自动使用 Durable Object SQLite,并在构建时拒绝 db.ts。有关按目标的持久化信息,请参阅数据库。
从 Supabase 仪表板 > 连接 复制连接字符串,并在运行时将其作为 SUPABASE_DATABASE_URL 提供:
| 部署 | 推荐连接 |
|---|---|
| 持久化、支持 IPv6 的 Node 服务器 | 直接连接 |
| 持久化、仅 IPv4 的 Node 服务器 | 会话模式的共享连接池器 |
特定于提供商的环境变量使密钥的来源清晰。如果你的项目已经使用另一种数据库变量约定,请在 db.ts 中一致使用它。通过你平台的密钥存储提供该值,永远不要提交它。对于本地开发,vite dev 会加载项目 .env 文件,而 flue run --env <file> 会加载任何 .env 格式的文件。
事务模式连接池不是默认设置。它可以保留在一个签出客户端上执行的显式事务,并且本质上不会破坏 BEGIN/COMMIT,但它不支持预处理语句或会话状态。如果你的部署需要事务模式,请保持 pg 查询未命名,如示例所示:不要在查询配置中传递 name 或以其他方式启用命名预处理语句,并且不要依赖会话状态。
使用事务安全的运行器
@flue/postgres 接受一个运行器,因此应用拥有驱动配置、连接池、TLS 和凭证。规范的 pg 运行器为整个事务回调签出一个客户端:
import { postgres } from '@flue/postgres';
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.SUPABASE_DATABASE_URL });
export default postgres({
query: async (text, params) => (await pool.query(text, params)).rows,
transaction: async (fn) => {
const client = await pool.connect();
try {
await client.query('BEGIN');
const result = await fn({
query: async (text, params) => (await client.query(text, params)).rows,
});
await client.query('COMMIT');
return result;
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
},
close: () => pool.end(),
});回调中的每个查询都使用签出的客户端。通过连接池发送这些查询可能会将工作转移到另一个连接,从而脱离事务。@flue/postgres 使用事务范围的 pg_advisory_xact_lock,而不是会话咨询锁来序列化会话更新;每个锁随其事务释放。
迁移
适配器的 migrate() 钩子会在生成的 Node 服务器启动时自动运行。它会幂等地创建 Flue 的 flue_* 表并标记格式版本,因此首次启动时会配置新的 Supabase 数据库,重启时会重用现有数据库。没有单独的迁移命令,由较新 Flue 版本写入的数据库会拒绝启动,而不是冒不兼容写入的风险。
存储内容
Flue 数据库存储运行时状态,而不是应用的整个数据模型。
由 Flue 存储:
- 规范的智能体对话流和压缩记录;
- 不可变附件负载;
- 已接受的直接提示和
dispatch(...)提交; - 持久化提交声明、租约和结算记录;
- 已接受工作的恢复状态。
不由 Flue 存储:
- 沙盒文件和已安装的依赖项;
- 外部 API 副作用;
- 应用拥有的业务数据;
- 提供商凭证或密钥。
有关恢复行为,请参阅持久性, 有关适配器契约,请参阅数据持久化 API。
验证
构建配置的 Node 目标并确认发现 db.ts。在非生产 Supabase 项目上,启动服务器并确认创建了 flue_* 表。创建智能体状态,重启服务器,并确认状态重新加载。如果使用共享连接池器,请验证其模式与部署匹配,并且当显式选择事务模式时,不使用命名预处理语句或会话状态。
何时选择 Supabase
当你的持久化 Node 部署需要持久化的共享 Flue 状态,并且 Supabase 已经提供其托管的 Postgres 时,请选择 Supabase。在 IPv6 可用时使用直接连接,或为仅 IPv4 的服务器使用会话模式共享连接池。对于其他托管或自托管的 Postgres 部署,请使用通用 Postgres 指南。