# @codelitdev/billing 中文文档

规范地址：https://npmcn.com/package/%40codelitdev/billing/

版本：0\.8\.2
npm 元数据更新时间：2026-11-09T11:09:41.202Z
中文译文更新时间：2026-11-10T07:04:32.159Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40codelitdev/billing
原文对照：https://npmcn.com/package/%40codelitdev/billing/?lang=original
项目主页：https://github.com/codelitdev/platform/tree/main/packages/billing#readme
源码仓库：https://github.com/codelitdev/platform

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

- 包体积（解压后）：892 kB，239 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：3 个
- peer 依赖：dodopayments ^2\.48\.0
- 首次发布：2026-08-31T07:19:56.182Z
- 最新版本发布：2026-11-09T11:09:40.888Z
- 近 30 天下载量：2970（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：16（近 12 个月 16 个）

## 中文简介

CodeLit产品供应商中性计费引擎

## 安装

```sh
npm install @codelitdev/billing
```

也可以使用：`pnpm add @codelitdev/billing`、`yarn add @codelitdev/billing`、`bun add @codelitdev/billing`

## README

# @ codelitdev/ billing (英语)

CodeLit产品提供商中性计费引擎. 它运行 **内部** 您的 API 进程针对 **** PostgreSQL数据库. 这不是一个托管的收费服务.

版本 **0.1.0-α.3 导弹**工作流程、行动赠款、运营商服务和生命周期钩 **实验**. 在第二个消费者(当然Lit)证明同一合同之前没有v1分期付款.

## 目的

CodeLit产品通过付款机构销售自己的SaaS(组织,学校,后为其他总量). 如果没有一个共享的引擎,每个产品都倾向于发展自己的目录,取出,网络呼和调节——这些副本在容易出错的部分上存在分歧.

这个包使这些力学标准化:

-   无法更改的版本价格目录与供应商核对
-   离职、客户门户、取消和计划变更
-   Webhook 校验、 耐用收件箱、 检索当前项目
-   订阅过渡、材料预测和对账租赁
-   供应商安全公共目录/商业状态读取模型
-   假的,多多,和柠檬斯克齐适配器 在一个合同后面

您的产品仍然拥有:

-   谁收帐(组织、学校、.)
-   计划名称、应享权利、配额、审判、优待、可用性
-   计划的改变是立即的还是延长的,如何按比例分配
-   Auth, CSRF, 近代代号, HTTP 路由, UI
-   Schema 迁移、回填、加密密钥、审计存储、提醒

软件包在安装、导入或处理启动时从未运行 DDL .

## 消费者准则

发动机为机械. 它不会从计划名称中推断出产品政策.

**你决定,然后通过:**

| 决定 | 你怎么告诉引擎 |
| --- | --- |
| 支付报价 | `offers` + 键 `requiredOfferKeys` 时间 `createBilling`; 准确设定, 不 `"free"` 内 `planIds` |
| 审判资格 | `trialDays` 退出(如果不符合资格,则为0)。 要求,HMAC,学校审判留在你的桌子上 |
| 升级与降级 | `startPlanChange({ effectiveAt, prorationMode })`。软件包不给Pro/Business排序 |
| 计划怎么解锁 | 你的权利解决者. `commercialState()` 只支付快照 |
| 实体生命周期 | `getBillableEntityBillingBlockers` 编号 : `getPayerBillingResponsibilities`;您选择了面向用户的错误 |
| 产品副作用 | `afterProjection` 编辑 **引擎交易** (单位:千美元)`store.getTransaction() ?? db`(中文(简体) ) |

**更改计划标记引擎所理解的:**

-   `effectiveAt`数字 : `immediately` | `next_billing_date`
-   `prorationMode`数字 : `prorated_immediately` | `do_not_bill`

声明提供者 `intervalChangesBillImmediately` 当计费间隔改变时, 开始并开出新账, 所以 `do_not_bill` 跨间隔失败 `plan_change_not_supported` 在提供方被调用之前。 声明提供者 `immediatePlanChangesOnly` 无法安排更改, 因此 `next_billing_date` 失败的方式相同.

