# @erquhart/convex-polar 中文文档

规范地址：https://npmcn.com/package/%40erquhart/convex-polar/

版本：0\.4\.1
npm 元数据更新时间：2025-03-27T19:58:39.248Z
中文译文更新时间：2026-11-13T21:30:48.988Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40erquhart/convex-polar
原文对照：https://npmcn.com/package/%40erquhart/convex-polar/?lang=original
项目主页：https://github.com/erquhart/convex-polar#readme
源码仓库：https://github.com/erquhart/convex-polar

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：411 kB，94 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：6 个
- peer 依赖：convex ^1\.19\.2，react ^18，react-dom ^18
- 首次发布：2024-11-14T00:28:54.511Z
- 最新版本发布：2025-03-27T19:58:39.086Z
- 近 30 天下载量：4377（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 0 个）

## 中文简介

Convex 的极性组件 .

## 安装

```sh
npm install @erquhart/convex-polar
```

也可以使用：`pnpm add @erquhart/convex-polar`、`yarn add @erquhart/convex-polar`、`bun add @erquhart/convex-polar`

## README

# Convex 极地组件 [![npm version](https://badge.fury.io/js/@convex-dev%2Fpolar.svg)](https://badge.fury.io/js/@convex-dev%2Fpolar)

在您的 Convex 应用程序中添加订阅和账单 [极点](https://polar.sh/)。 。 。 .

**看看这个 [示例应用程序](https://npmcn.com/package/%40erquhart/convex-polar/example) 一个完整的例子.**

```tsx
// Get subscription details for the current user
const {
  productKey,
  status,
  currentPeriodEnd,
  currentPeriodStart,
  ...
} = await polar.getCurrentSubscription(ctx, {
  userId: user._id,
});

// Show available plans
<CheckoutLink
  polarApi={api.example}
  productIds={[products.premiumMonthly.id, products.premiumYearly.id]}
  // Optional: turn off embedding to link to a checkout page
  embed={false}
>
  Upgrade to Premium
</CheckoutLink>

// Manage existing subscriptions
<CustomerPortalLink polarApi={api.example}>
  Manage Subscription
</CustomerPortalLink>
```

## 先决条件

### Convex 应用程序

你需要一个Convex App来使用组件. 跟着任何 [Convex 快速启动](https://docs.convex.dev/home) 来设置一个.

### 极账户

-   [创建极账户](https://polar.sh/)
-   创建一个组织并创建一个组织标志,并有权限:
    -   `products:read`
    -   `products:write`
    -   `subscriptions:read`
    -   `subscriptions:write`
    -   `customers:read`
    -   `customers:write`
    -   `checkouts:read`
    -   `checkouts:write`
    -   `checkout_links:read`
    -   `checkout_links:write`
    -   `customer_portal:read`
    -   `customer_portal:write`
    -   `customer_sessions:write`

## 安装

安装组件包 :

```ts
npm install @convex-dev/polar
```

创建一个 `convex.config.ts` 应用程序中的文件 `convex/` 文件夹并安装 通过调用 `app.use`数字 :

```ts
// convex/convex.config.ts
import { defineApp } from "convex/server";
import polar from "@convex-dev/polar/convex.config";

const app = defineApp();
app.use(polar);

export default app;
```

设置您的极组织符号 :

```sh
npx convex env set POLAR_ORGANIZATION_TOKEN xxxxx
```

## 使用量

### 设置极地网点

极地组件使用webhooks保持订阅数据同步. 你将需要:

1.  在极地仪表板上创建一则网钩和网钩秘密,使用您 [汇流站点 網址](https://docs.convex.dev/production/environment-variables#system-environment-variables) + 键 `/polar/events` 作为网点。 应该是这样的 `https://verb-noun-123.convex.cloud/polar/events`
    
    启用以下事件 :
    
    -   `product.created`
    -   `product.updated`
    -   `subscription.created`
    -   `subscription.updated`
2.  设置您的 Convex 环境中的 Webhook 密钥 :
    

```sh
npx convex env set POLAR_WEBHOOK_SECRET xxxxx
```

3.  在您的网页处理器中注册 `convex/http.ts`数字 :

```ts
import { httpRouter } from "convex/server";
import { polar } from "./example";

const http = httpRouter();

// Register the webhook handler at /polar/events
polar.registerRoutes(http as any);

export default http;
```

您也可以为 Webhook 事件提供召回:

```ts
polar.registerRoutes(http, {
  // Optional custom path, default is "/events/polar"
  path: "/events/polar",
  // Optional callbacks for webhook events
  onSubscriptionUpdated: async (ctx, event) => {
    // Handle subscription updates, like cancellations.
    // Note that a cancelled subscription will not be deleted from the database,
    // so this information remains available without a hook, eg., via
    // `getCurrentSubscription()`.
    if (event.data.customerCancellationReason) {
      console.log("Customer cancelled:", event.data.customerCancellationReason);
    }
  },
  onSubscriptionCreated: async (ctx, event) => {
    // Handle new subscriptions
  },
  onProductCreated: async (ctx, event) => {
    // Handle new products
  },
  onProductUpdated: async (ctx, event) => {
    // Handle product updates
  },
});
```

4.  一定要运行 `npx convex dev` 用极点启动您的 Convex 应用程序 启用组件, 它将将 Webhook 处理器部署到您的 Convex 举个例子.

### 在极地创建产品

在极地仪表板上为您想要的每个定价计划创建产品 提供。 产品数据将自动同步到您的 Convex 应用程序 .

**说明:** 你每个计划可以有一个价格, 所以计划每月和每年 定价需要极地的两个产品.

**说明:** Convex 极地部分目前正在建设,以支持经常性 订户,不得按预期一次性付款。 请 [打开一个问题](https://github.com/convex-dev/polar/issues) 或者说 [在 Discord 上访问](https://discord.gg/convex) 如果你遇到任何问题.

### 初始化极端客户端

在 Convex 后端创建极端客户端 :

```ts
// convex/example.ts
import { Polar } from "@convex-dev/polar";
import { api, components } from "./_generated/api";
import { DataModel } from "./_generated/dataModel";

export const polar = new Polar(components.polar, {
  // Required: provide a function the component can use to get the current user's ID and
  // email - this will be used for retrieving the correct subscription data for the
  // current user. The function should return an object with `userId` and `email`
  // properties.
  getUserInfo: async (ctx) => {
    const user = await ctx.runQuery(api.example.getCurrentUser);
    return {
      userId: user._id,
      email: user.email,
    };
  },
  // Optional: Configure static keys for referencing your products.
  // Alternatively you can use the `listAllProducts` function to get
  // the product data and sort it out in your UI however you like
  // (eg., by price, name, recurrence, etc.).
  // Map your product keys to Polar product IDs (you can also use env vars for this)
  // Replace these keys with whatever is useful for your app (eg., "pro", "proMonthly",
  // whatever you want), and replace the values with the actual product IDs from your
  // Polar dashboard
  products: {
    premiumMonthly: "product_id_from_polar",
    premiumYearly: "product_id_from_polar",
    premiumPlusMonthly: "product_id_from_polar",
    premiumPlusYearly: "product_id_from_polar",
  },
  // Optional: Set Polar configuration directly in code
  organizationToken: "your_organization_token", // Defaults to POLAR_ORGANIZATION_TOKEN env var
  webhookSecret: "your_webhook_secret", // Defaults to POLAR_WEBHOOK_SECRET env var
  server: "sandbox", // Optional: "sandbox" or "production", defaults to POLAR_SERVER env var
});

// Export API functions from the Polar client
export const {
  changeCurrentSubscription,
  cancelCurrentSubscription,
  getConfiguredProducts,
  listAllProducts,
  generateCheckoutLink,
  generateCustomerPortalUrl,
} = polar.api();
```

### 显示产品和价格

使用导出 `getConfiguredProducts` 或者说 `listAllProducts`函数以显示您的产品及其价格:

#### `getConfiguredProducts`

```tsx
// Simple example of displaying products and prices if you've configured
// products by key in the Polar constructor
function PricingTable() {
  const products = useQuery(api.example.getConfiguredProducts);
  if (!products) return null;

  return (
    <div>
      {products.premiumMonthly && (
        <div>
          <h3>{products.premiumMonthly.name}</h3>
          <p>
            ${(products.premiumMonthly.prices[0].priceAmount ?? 0) / 100}/month
          </p>
        </div>
      )}
      {products.premiumYearly && (
        <div>
          <h3>{products.premiumYearly.name}</h3>
          <p>
            ${(products.premiumYearly.prices[0].priceAmount ?? 0) / 100}/year
          </p>
        </div>
      )}
    </div>
  );
}
```

#### `listAllProducts`

```tsx
// Simple example of displaying products and prices if you haven't configured
// products by key in the Polar constructor
function PricingTable() {
  const products = useQuery(api.example.listAllProducts);
  if (!products) return null;

  // You can sort through products in the client as below, or you can use
  // `polar.listAllProducts` in your own Convex query and return your desired
  // products to display in the UI.
  const proMonthly = products.find(
    (p) => p.prices[0].recurringInterval === "month"
  );
  const proYearly = products.find(
    (p) => p.prices[0].recurringInterval === "year"
  );
  return (
    <div>
      {proMonthly && (
        <div>
          <h3>{proMonthly.name}</h3>
          <p>
            ${(proMonthly.prices[0].priceAmount ?? 0) / 100}/
            {proMonthly.prices[0].recurringInterval}
          </p>
        </div>
      )}
      {proYearly && (
        <div>
          <h3>{proYearly.name}</h3>
          <p>${(proYearly.prices[0].priceAmount ?? 0) / 100}/year</p>
        </div>
      )}
    </div>
  );
}
```

每种产品包括:

-   `id`:极地产品ID
-   `name`: 产品名称
-   `prices`: 价格组合,与:
    -   `priceAmount`: 价格以美分计
    -   `priceCurrency`: 货币代码(如"USD")
    -   `recurringInterval`:"月"或"岁"

### 添加订阅 UI 组件

使用提供的 React 组件为您的应用程序添加订阅功能 :

```tsx
import { CheckoutLink, CustomerPortalLink } from "@convex-dev/polar/react";
import { api } from "../convex/_generated/api";

// For new subscriptions
<CheckoutLink
  // For our example, the api.example object includes the generateCheckoutLink
  // function. You can also pass any object that includes this function.
  polarApi={api.example}
  productIds={[products.premiumMonthly.id, products.premiumYearly.id]}
  // Optional: turn off embedding to link to a checkout page
  embed={false}
>
  Upgrade to Premium
</CheckoutLink>

// For managing existing subscriptions
<CustomerPortalLink
  polarApi={{
    generateCustomerPortalUrl: api.example.generateCustomerPortalUrl,
  }}
>
  Manage Subscription
</CustomerPortalLink>
```

### 处理订阅更改

极地组件提供处理用户更改的功能 当前用户.

**说明:** 强烈建议在 改变他们的订阅方式!

```ts
// Change subscription
const changeSubscription = useAction(api.example.changeCurrentSubscription);
await changeSubscription({ productId: "new_product_id" });

// Cancel subscription
const cancelSubscription = useAction(api.example.cancelCurrentSubscription);
await cancelSubscription({ revokeImmediately: true });
```

### 访问订阅数据

在您的应用程序中查询订阅信息 :

```ts
// convex/example.ts

// A query that returns a user with their subscription details
export const getCurrentUser = query({
  handler: async (ctx) => {
    const user = await ctx.db.query("users").first();
    if (!user) throw new Error("No user found");

    const subscription = await polar.getCurrentSubscription(ctx, {
      userId: user._id,
    });

    return {
      ...user,
      subscription,
      isFree: !subscription,
      isPremium:
        subscription?.productKey === "premiumMonthly" ||
        subscription?.productKey === "premiumYearly",
    };
  },
});
```

## API 参考

### 极端客户端

这个 `Polar` 类 接受配置对象 :

-   `getUserInfo`: 获取当前用户ID和电子邮件的函数
-   `products`: (可选) 任意命名的极地产品ID密钥地图
-   `organizationToken`: (可选)你的极地组织标志. 倒计时 `POLAR_ORGANIZATION_TOKEN` 环境 var
-   `webhookSecret`: (可选)你的极地网球秘诀. 倒计时 `POLAR_WEBHOOK_SECRET` 环境 var
-   `server`: (可选)极地服务器环境:"sandbox"或"生产". 倒计时 `POLAR_SERVER` 环境 var

### 反应组件

#### 退出链接

道具 :

-   `polarApi`: 含有 `generateCheckoutLink` 函数
-   `productIds`: 复选时要显示的产品标识组
-   `children`: 反应儿童(按钮内容)
-   `embed`: (可选)是否嵌入出账链接. 默认为 `true`。 。 。 .
-   `className`: (可选) CSS 类名

#### 客户端端链接

道具 :

-   `polarApi`: 含有 `generateCustomerPortalUrl` 函数
-   `children`: 反应儿童(按钮内容)
-   `className`: (可选) CSS 类名

### API 函数

#### 更改当前订阅

更改对新计划的现有订阅 :

```ts
await changeSubscription({ productId: "new_product_id" });
```

#### 取消当前订阅

取消已有的订阅 :

```ts
await cancelSubscription({ revokeImmediately: true });
```

#### 获取当前订阅

获取当前用户的订阅细节 :

```ts
const subscription = await polar.getCurrentSubscription(ctx, { userId });
```

#### 获得产品

列出所有现有产品及其价格:

```ts
const products = await polar.listProducts(ctx);
```

#### 登记册

登记极地组件的 Webhook 处理器 :

```ts
polar.registerRoutes(http, {
  // Optional: customize the webhook endpoint path (defaults to "/polar/events")
  path: "/custom/webhook/path",
});
```

Webhook 处理器使用 `webhookSecret` 从极端客户端配置或 `POLAR_WEBHOOK_SECRET` 环境变量.

## 常见问题

### @erquhart/convex-polar 是什么？

Convex 的极性组件 \.

### 如何安装 @erquhart/convex-polar？

在项目目录运行 npm install @erquhart/convex-polar，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：convex（^1\.19\.2）、react（^18）、react-dom（^18）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @erquhart/convex-polar 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @erquhart/convex-polar 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @erquhart/convex-polar 可以商用吗？

@erquhart/convex-polar 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @erquhart/convex-polar 的下载量有多少？

根据 npm 官方下载统计，@erquhart/convex-polar 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,377 次，日均约 146 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @erquhart/convex-polar 还在维护吗？

最新版本 0\.4\.1 发布于 2025/03/28（1\.6 年前）；至今共发布 15 个版本，其中过去 12 个月发布了 0 个；首次发布于 2024/11/14。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

