Supabase Stripe Wrapper:用 Postgres FDW 直接读写 Stripe 数据的技术详解
本文以 Supabase 仓库中 Stripe Wrapper 集成概览 为起点,深入解析这个 Foreign Data Wrapper(外部数据包装器)的完整技术定义:它的扩展、处理器与校验器命名、服务器级连接参数(如 api_key_id、api_url)、Studio 中"按表创建"与"外部 Schema"两种使用模式、全部 27 个可映射的 Stripe 对象及其列结构,以及它依赖的 wrappers、supabase_vault 前置扩展。读完后,你将能够基于仓库中的真实元数据,在自己的 Postgres 数据库中正确配置并查询 Stripe 的客户、订阅、发票与支付数据。
什么是 Stripe Wrapper
官方概览文档 给出的核心定义只有两句,但信息密度很高:
Stripe 是一个 API 驱动的支付处理和订阅管理平台。Stripe Wrapper 是一个 Foreign Data Wrapper,允许你在 Postgres 数据库内部直接从 Stripe 读取和写入数据。
这意味着 Stripe 的账户数据不需要经过 ETL 管道或 Webhook 搬运,就能以 Postgres 外表(foreign table)的形式出现在你的数据库里,直接用 SQL 完成 JOIN、聚合和 BI 查询。"读写"两个方向都要注意:既支持 SELECT 拉取 Stripe API 的对象列表,也支持通过 INSERT/UPDATE 回写到 Stripe。
在 Supabase Studio 的集成市场中,该集成的标识为 stripe_wrapper,其展示描述为"Payment processing and subscription management",归类于 billing 分类。
技术身份:扩展、Handler 与 Validator
从源码定义 Wrappers.constants.ts 可以看到,每个 Wrapper 在 Postgres 侧都由三元组标识:
| 属性 | stripe_wrapper 的取值 | 作用 |
|---|---|---|
extensionName |
StripeFdw |
需要安装的 Postgres 扩展 |
handlerName |
stripe_fdw_handler |
CREATE SERVER ... HANDLER 时指定的 FDW 处理函数 |
validatorName |
stripe_fdw_validator |
校验服务器/外表选项合法性的函数 |
name |
stripe_wrapper |
Studio 内部集成标识 |
docsUrl |
/guides/database/extensions/wrappers/stripe |
官方文档页 |
在 WRAPPER_HANDLERS 映射表 中,Stripe 与 Firebase、S3、ClickHouse、BigQuery、Airtable 等属于原生(非 WASM)FDW 处理器一列;而 Paddle、Snowflake、Slack、Notion 等则统一走 wasm_fdw_handler。这种区分说明 Stripe 使用的是针对其 REST API 专门实现的 C 层 FDW,而非通用 WASM 封装。
服务器级连接参数
在 stripe_wrapper 的 server.options 定义 中,连接 Stripe 需要配置以下三个服务器选项:
| 选项名 | 表单标签 | 必填 | 说明 |
|---|---|---|---|
api_key_id |
Stripe Secret Key | 是 | Stripe 密钥;encrypted: true 且 secureEntry: true,表示 Studio 会以密文形式存入 Vault,输入框为安全输入 |
api_url |
Stripe API URL | 否 | 默认值 https://api.stripe.com/v1,可覆盖以指向其他 API 端点 |
supabase_target_schema |
Target Schema | 否 | 隐藏且只读 的框架选项(hidden: true, readOnly: true),由 Studio 在后台自动写入,用于指定外表落位的 target schema |
密钥通过 encrypted 标记说明其不直接落在 CREATE SERVER 的明文中,而是经由 Supabase Vault 扩展托管——这也是下面"前置扩展"一节中 supabase_vault 成为必需项的原因。
表单层面对这些选项做了强制校验:Wrappers.utils.ts 的 getWrapperCreationFormSchema 会遍历 server.options,把所有 required: true 的选项(即 api_key_id)编译为 Zod 必填字段,可选项(api_url)编译为 z.string().optional()。对应的单测 Wrappers.utils.test.ts 断言了:缺少 api_key_id 时校验失败并定位到该字段,而缺少 api_url 时不产生错误——与上面的参数表一一对应。
两种使用模式:Tables 模式与 Schema 模式
创建 Wrapper 表单是一个以 mode 为判别字段的 discriminated union(源码):
- Tables 模式(
mode: 'tables'):逐表映射。用户从预定义的 Stripe 对象列表中选择要映射的对象,每张外表需要table_name、所属schema(可选custom+ 自定义schema_name)、列集合columns,以及该对象的object选项;要求"至少一张表"。 - Schema 模式(
mode: 'schema'):整 Schema 映射。只需提供source_schema(Stripe 侧源 schema)与target_schema(Postgres 侧唯一目标 schema)。stripe_wrapper 的 source_schema 选项 默认值为stripe。
单测 Wrappers.utils.test.ts 明确验证了两个分支:tables 模式缺 tables 字段会报错,schema 模式缺 source_schema/target_schema 会报错。
支持的 27 个 Stripe 对象
stripe_wrapper 的 tables 数组 完整枚举了可映射的 Stripe API 对象,每个对象由一个不可编辑、必填的 object 选项指向对应的 API 端点:
| 对象 | object 默认值 |
说明(原文描述摘要) |
|---|---|---|
| Accounts | accounts |
Stripe 账户下的账户列表 |
| Balance | balance |
账户当前余额 |
| Balance Transactions | balance_transactions |
构成账户余额的交易 |
| Charges | charges |
已发生的扣款 |
| Checkout Sessions | checkout/sessions |
Checkout/Payment Links 支付会话 |
| Customers | customers |
客户 |
| Disputes | disputes |
客户向发卡机构发起的争议 |
| Events | events |
Stripe 账户内发生的事件 |
| Files | files |
托管在 Stripe 服务器上的文件 |
| File Links | file_links |
与非 Stripe 用户共享文件的链接 |
| Invoices | invoices |
发票 |
| Mandates | mandates |
客户授权扣款的凭证记录 |
| Meters | billing/meters |
计费中的用量计量事件 |
| Payment Intents | payment_intents |
支付意向 |
| Payouts | payouts |
提现/打款到银行账户或借记卡 |
| Prices | prices |
产品价格对象 |
| Products | products |
产品 |
| Refunds | refunds |
退款 |
| Setup Attempts | setup_attempts |
SetupIntent 的确认尝试 |
| Setup Intents | setup_intents |
保存支付凭证的意向 |
| Subscriptions | subscriptions |
订阅 |
| Tokens | tokens |
令牌 |
| Top-ups | topups |
充值 |
| Transfers | transfers |
转账 |
列结构上有两点值得注意的设计:
- 固定列 +
attrsjsonb 列:每张表都暴露少量强类型列(id/text、金额类bigint、created/timestamp、状态类text、布尔bool等),并统一附加一个attrs(jsonb)列承载 Stripe API 返回的完整 JSON。例如 Balance Transactions 表暴露id、amount、currency、fee、net、status、type、created之外,其余字段全部收进attrs。这保证了常用字段有类型、有性能,长尾字段又不丢失。 rowid_column选项:Accounts、Checkout Sessions、Customers、Products、Subscriptions 等对象额外提供可编辑的rowid_column(默认id),用于标识行身份,支撑对 Stripe 的写回操作(UPDATE/DELETE依赖它定位远端对象)。
前置扩展与版本约束
Stripe Wrapper 并非开箱即用,它依赖两个扩展,这一点在 getRequiredExtensionsToInstall 及其测试中有明确定义:
wrappers:FDW 框架核心扩展;supabase_vault:用于安全托管api_key_id等加密选项。
Wrappers.utils.test.ts 验证了"缺哪个补哪个"的安装逻辑:两个都已安装时返回空数组,只装了 supabase_vault 时返回 ['wrappers']。
另外,hasForeignSchemaSupport 的单测界定了版本能力边界:wrappers 扩展 >= 0.5.0 才支持外部 Schema(foreign schema)模式,0.4.9 及以下返回 false。因此如果你要使用上文的 Schema 模式(source_schema/target_schema),应确认数据库中安装的 wrappers 版本满足该前提。
与 Stripe Sync Engine 的分工
同目录下还有一个近亲集成 stripe_sync_engine,其官方描述是:"将 Stripe 账户中的 customers、subscriptions、invoices、payments 数据同步(sync)到 Supabase 账户的 Postgres 表"。两者定位不同:
- stripe_wrapper(本文主题):FDW,数据实时代理,查询时按需读写 Stripe,适合交互式 SQL 分析、联表查询;
- stripe_sync_engine:同步引擎,把数据物化到本地 Postgres 表,适合需要本地持久副本的场景。
在 Studio 集成市场里二者并列出现,选择依据取决于"实时代理"还是"物化副本"。
概览文档在 Studio 中的加载机制
最后交代一下这份 overview.md 本身如何进入产品。overviews.ts 维护了一个以集成为键的惰性加载表,stripe_wrapper 的条目动态 import 本概览 Markdown;文件头部注释解释了为什么必须写成字符串字面量:webpack/turbopack 与 Vite/Rolldown 的 md-as-string 加载器(next.config.ts 的 raw-loader 规则、vite.config.ts 的 mdRawLoader 插件)只能静态分析字面量导入,模板字符串写法会在 TanStack 构建中抛出 TypeError: Failed to resolve module specifier。loadIntegrationOverview(integrationId) 对没有概览的集成(如 marketplace 应用)返回 null。配套的 overviews.test.ts 会断言这张映射表与磁盘上的 overview.md 文件保持同步——新增集成时,overview.md 与 overviews.ts 条目需要同时添加。
小结
Stripe Wrapper 让 Stripe 数据以标准 Postgres 外表的形式进入你的数据库:由 StripeFdw 扩展、stripe_fdw_handler 处理器与 stripe_fdw_validator 校验器构成技术底座,通过 api_key_id(Vault 加密托管)与可选的 api_url 建立连接,支持 27 个 Stripe 对象的逐表映射(Tables 模式)或整体 Schema 映射(要求 wrappers >= 0.5.0)。所有参数、列与默认值均可在上述 Wrappers.constants.ts 与 Wrappers.utils.ts 中查证,测试文件 Wrappers.utils.test.ts 则锁定了这些校验行为。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00