典型的SaaS拆分(SendLit做什么,不需要):升级 → 即时+ 按比例;降级 → 下一张发票 + 不收帐. 直到一个网约车/和解快照 实际显示新产品, `commercialState().activePaidPlan` 留在当前计划中 `pendingPlanChange` 已经设定。 您的UI应该禁用第二次更改, 并说“ 被确认” 与“ 预定” .

**不许 :**

-   将应用程序Free/OSS/trial输入生成 `planIds`
-   拿着应用程序 `db.transaction()` 穿过一个服务商呼叫,或巢 `db.transaction()` 在内部的根池上 `afterProjection`
-   处理退出方向, `payment.succeeded`,或敬酒作为权利
-   重新解释路由中的供应商 SDK 错误; 映射 `BillingWorkflowError.code` 仅限
-   读取或写入计费状态 `billing.store`;它是发动机的内部

## 安装

```bash
bun add @codelitdev/billing@0.1.0-alpha.3
# or: bun add @codelitdev/billing@alpha
# Dodo is an optional peer of the Dodo adapter
bun add dodopayments
```

公共进口( 不导入) `src/`:

| 子路径 | 使用 |
| --- | --- |
| `@codelitdev/billing/config` | `defineBillingConfig` |
| `@codelitdev/billing/drizzle` | `createDrizzleBillingStore` |
| `@codelitdev/billing/workflows` | `createBilling` (实验性) |
| `@codelitdev/billing/operations` | 操作员检查/ 重试/ 取消 |
| `@codelitdev/billing/providers` | 登记、假合同类型 |
| `@codelitdev/billing/providers/dodo` | `createDodoBillingProvider` |
| `@codelitdev/billing/providers/lemonsqueezy` | `createLemonSqueezyBillingProvider` |
| `@codelitdev/billing/core` | 状况、金钱、错误、时钟 |
| `@codelitdev/billing/catalog` | 提供验证/ 公共目录 |
| `@codelitdev/billing/testing` | 供应商合同+工作流程利用 |

CLI: 爱丽丝

```bash
bun x codelit-billing generate --config billing.config.ts
bun x codelit-billing generate --check --config billing.config.ts
```

## 如何融为一体

```
Your API / UI
  auth, grants, plan policy, entitlements
       │
       ▼
  createBilling  ──► catalog + state machines
                 ──► provider adapter (Dodo / fake)
                 ──► Drizzle store ──► your Postgres
                 ──► your audit + afterProjection hooks
```

在实践中重要的六边规则:

-   核心从不读 `process.env` 或者墙壁时间。 你注射一个 `Clock` 和提供者选项.
-   无法通过服务商 HTTP 呼叫进行数据库交易 。 持久退出 / webhook / 工作行弥合了这一差距.
-   一个经过验证的网球是唤醒。 只有在 `retrieveSubscription` 和材料快照diff.
-   云构成需要审计钩和回URL许可列表.

## 1\. 说明计划a (`billing.config.ts`(中文(简体) )

与"Better Auth"相同的想法:软件包拥有Canonical模型;您检查生成的TypeScript,并通过细雨-kit拥有SQL.

```ts
import { defineBillingConfig } from "@codelitdev/billing/config";

export default defineBillingConfig({
    dialect: "postgresql",
    adapter: "drizzle",
    output: "./src/db/schema/billing.generated.ts",
    billableEntity: {
        modelName: "organization",
        tableImport: "./organizations",
        tableExport: "organizations",
        idColumn: "id",
        idType: "uuid",
        onDelete: "restrict",
    },
    payer: {
        modelName: "user",
        tableImport: "./auth",
        tableExport: "user",
        idColumn: "id",
        idType: "text",
        onDelete: "restrict",
    },
    planIds: ["pro", "business"],
    requiredOfferKeys: [
        "pro_month",
        "pro_year",
        "business_month",
        "business_year",
    ],
    additionalFields: {
        checkoutAttempts: {
            pendingTeamName: { type: "text", nullable: true },
        },
    },
});
```

`planIds` 为: **已支付** 计划一直坚持在犬行。 免费计划或无卡试验留在您的桌子上 `"free"` 在这里.

然后说:

