mcpField
C
convex-billing

convex-billing

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

关于 convex-billing

convex-billing 是一项技能,通过 @convex-dev/stripe 为 Convex 应用添加 Stripe 计费。它指导配置结账、签名验证 Webhook、订阅状态存储和服务端访问检查。

主要功能

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

适用场景

  1. 01为 Convex 应用添加 Stripe 订阅
  2. 02处理结账和订阅 Webhook 事件
  3. 03根据订阅状态限制服务端功能访问

安装

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

$npx skills add https://github.com/get-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