npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

woyingdang_creemsdk

v1.0.0

Published

Modular Creem Payment SDK for TypeScript/JavaScript projects

Readme

Creem Payment SDK

模块化的 Creem 支付集成 SDK,方便快速集成 Creem 支付功能

版本: 1.0.0 作者: 幽浮喵 (猫娘工程师) 文档: https://docs.creem.io

快速开始

安装

# 复制 SDK 文件到项目中
cp -r lib/creem your-project/lib/

环境变量配置

.env.local 文件中添加以下配置:

# ============================================
# Creem Payment 配置
# ============================================

# Creem API Key(服务端专用)
# 测试密钥:creem_test_xxxxxxxxxxxxxxxxx
# 生产密钥:creem_sk_xxxxxxxxxxxxxxxxx
CREEM_API_KEY=creem_test_xxxxxxxxxxxxxxxxx

# Creem Public Key(客户端使用)
NEXT_PUBLIC_CREEM_PUBLIC_KEY=creem_pk_xxxxxxxxxxxxxxxxx

# Creem API Base URL(可选)
# 测试环境:https://test-api.creem.io
# 生产环境:https://api.creem.io
CREEM_API_BASE_URL=https://test-api.creem.io

# Creem Webhook Secret(可选)
# 用于验证 Webhook 请求的签名
CREEM_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxx

# Creem Product IDs(需要在 Creem Dashboard 创建产品)
CREEM_PRODUCT_PRO_MONTHLY=prod_xxxxxxxxxxxxxxxxx
CREEM_PRODUCT_PRO_YEARLY=prod_xxxxxxxxxxxxxxxxx
CREEM_PRODUCT_ENTERPRISE_MONTHLY=prod_xxxxxxxxxxxxxxxxx
CREEM_PRODUCT_ENTERPRISE_YEARLY=prod_xxxxxxxxxxxxxxxxx

基础使用

import { createCreemClient } from '@/lib/creem'

// 创建客户端
const client = createCreemClient()

// 创建支付链接
const checkout = await client.checkouts.create({
  productId: 'prod_abc123',
  successUrl: 'https://example.com/success',
  customer: { email: '[email protected]' },
  metadata: { userId: '123' }
})

// 跳转到支付页面
window.location.href = checkout.checkout_url

功能特性

✨ 核心功能

  • 完整的类型支持 - 完整的 TypeScript 类型定义
  • 链式调用 - 支持链式调用 API
  • 错误处理 - 统一的错误处理和用户友好提示
  • Webhook 处理 - 内置 Webhook 验证和处理
  • 测试模式 - 完整的测试环境支持
  • 工具函数 - 丰富的辅助工具函数

🎯 支持的 API

  • Checkout API - 创建支付链接
  • Customer API - 客户管理
  • Product API - 产品管理
  • Subscription API - 订阅管理
  • Webhook API - Webhook 事件处理

使用示例

创建支付链接

import { createCreemClient } from '@/lib/creem'

const client = createCreemClient()

const checkout = await client.checkouts.create({
  productId: 'prod_abc123',
  units: 1,
  successUrl: 'https://example.com/checkout/success',
  customer: {
    email: '[email protected]'
  },
  metadata: {
    userId: '123',
    plan: 'pro'
  },
  customField: [
    {
      type: 'text',
      key: 'company_name',
      label: 'Company Name',
      optional: true
    }
  ]
})

console.log('Checkout URL:', checkout.checkout_url)

获取结账信息

const checkout = await client.checkouts.retrieve('ch_abc123')
console.log('Status:', checkout.status)
console.log('Customer:', checkout.customer)

创建客户门户链接

const portal = await client.customers.createBilling({
  customerId: 'cust_abc123',
  returnUrl: 'https://example.com'
})

console.log('Customer Portal URL:', portal.billing_url)

获取产品信息

const product = await client.products.retrieve('prod_abc123')
console.log('Product Name:', product.name)
console.log('Price:', product.price)

列出所有产品

const products = await client.products.list({
  status: 'active',
  billingType: 'recurring'
})

console.log('Products:', products.data)

管理订阅

// 获取订阅信息
const subscription = await client.subscriptions.retrieve('sub_abc123')

// 更新订阅
await client.subscriptions.update('sub_abc123', {
  units: 5
})

// 升级订阅
await client.subscriptions.upgrade('sub_abc123', {
  productId: 'prod_xyz789',
  proration: true
})