```bash
bun x codelit-billing generate --config apps/api/billing.config.ts
bun x drizzle-kit generate
bun x drizzle-kit migrate
```

CI 应该运行 `generate --check` 承诺 `billing.generated.ts` 无法漂移。 手编辑 SQL 用于回填( 例如种子一个 Free) `billing_plan_states` 行; 从不编辑生成的 TypeScript .

实例: `examples/reference-product/`, (中文(简体) ), `examples/consumers/sendlit/`。 。 。 .

## 2\. 制作引擎

解开你自己的地窖 已键入多多选项 。 电线 Drizzle, 赠款,加密, 和产品效果.

当有多个产品共享一款多多业务时,多多将每个事件发送到每个webhook端点. 给每个产品自己的道多品牌, 创建自己的产品在这个品牌之下,并设定 `brandId`网络用户 `brand_id` 另一个品牌被存储为 `ignored`:它们被保存用于分解,但从未加工、再试验或隔离。 网络呼喊没有 `brand_id` 和以前一样处理。 见 [ADR 0009 (韩语)](https://npmcn.com/package/docs/decisions/0009-dodo-brand-webhook-filtering.md)。 。 。 .

要通过柠檬汁来销售, 做曲 `createLemonSqueezyBillingProvider` 从 `@codelitdev/billing/providers/lemonsqueezy` 与 `apiKey`,产品 `storeId`,和商店的 webhook `webhookSecrets`设置 `checkoutProvider: "lemonsqueezy"`. Catalog 提供莱蒙 Squeezy 变体 ID 名称为 `providerProductId`。来自其他商店的 Webhooks 存储为 `ignored`. 试验来自变体,所以退出 `trialDays`; 立即适用计划修改,以及 `do_not_bill` 被拒绝更改到另一个间隔, 因为柠檬挤压的账单是一次性的。 关闭商店客户端设置中的计划更改: 引擎隔离一个没有开始的计划更改, 以及该订阅的后期webhooks.

```ts
import { systemClock } from "@codelitdev/billing/core";
import { createDrizzleBillingStore } from "@codelitdev/billing/drizzle";
import { createBilling } from "@codelitdev/billing/workflows";
import { createDodoBillingProvider } from "@codelitdev/billing/providers/dodo";
import { db } from "./db/client";
import * as billingSchema from "./db/billing.generated";

const clock = systemClock;
const store = createDrizzleBillingStore(db, {
    schema: billingSchema,
    clock,
    planStateDefaults: { plan: "free", rampStage: 0, rampCleanStageDays: 0 },
    checkoutApplicationFields: {
        toColumns: (fields) => ({
            pendingTeamName:
                typeof fields.pendingTeamName === "string"
                    ? fields.pendingTeamName
                    : null,
        }),
        fromRow: (row) => ({ pendingTeamName: row.pendingTeamName ?? null }),
    },
});

export const billing = createBilling({
    database: store,
    providers: [
        createDodoBillingProvider({
            apiKey: process.env.DODO_PAYMENTS_API_KEY!,
            environment: "test_mode", // or "live_mode"
            webhookSecrets: [
                {
                    version: "current",
                    secret: process.env.DODO_PAYMENTS_WEBHOOK_KEY_CURRENT!,
                },
            ],
            // Your product's Dodo brand. Other brands' webhooks are ignored.
            brandId: process.env.DODO_BRAND_ID,
            clock,
        }),
    ],
    clock,
    authorization: yourGrantPort, // consume-once BillingAuthorizationPort
    sensitiveValues: yourEncryptPort,
    hooks: {
        audit: yourAuditHook,
        lifecycle: {
            afterProjection: (input) =>
                applyProductEffects(input, store.getTransaction() ?? db),
        },
    },
    mode: "cloud", // "oss" forbids providers, offers, and catalog revision
    checkoutProvider: "dodo",
    requestedRevision: 1,
    requiredOfferKeys: [
        "pro_month",
        "pro_year",
        "business_month",
        "business_year",
    ],
    offers: yourOffers, // must match requiredOfferKeys exactly
    returnUrlValidator: (url) =>
        new URL(url).origin === new URL(process.env.WEB_CLIENT!).origin,
});
```

`afterProjection` 运行 **内部** 发动机交易 使用 `store.getTransaction() ?? db` 和做( 做) **没有** 打开巢穴 `db.transaction()` 在根池客户端上—— 僵持状态 `FOR UPDATE` 作行相会. 如果您通过引擎客户端, 请在引擎客户端上写; 只有收到根时才有巢 `db`。 。 。 .

开放源码软件模式 : `mode: "oss"`,空的供应商, `checkoutProvider: ""`, (中文(简体) ), `requestedRevision: null`没有报价。 引擎拒绝退票; 您的产品会自动解锁付费能力 .

## 3\. 启动时的目录

云启动验证配置形状 **记录** 请求的修订。 它不能阻止 Dodo 的普通API 准备状态 .

```ts
await billing.recordRequestedCatalog();
// later, from a worker / sweep — not on the hot health path
await billing.verifyRequestedCatalog();
```

只有在要求的修订得到核实时,才可进行离职 **活动** 修订。 待决或无效的请求集 `checkoutAvailable: false` 最后经核实的修订仍然是商业预测。 运算符放弃错误请求 `abandonRequestedCatalog` 返回配置后.

在创建提供者会话之前, 立即重新检查选中的产品 。 错配会冻结新的取出; 现有的订阅者会保存上次核实的映射 .

## 4\. 人类收费行动

您的应用认证用户, 证明最近 认证 / CSRF , 不管你喜欢什么, 然后发布一个 **单用途** `BillingActionGrant`。引擎消耗赠款 **财务报告和审定财务报表** 检查坚持付款人。 新的补助金不能将付款人换到现有的客户或订阅者.

```ts
const { checkoutUrl } = await billing.startCheckout({
    grant,
    entity: { kind: "organization", id: organizationId },
    payer: { id: userId, email, name },
    offerKey: "pro_month",
    catalogRevision: displayedRevision, // the revision the UI showed
    returnUrl,
    trialDays: 14, // 0 if ineligible; the package does not decide eligibility
    applicationFields: { pendingTeamName: "Acme Team" },
});
```

一个实体每次有一个开放式的离职,一个小时后失效. 再次开始相同报价的退票 。 如果同一付款人选择了另一个报价,例如每月一次,则该报价将取代开放式报价。 旧的退票变成了 `abandoned`,以及支持其过期时关闭页面的提供者。 如果它已经支付,它会变成 `conflicted`:它允许在没有其他情况下进入,否则第二次订阅对操作员进行隔离。 当另一个付款人的退票是开放的, `startCheckout` 失败 `checkout_pending`。 。 。 .

其他赠款行动: `startPortal`, (中文(简体) ), `cancel`,并修改计划:

```ts
await billing.startPlanChange({
    grant,
    entity: { kind: "organization", id: organizationId },
    payer: { id: userId, email, name },
    offerKey: "business_month",
    catalogRevision: displayedRevision,
    effectiveAt: "immediately", // or "next_billing_date"
    prorationMode: "prorated_immediately", // or "do_not_bill"
});
```

提交用户看到的目录修订; 一个 stale 修订失败 `catalog_changed` 并可能包括目前的公共目录.

`cancel`, (中文(简体) ), `resumeCancellation`,以及 `startPlanChange` 更改后从提供者读取订阅, 所以 `commercialState` 反映在网络呼声到来之前. `cancel` 付款期结束时的注销。 订阅时将保留应享权利来源,直到 `paidThroughAt`,以及 `commercialState` 报告 `cancelAtPeriodEnd: true` 同时,显示结束日期并提议恢复. `resumeCancellation` 清除计划取消并使用 `cancellation` 赠款。 期限一结束,提供者的网页钩或 `runDeadlineBatch` 取消权利。 见 [ADR 0010 (英语)](https://npmcn.com/package/docs/decisions/0010-cancel-at-period-end.md)。 。 。 .

```ts
const state = await billing.commercialState(organizationId);
if (state.cancelAtPeriodEnd) {
    // "Pro stays active until {state.paidThroughAt}" and a resume button
}
await billing.resumeCancellation({ grant, entity, payer });
```

重新定向不是支付。 由webhook投影或对账产生的应享权利变化。 预定的计划更改不会重写订阅, 直至提供者的当前快照符合即将进行的尝试 .

## 5\. 网络用户和工人

挂载每个提供者的网页 `POST /webhooks/billing/<provider>` 例如,在API上 `/webhooks/billing/dodo`。在每个产品中使用相同的路径,所以一个提供者的端点设置在产品中看起来是一样的.

保护 **原始内容** 躯体。 持久地插入事件后返回 2xx(包括复制件) 。 同步发射.

```ts
const ingested = await billing.ingestWebhook({
    provider: "dodo",
    raw: { body, headers },
});
res.status(ingested.duplicate ? 200 : 202).json({ accepted: true });
void billing.runWebhookInboxBatch({ workerId: `billing-${process.pid}` });
```

软件包不启动定时器 。 您的排程器应该打电话, 有独特的 `workerId`编号:

| 单位 | 任务 |
| --- | --- |
| `runWebhookInboxBatch` | 经排水核实的事件(回收+项目) |
| `runReconciliationBatch` | 排出卡住的退出, 计划更改, 和未调节的订阅( Q)`discover: false` ,然后运行队列任务 |
| `runDeadlineBatch` | 到期未结结结账; 过期未结付应享权利 |
| `purgeExpiredSensitiveValues` | 丢弃旧的加密取出 URL/ 重放有效载荷 |
| `verifyRequestedCatalog` | 完成目录修订 |

算什么被卡住了 就可以被装扮成 `createBilling({ reconciliation: { checkoutStaleAfterMs, planChangeStaleAfterMs, subscriptionStaleAfterMs } })`;默认时间为一分一小时. 每个未核对的订阅费用每个期间有一个供应商阅读.

多事件安全是数据库租赁,不是程序本地变种。 从不持有一个应用交易 通过一个提供者呼叫.

## 6\. 阅读模型

普通路线不得调用提供者.

```ts
const catalog = await billing.publicCatalog();
// { revision, checkoutAvailable, offers: [{ key, plan, interval, amountMinor, currency, displayTrialDays }] }
// no provider product IDs

const commercial = await billing.commercialState(organizationId);
// activePaidPlan, subscriptionStatus, periods, pendingCheckout / pendingPlanChange, projectionVersion

// Inside your own transaction, for example when reserving quota:
await db.transaction(async (tx) => {
    const locked = await billing.commercialState(organizationId, { transaction: tx });
    // the Drizzle store locks the rows it read until tx ends
});
```

`commercialState` 是有偿访问的真相来源。 它会重新检查时钟,所以计划取消 停止计酬一次 `paidThroughAt` 在提供商最后活动之前 `runDeadlineBatch`. 决定从中解锁什么计划;不将付费状态复制到产品表中并重新确定.

以你的审判,自由计划,配额,和 `canManageBilling`。 。 。 . `projectionVersion` 是缓存密钥; 等同的 webhook 重放仅更新新鲜度, 不递增 .

关闭/ 删除/ 所有人降级前, 呼叫 `getBillableEntityBillingBlockers` 编号 : `getPayerBillingResponsibilities` 在与变异相同的交易中。 软件包报告阻塞器; 您决定了显示用户的错误 .

工作流失败 `BillingWorkflowError` 带有稳定代码( :`catalog_changed`, (中文(简体) ), `payer_mismatch`, (中文(简体) ), `checkout_pending`在应用程序中将其映射到 HTTP 。 不要坚持原始 SDK 消息 .

## 7\. 运营商CLI

产品 CLI 调用 `createOperations`。每个变异需要 `OperatorContext` (单位:千美元)`actorId`边框 `reason`,可选票)并点击审计钩. 该包件不载运 Org/school CLI.

```ts
import { createOperations } from "@codelitdev/billing/operations";

const ops = createOperations({
    billing,
    clock,
    requestedRevision: 1,
    checkoutProvider: "dodo",
    sensitiveValues,
});

await ops.health();
await ops.inspectWebhook(providerEventId);
await ops.retryWebhook(ctx, providerEventId, "preserve_attempts"); // also drains the inbox
await ops.reconcileEntity(ctx, billableEntityId); // requires a local entitlement row
await ops.projectProviderSubscription(ctx, {
    providerSubscriptionId, // e.g. from the checkout return URL
    checkoutAttemptId, // optional; defaults to snapshot metadata
});
await ops.adoptProviderSubscription(ctx, {
    providerName: "lemonsqueezy",
    providerSubscriptionId, // started with the provider before this package
    entity: { kind: "organization", id: organizationId },
    payer: { id: userId, email },
});
await ops.requestCancellation(ctx, subscriptionId);
const payload = await ops.inspectWebhookReplay(ctx, providerEventId);
```

`adoptProviderSubscription` 接管在引擎外创建的订阅,例如产品使用此包之前的订阅. 它将供应商的客户与付款人联系起来,并预测订阅情况;之后,续约、取消、恢复和门户正常工作。 订阅的产品必须在提供者的活性目录中,为同一个实体再次采用是安全的. 见 [ADR 0014 (英语)](https://npmcn.com/package/docs/decisions/0014-lemon-squeezy-adapter-and-adoption.md)。 。 。 .

`reconcileEntity` 无法创建付费但未经预测的离职单的订阅。 使用 `projectProviderSubscription` 提供商已经持有订阅身份证明,本地权益仍然缺失.

别 `UPDATE billing_webhook_events SET status = 'pending'` 手边。 重试或保留尝试计数器或启动 `new_budget`。 。 。 .

程序: [`docs/runbooks.md`](https://npmcn.com/package/%40codelitdev/billing/docs/runbooks.md)。 。 。 .

## 8\. 测试

```ts
import {
    runBillingProviderContract,
    createWorkflowHarness,
} from "@codelitdev/billing/testing";
```

-   `runBillingProviderContract(adapter)` ——每个适配器,包括CI中的多多与假和有门的沙盒测试对多多测试模式.
-   `createWorkflowHarness()` ——编目,结账,网约车订购,赠款,对账不设网络.

`bun test` 是决定性的。 活度多多沙盒测试停留在显式地洞门后.

## 此软件包不会做什么

-   产品路线、ts-rest、MCP或UI
-   授权、成员、公司社会责任基金或发行行动标志
-   安装/ 导入/ 启动时自动 SQL
-   共享计费数据库
-   用量、税费或发票
-   把用户从一个供应商移动到另一个供应商
-   SendLit 名声、域名或“一个拥有的自由矿石”政策

## 版本

-   **0.1.0-alpha.x (英语)** ——实验工作流程. 公共核心/培训/提供者类型旨在保持稳定;工作流程/合同仍可改变。 安装 `alpha` 标记, 不 `latest`。 。 。 .
-   Schema-changing 软件包的放出会撞倒生成的 schema 版本. 升级:打击依赖性 `generate` \* 审查《服务贸易总协定》 \* `drizzle-kit generate` + 应用回填 + 在产品中迁移 + 部署相容的API/工人.
-   建筑和推出: [`docs/architecture.md`](https://npmcn.com/package/%40codelitdev/billing/docs/architecture.md). 采掘业差异: [`docs/decisions/0001-extraction-discrepancies.md`](https://npmcn.com/package/%40codelitdev/billing/docs/decisions/0001-extraction-discrepancies.md)。 。 。 .

## 开发此 repo

```bash
bun install
bun test
bun run typecheck
bun run build
bun run test:packed   # install the tarball via public exports only
```

## 常见问题

### @codelitdev/billing 是什么？

CodeLit产品供应商中性计费引擎

### 如何安装 @codelitdev/billing？

在项目目录运行 npm install @codelitdev/billing，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 codelit-billing，可以用 npx codelit-billing 直接运行。

### @codelitdev/billing 支持 TypeScript 吗？

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

### @codelitdev/billing 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @codelitdev/billing 可以商用吗？

@codelitdev/billing 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @codelitdev/billing 的下载量有多少？

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

### @codelitdev/billing 还在维护吗？

最新版本 0\.8\.2 发布于 2026/11/09（今天）；至今共发布 16 个版本，其中过去 12 个月发布了 16 个；首次发布于 2026/08/31。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

