Cell - Stripe 组件
将 @celljs/stripe 和 stripe(官方 SDK,一个对等依赖)添加到依赖中,以使用 Stripe:@Autowired(StripeClient) 给出配置的 Stripe 客户端,webhook 端点验证事件的 Stripe-Signature 并按类型将其路由到你的处理程序。API 本身是官方 SDK 的,带有其类型。
bun add @celljs/stripe stripe数据库驱动程序不是此包的依赖:安装你的数据源使用的那个(mysql2、pg、better-sqlite3、sql.js 等)。mysql2 是一个可选的对等依赖;当配置的数据源的驱动程序缺失时,应用程序在启动时失败,显示 CELL_TYPEORM_DRIVER_MISSING 和安装它的命令。
# cell.yml:配置仅对服务器有效,除非 schema 标记为公开;从环境中获取秘密
stripe:
apiKey: ${env.STRIPE_SECRET_KEY}
webhook:
secret: ${env.STRIPE_WEBHOOK_SECRET} # whsec_...import { Autowired } from '@celljs/core';
import { Body, Controller, Post } from '@celljs/mvc/lib/node';
import { StripeClient, StripeWebhookHandler } from '@celljs/stripe';
import type Stripe from 'stripe';
@Controller('checkout')
export class CheckoutController {
@Autowired(StripeClient)
protected readonly stripe: StripeClient;
@Post()
async create(@Body() order: { id: string }) {
const session = await this.stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{ price: 'price_123', quantity: 1 }],
client_reference_id: order.id,
success_url: 'https://shop.example.com/paid',
});
return { url: session.url };
}
}
@StripeWebhookHandler('checkout.session.completed')
export class CheckoutCompletedHandler implements StripeWebhookHandler<Stripe.CheckoutSessionCompletedEvent> {
async handle(event: Stripe.CheckoutSessionCompletedEvent) {
// event.data.object 是会话;标记订单已支付一次:Stripe 可以多次传递事件。
}
}Webhook
端点是 POST /stripe/webhook(stripe.webhook.url,在 server.path 下):在 Stripe 仪表板中注册其 URL,或在开发期间用 stripe listen --forward-to localhost:3000/stripe/webhook 将事件转发到它(将 secret 设置为它打印的那个)。它在 body 解析器和身份验证之前运行,使用每个 secret 验证作为发送的 body 上的签名(列表为多个端点或轮换服务)和 tolerance 为 300 秒,然后运行事件类型的 @StripeWebhookHandler 组件,然后是声明为无类型的那些,一个接一个。它回应:
- 200
{"received":true}当他们全部成功时(或没有处理程序接受该类型时:记录为警告); - 400 当签名不匹配时;
- 500 当处理程序抛出时(或 secret 未配置):Stripe 为期三天重试事件。
StripeWebhookVerifier 验证在你自己的路由上接收的请求:verify(rawBody, signatureHeader)。
配置
stripe:
apiKey: ${env.STRIPE_SECRET_KEY}
config: # Stripe 客户端的选项
maxNetworkRetries: 2
# apiVersion: 2025-... # 固定一个;SDK 的默认值
webhook:
enabled: true
url: /stripe/webhook
secret: ${env.STRIPE_WEBHOOK_SECRET} # 或列表
tolerance: 300 # 秒客户端在首次使用时创建;重新绑定 StripeFactory(@Component({ id: StripeFactory, rebind: true }))以另一种方式创建它,例如每个租户一个密钥。SDK 在 Bun、Deno 和 Cloudflare Workers 上选择其 fetch 和 SubtleCrypto 构建。stripe 的当前版本需要 Node.js 20 或更高版本(Cell 的其余部分在 18 上运行)。
在没有 Stripe 账户的情况下测试
stripe-mock 回答 Stripe OpenAPI 规范的每个 API 并验证参数(它不保持状态)。用 config: { host: '127.0.0.1', port: 12111, protocol: 'http' } 和任何 sk_test_<letters and digits> 密钥指向客户端;此包对其的测试运行时:
docker run --rm -p 12111:12111 stripe/stripe-mock
STRIPE_MOCK_URL=http://127.0.0.1:12111 bunx turbo run test --filter=@celljs/stripe错误
Stripe 的 API 错误是 SDK 的(Stripe.errors.StripeError)。配置和 webhook 失败是带有稳定 code 和 hint 的 CellStripeError:
| 代码 | 何时 |
|---|---|
CELL_STRIPE_NOT_CONFIGURED | 当客户端被注入时 stripe.apiKey 未设置 |
CELL_STRIPE_WEBHOOK_NOT_CONFIGURED | 事件到达且 stripe.webhook.secret 未设置 |
CELL_STRIPE_SIGNATURE_INVALID | 没有 secret 验证 Stripe-Signature,或其时间戳在 tolerance 外 |