// 取消订阅
await client.subscriptions.cancel('sub_abc123')

Webhook 处理

import { WebhookHandler, WEBHOOK_EVENTS } from '@/lib/creem'

// 创建 Webhook 处理器
const handler = new WebhookHandler({
  webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
  handlers: {
    'checkout.completed': async (data) => {
      console.log('Checkout completed:', data)
      // 处理结账完成逻辑
    },
    'subscription.created': async (data) => {
      console.log('Subscription created:', data)
      // 处理订阅创建逻辑
    },
    'subscription.canceled': async (data) => {
      console.log('Subscription canceled:', data)
      // 处理订阅取消逻辑
    }
  },
  onError: (error, event) => {
    console.error('Webhook error:', error)
    // 处理错误
  }
})

// 在 Next.js API 路由中使用
export async function POST(request: Request) {
  return handler.handle(request)
}

工具函数使用

import {
  verifyWebhookSignature,
  getProductId,
  formatAmount,
  isTestMode,
  isValidProductId
} from '@/lib/creem'

// 验证 Webhook 签名
const isValid = verifyWebhookSignature(
  payload,
  signature,
  webhookSecret
)

// 获取产品 ID
const productId = getProductId('pro', 'monthly')

// 格式化金额
const formatted = formatAmount(1999, 'USD') // '$19.99'

// 判断是否为测试环境
if (isTestMode()) {
  console.log('Running in test mode')
}

// 验证产品 ID
const isValid = isValidProductId('prod_abc123')

Next.js 集成示例

API 路由示例

// app/api/checkout/route.ts
import { createCreemClient, CreemError } from '@/lib/creem'
import { NextRequest, NextResponse } from 'next/server'

export async function POST(request: NextRequest) {
  try {
    const body = await request.json()

    // 创建客户端
    const client = createCreemClient()

    // 创建支付链接
    const checkout = await client.checkouts.create({
      productId: getProductId(body.plan, body.billing),
      successUrl: `${process.env.NEXT_PUBLIC_SITE_URL}/checkout/success`,
      customer: body.email ? { email: body.email } : undefined,
      metadata: {
        plan: body.plan,
        billing: body.billing,
      },
    })

    return NextResponse.json(checkout)
  } catch (error) {
    if (error instanceof CreemError) {
      return NextResponse.json(
        { error: error.getUserMessage() },
        { status: error.statusCode || 500 }
      )
    }

    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    )
  }
}

Webhook 路由示例

// app/api/webhooks/creem/route.ts
import { WebhookHandler } from '@/lib/creem'

const handler = new WebhookHandler({
  webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
  handlers: {
    'checkout.completed': async (data) => {
      console.log('Checkout completed:', data)

      // 更新数据库
      // await db.orders.update({...})
    },
    'subscription.created': async (data) => {
      console.log('Subscription created:', data)

      // 创建用户订阅记录
      // await db.subscriptions.create({...})
    },
    'subscription.canceled': async (data) => {
      console.log('Subscription canceled:', data)

      // 取消用户订阅
      // await db.subscriptions.update({...})
    }
  },
  onError: (error, event) => {
    console.error('Webhook error:', error, event)
  }
})

export async function POST(request: Request) {
  return handler.handle(request)
}

前端组件示例

// components/Pricing.tsx
'use client'

import { useState } from 'react'
import { createCreemClient, CreemError } from '@/lib/creem'

export function Pricing() {
  const [loading, setLoading] = useState(false)

  const handleSubscribe = async (plan: string, billing: string) => {
    setLoading(true)
    try {
      const response = await fetch('/api/checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ plan, billing }),
      })

      const data = await response.json()

      if (data.checkout_url) {
        // 跳转到支付页面
        window.location.href = data.checkout_url
      } else {
        throw new Error(data.error || 'Failed to create checkout')
      }
    } catch (error) {
      console.error('Checkout error:', error)
      alert(error instanceof Error ? error.message : 'Failed to initiate checkout')
    } finally {
      setLoading(false)
    }
  }

  return (
    <button
      onClick={() => handleSubscribe('pro', 'monthly')}
      disabled={loading}
    >
      {loading ? 'Processing...' : 'Start Pro Trial'}
    </button>
  )
}

测试模式

测试卡片

使用以下测试卡片号进行测试:

