# @krizaka/credits 中文文档

规范地址：https://npmcn.com/package/%40krizaka/credits/

版本：0\.1\.4
npm 元数据更新时间：2026-11-01T14:49:48.978Z
中文译文更新时间：2026-11-01T16:40:44.227Z
软件包许可：Apache-2\.0

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

原始 npm 页面：https://www.npmjs.com/package/%40krizaka/credits
原文对照：https://npmcn.com/package/%40krizaka/credits/?lang=original
项目主页：https://github.com/krizaka/krizaka-ts/tree/main/packages/credits
源码仓库：https://github.com/krizaka/krizaka-ts

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

- 包体积（解压后）：214 kB，18 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22
- 运行依赖：4 个
- peer 依赖：zod \>=3\.23，vitest \>=4
- 首次发布：2026-10-27T00:17:41.132Z
- 最新版本发布：2026-11-01T14:49:48.616Z
- 已发布版本数：6（近 12 个月 6 个）

## 中文简介

每个Krizaka产品都有一个信用分类账：每天和每月限额到期的赠款，购买，借记，退款，持有。扩展;平衡是推导出来的。同时消费永远不会为负，也不会花费两次。没有数据库客户机，没有

## 安装

```sh
npm install @krizaka/credits
```

也可以使用：`pnpm add @krizaka/credits`、`yarn add @krizaka/credits`、`bun add @krizaka/credits`

## README

# @krizaka /学分

**每个Krizaka产品都有一个信用分类账。** 它取代了三种型号：Yomizaka的 `audit_credits` 和 `free_audit_used_at` 列在 `accounts` （`reserveAudit` / `releaseAudit` / `refundFailedAudit`)，以及Java工具包 `credit_wallet` / `credit_ledger_entry` / `credit_hold` （`krizaka-billing`，后面跟着他们的名字和事件)。优惠券模块（#46）通过它授予上限积分。

> **分类帐只是附注，余额是派生出来的。** 没有什么东西能储存可以漂移的平衡：罐子剩下的是它的线条之和。数据库触发器拒绝任何 `UPDATE` 或者 `DELETE` 一行的。积分是整数，而不是浮点数。

```ts
import { emitMigration, transaction } from "@krizaka/db";
import { createCredits, creditsSchema } from "@krizaka/credits";
import { creditsSettings, readCreditsSettings } from "@krizaka/credits/settings";

emitMigration(creditsSchema, 1, { tables: { owner: "accounts" } }); // commit the SQL once, in your migrations

const credits = createCredits({ clock, settings: () => readCreditsSettings((key) => settings.get(key)), outbox });

await transaction(connect, async (tx) => {
  // a coupon's free credits: 20 audits, at most 5 a day, then stop; they lapse in 30 days
  await credits.grant(tx, { accountId, amount: 20, capPerDay: 5, expiresAt, onExhausted: "stop", source: `coupon:${redemptionId}`, idempotencyKey: `redeem-${redemptionId}` });
  // credits bought (the payment webhook, in the event's transaction)
  await credits.purchase(tx, { accountId, amount: 10, source: `purchase:${paymentRef}`, idempotencyKey: `pay-${paymentRef}` });
});

// spending: it refuses with a typed code, writes nothing when it refuses, and a replay of the key spends nothing more
const { draws } = await credits.consume(tx, { accountId, amount: 1, reason: `audit:${auditId}`, idempotencyKey: `audit-${auditId}` });
await credits.refund(tx, { accountId, consumed: `audit-${auditId}`, reason: "the run failed" }); // back to the same pots, once
```

## 该模型

-   **两种锅。** 一、 **授予** 锅是免费使用的（优惠券，津贴，演示）：它总是 **到期**，可能会被封顶 **每天** 和 **每个月**，并说明用完后会发生什么： `stop` 或者 `fallback_paid`． 一个 **购买** Pot不会过期，也不会封顶。
-   **`consume(tx, { accountId, amount, reason, idempotencyKey })`** 从授予的POTS中提取 **第一个到期**，然后从购买的积分中扣除。没有什么是片面的：它涵盖了全部或拒绝。
    -   越过锅盖： `CREDITS_CAP_DAY` / `CREDITS_CAP_MONTH` （合理使用限制：购买的积分不绕过它；另一个被授予的锅仍然可以服务）；
    -   一个 `stop` 空锅： `CREDITS_EXHAUSTED`，即使存在购买积分；
    -   一个 `fallback_paid` 锅是空的：它移动到购买的积分，然后回答 `PAYWALL`；
    -   没有学分： `PAYWALL`. 拒绝是 `CreditsError`S和a `code` 和HTTP `status` 路线可以回答（402 / 429）。
