mcpField
C
convex-billing

convex-billing

github.com/convex开发6936.9k 次安装1 天前更新
代码仓库

关于 convex-billing

convex-billing 是一项使用 @convex-dev/stripe 为 Convex 添加 Stripe 账单功能的技能。它指导配置结账、签名验证 Webhook、组件存储的订阅状态,以及服务端订阅权限控制。

主要功能

  1. 01安装并配置 @convex-dev/stripe
  2. 02设置结账 action
  3. 03注册签名验证 Webhook
  4. 04在组件表中存储订阅状态
  5. 05通过服务端查询控制访问

适用场景

  1. 01为 Convex 应用添加 Stripe 订阅结账
  2. 02处理 Stripe 订阅和付款事件
  3. 03依据存储的订阅状态限制功能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/convex/agent-skills --skill convex-billing

安装后在 Claude Code 中输入/convex-billing确认已加载。

详细介绍

添加计费 / 支付

使用 @convex-dev/stripe 将 Stripe 接入 Convex:创建结账 action、由组件注册的 httpAction webhook(自动验证签名)、存储在组件表中的订阅状态,以及通过 query 在服务端进行访问控制。

工作流

  1. 安装组件:npm install @convex-dev/stripe。
  2. 创建 convex/convex.config.ts:
    import { defineApp } from 'convex/server';
    import stripe from '@convex-dev/stripe/convex.config.js';
    const app = defineApp();
    app.use(stripe);
    export default app;
    
  3. 将 Stripe 密钥存储在 Convex 环境变量中(使用 env micro power):STRIPE_SECRET_KEY(sk_test_… / sk_live_…)和 STRIPE_WEBHOOK_SECRET(whsec_…)。
  4. 创建 convex/http.ts 以注册 webhook 路由(组件会自动处理签名验证):
    import { httpRouter } from 'convex/server';
    import { components } from './_generated/api';
    import { registerRoutes } from '@convex-dev/stripe';
    const http = httpRouter();
    registerRoutes(http, components.stripe, { webhookPath: '/stripe/webhook' });
    export default http;
    
  5. 创建 convex/billing.ts,其中包含结账 action 和订阅访问控制 query:
    import { action, query } from './_generated/server';
    import { components } from './_generated/api';
    import { StripeSubscriptions } from '@convex-dev/stripe';
    import { v } from 'convex/values';
    const stripeClient = new StripeSubscriptions(components.stripe, {});
    export const createSubscriptionCheckout = action({
      args: { priceId: v.string() },
      returns: v.object({ sessionId: v.string(), url: v.union(v.string(), v.null()) }),
      handler: async (ctx, args) => {
        const identity = await ctx.auth.getUserIdentity();
        if (!identity) throw new Error('Not authenticated');
        const customer = await stripeClient.getOrCreateCustomer(ctx, { userId: identity.subject, email: identity.email, name: identity.name });
        return await stripeClient.createCheckoutSession(ctx, { priceId: args.priceId, customerId: customer.customerId, mode: 'subscription', successUrl: `${process.env.SITE_URL ?? 'http://localhost:3000'}/?success=true`, cancelUrl: `${process.env.SITE_URL ?? 'http://localhost:3000'}/?canceled=true`, subscriptionMetadata: { userId: identity.subject } });
      },
    });
    export const isSubscribed = query({
      args: {},
      returns: v.boolean(),
      handler: async (ctx) => {
        const identity = await ctx.auth.getUserIdentity();
        if (!identity) return false;
        const subscriptions = await ctx.runQuery(components.stripe.public.listSubscriptionsByUserId, { userId: identity.subject });
        return subscriptions.some((sub) => sub.status === 'active' || sub.status === 'trialing');
      },
    });
    
  6. 运行 npx convex dev --once — 它会安装组件并推送函数。确认输出中显示 ✔ Installed component stripe.。
  7. 在 Stripe Dashboard → Webhooks 中:添加端点 https://<deployment>.convex.site/stripe/webhook,订阅 checkout.session.completed、customer.subscription.*、invoice.*、payment_intent.*。将签名密钥复制为 STRIPE_WEBHOOK_SECRET。

规则

  • 使用 @convex-dev/stripe(npm: @convex-dev/stripe@^0.1.4)— 它会通过 registerRoutes 在内部处理 webhook 签名验证;不要手动编写 constructEvent webhook。
  • Stripe 密钥存储在 Convex 环境变量中(使用 env micro power):STRIPE_SECRET_KEY 和 STRIPE_WEBHOOK_SECRET。
  • 通过服务端存储的订阅状态进行访问控制,使用 isSubscribed query(读取组件表),而不是依赖客户端声明。
  • convex/convex.config.ts 必须从 '@convex-dev/stripe/convex.config.js' 导入(不能使用 .ts)— Convex 打包器要求使用 .js 扩展名。

评论

支持 Markdown