| 卡片号 | 描述 | |--------|------| | 4242 4242 4242 4242 | 成功支付 | | 4000 0000 0000 0002 | 卡片被拒绝 | | 4000 0000 0000 9995 | 余额不足 | | 4000 0000 0000 0127 | CVC 错误 | | 4000 0000 0000 0069 | 卡片过期 |

注意:所有测试卡片都可以使用任何未来日期、任何 CVC 和任何账单信息。

切换测试/生产模式

Creem Dashboard 顶部导航栏点击 "Test Mode" 切换。

重要提示: 测试环境和生产环境使用不同的 API 密钥和产品 ID。

错误处理

import { createCreemClient, CreemError } from '@/lib/creem'

const client = createCreemClient()

try {
  await client.checkouts.create({...})
} catch (error) {
  if (error instanceof CreemError) {
    // 判断错误类型
    if (error.isAuthError()) {
      console.log('认证失败')
    } else if (error.isNotFoundError()) {
      console.log('资源不存在')
    } else if (error.isRateLimitError()) {
      console.log('请求过于频繁')
    }

    // 获取用户友好的错误消息
    console.log(error.getUserMessage())
  }
}

API 参考

CreemClient

方法

| 方法 | 说明 | |------|------| | checkouts.create(params) | 创建支付链接 | | checkouts.retrieve(id) | 获取结账信息 | | customers.createBilling(params) | 创建客户门户链接 | | customers.retrieve(id) | 获取客户信息 | | customers.retrieveByEmail(email) | 根据邮箱获取客户 | | products.retrieve(id) | 获取产品信息 | | products.list(params) | 列出产品 | | subscriptions.retrieve(id) | 获取订阅信息 | | subscriptions.update(id, params) | 更新订阅 | | subscriptions.upgrade(id, params) | 升级订阅 | | subscriptions.cancel(id) | 取消订阅 |

工具函数

| 函数 | 说明 | |------|------| | verifyWebhookSignature(payload, signature, secret) | 验证 Webhook 签名 | | parseWebhookEvent(payload) | 解析 Webhook 事件 | | getProductId(plan, billing) | 获取产品 ID | | formatAmount(amount, currency) | 格式化金额 | | isTestMode() | 判断是否为测试环境 | | getApiEndpoint() | 获取 API 端点 | | isValidProductId(productId) | 验证产品 ID 格式 | | generateRequestId() | 生成请求追踪 ID | | createSuccessUrl(baseUrl, path, params) | 创建成功跳转 URL |

常见问题

Q: 如何获取 API Key?

A: 访问 Creem Dashboard,进入 Developers > API Keys 创建 API 密钥。测试密钥以 creem_test_ 开头,生产密钥以 creem_sk_ 开头。

Q: 测试环境和生产环境的区别?

A:

  • 测试环境:使用测试 API Key 和测试卡片,不会产生真实费用
  • 生产环境:使用生产 API Key,处理真实支付
  • 两个环境使用不同的 API 端点、API Key 和产品 ID

Q: 如何验证 Webhook 签名?

A: 使用 verifyWebhookSignature 函数验证签名,或使用 WebhookHandler 类自动处理验证。

Q: 支付成功后如何处理?

A: 通过 Webhook 监听 checkout.completed 事件,或在用户跳转回成功页面时查询结账状态。

Q: 如何处理退款?

A: 在 Creem Dashboard 中手动处理退款,或通过 Webhook 监听相关事件。

相关资源

许可证

MIT

支持

如有问题,请提交 Issue 或联系 Creem 官方支持。


发布到 npm

快速发布

cd lib/creem
npm run build
npm publish

详细发布指南请参考:

发布前准备

  1. 更新 package.json

    • 修改包名:@your-org/creem-sdk
    • 更新作者信息
    • 更新仓库链接
  2. 构建 TypeScript

    npm run build
  3. 验证构建输出

    • 检查 dist/ 目录
    • 确认所有文件正确生成
  4. 发布到 npm

    npm login
    npm publish

当前包配置

{
  "name": "@your-org/creem-sdk",
  "version": "1.0.0",
  "description": "Modular Creem Payment SDK for TypeScript/JavaScript projects",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "publishConfig": {
    "access": "public"
  }
}

发布检查清单

  • [ ] 已更新 package.json 中的包名和作者信息
  • [ ] 已更新版本号
  • [ ] 已运行 npm run build 成功
  • [ ] dist 目录包含所有必需文件
  • [ ] README.md 文档完整
  • [ ] LICENSE 文件存在
  • [ ] 已登录 npm