-   **成立。** `hold` 为正在进行的工作保留积分（它计入上限和余额，并在之后到期） `credits.holdTtlSeconds`); `settle(holdId, { amount? })` 花费工作的成本（最多是保留），并释放其余部分； `release` 释放一切。一旦每个;重播回答第一个结果。
-   **`refund`** 将一次消费（或固定持有）所花的钱返还给相同的锅。 **`expire(grantId)`** 注销剩下的钱（一张作废的优惠券：已经消费的积分永远不会收回）； **`expireDue`** 在一个工作中扫掉掉了的锅。 **`adjust`** 是管理员的签名更正，从不低于零。
-   **`balance`** 是 `{ total, granted, purchased, held, available, grants[] }`派生的; **`history`** 先写最新的行。
-   **幂等性。** 每次写信都需要一把钥匙；操作的行是 `<kind>.<key>:<n>` （在数据库中唯一）。密钥在每个分类账中是唯一的，而不是每个帐户：使用id（付款ref，作业id）。已使用的密钥 **另一个账户** 被拒绝了(`CREDITS_KEY_REUSED`）. 键不带冒号。
-   **并发性。** 每个作家都会 `pg_advisory_xact_lock` 首先在帐户上，然后读取并决定：最后一个信用的并发消费永远不会为负，上限在负载下保持，并且多次发送的一个键花费一次（所有在PostgreSQL上证明，在循环中）。
-   **日期和月份** 在管理员的IANA区域中被PostgreSQL删除(`credits.timeZone`、默认 `America/Toronto`)，所以夏令时是数据库自己的时区数据；“今天”来自注入时钟。
-   **事件** (通过 `@krizaka/outbox`，在调用者的事务中，从事实派生的id，因此每个都宣布一次)： `evt.credit.granted.v1` 和 `evt.credit.exhausted.v1`的名字 `krizaka-billing-api`，每个都有一个JSON模式(`CREDIT_EVENT_SCHEMAS`）。
-   **设置** （`@krizaka/credits/settings`): `credits.timeZone` （在运行时的IANA区域中进行选择）和 `credits.holdTtlSeconds` (900年,30 - 86400)。
-   **表** （`creditsSchema`、Postgres模式 `credits`): `grant`， `entry`， `hold`． 它引用的一个产品表是所有者(`owner`（帐户表）。有信用的账户是 **匿名，从未删除**它是一种会计记录，就像发票一样。
-   `creditsLedgerContract` （`@krizaka/credits/testkit`)是每个商店的合同； `memoryCreditStore()` 是用于单元测试的(它没有事务，所以 `lock` 不做任何事情：并发性是在PostgreSQL上证明的)。

## 采用它（Yomizaka）

`audit_credits` 变成购买的锅(`purchase` 每个账户的余额，键 `import-<accountId>`)，免费审核是一项授予的工作 `onExhausted: "fallback_paid"`， `reserveAudit` 一个 `consume` (一个 `PAYWALL` 已经是Yomizaka的402)， `releaseAudit` 和 `refundFailedAudit` 一个 `refund` 消费键的。

## 常见问题

### @krizaka/credits 是什么？

每个Krizaka产品都有一个信用分类账：每天和每月限额到期的赠款，购买，借记，退款，持有。扩展;平衡是推导出来的。同时消费永远不会为负，也不会花费两次。没有数据库客户机，没有

### 如何安装 @krizaka/credits？

在项目目录运行 npm install @krizaka/credits，或使用 pnpm add / yarn add / bun add。

### @krizaka/credits 支持 TypeScript 吗？

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

### @krizaka/credits 支持 ESM 还是 CommonJS？

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

### @krizaka/credits 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @krizaka/credits 可以商用吗？

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

### @krizaka/credits 还在维护吗？

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

