# @base316/sdk 中文文档

规范地址：https://npmcn.com/package/%40base316/sdk/

版本：0\.10\.0
npm 元数据更新时间：2026-11-06T22:40:05.967Z
中文译文更新时间：2026-11-07T20:12:38.386Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40base316/sdk
原文对照：https://npmcn.com/package/%40base316/sdk/?lang=original
项目主页：https://base316.com/
源码仓库：https://github.com/ThinkfleetAI/base316

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

- 包体积（解压后）：2.4 MB，38 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2026-09-13T13:36:42.280Z
- 最新版本发布：2026-11-06T22:40:05.800Z
- 近 30 天下载量：2679（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：10（近 12 个月 10 个）

## 中文简介

官方基础316 SDK:认证,应享权利和使用量度.

## 安装

```sh
npm install @base316/sdk
```

也可以使用：`pnpm add @base316/sdk`、`yarn add @base316/sdk`、`bun add @base316/sdk`

## README

# @ base316/sdk (英语)

认证、应享权利和使用计量 [基础316](https://base316.com/)。 。 。 .

```bash
npm install @base316/sdk
```

## 两个客户,用他们持有的钥匙分割

```ts
import { Base316, Base316Browser } from "@base316/sdk";
```

`Base316` 持有 **密钥** 属于您的服务器 . `Base316Browser` 持有 **可公布密钥** 并且可以安全地向浏览器发送.

拆分是强制执行的,而不是建议: `Base316` 在浏览器中 抛出,因为泄露出的秘密密钥是环境的完全妥协.

## 服务器

```ts
import { Base316 } from "@base316/sdk";

const base316 = new Base316({ secretKey: process.env.BASE316_SECRET_KEY });
```

### 这个账户能做吗?

```ts
const decision = await base316.access.check({
    externalId: "acct_42", // your own id for the account
    feature: "projects",
    requested: 1, // what is about to be consumed
});

if (!decision.allowed) {
    throw new Error(decision.reason);
}
```

`requested` 之所以这样有用: 支票拒绝 _在此之前_ 工作情况 而不是报告超龄.

### 记录所使用的内容

```ts
await base316.events.record({
    externalId: "acct_42",
    name: "api.call",
    value: 1,
    idempotencyKey: crypto.randomUUID(),
});
```

通过一个 `idempotencyKey`。在网络超时后重试是第二次 有个客户两次开票 申请一次是支持票 无法从数据中回复.

### 客户、订阅和发票

```ts
// Look one up by your own id rather than paging the whole list.
const customer = await base316.customers.byExternalId("acct_42");

const subscriptions = await base316.subscriptions.list({ customerId: customer.id });
const invoices = await base316.invoices.list({ customerId: customer.id });
```

`byExternalId` 返回时 `null` 您尚未创建客户。 那个 是处理的正常状态,而不是错误.

发票、信用附注和引文作为PDF下载,作为PDF返回 `Uint8Array`数字 :

```ts
import { writeFile } from "node:fs/promises";

await writeFile(`${invoice.number}.pdf`, await base316.invoices.pdf(invoice.id));
await base316.creditNotes.pdf(creditNoteId);
await base316.quotes.pdf(quoteId);
```

在浏览器中, `billing.invoicePdf(session, id)` 返回已签名用户的 同样的发票。 传到一个 `Blob` 类型 `application/pdf` 作为下载提供.

### 定义销售内容

```ts
const meter = await base316.catalog.meters.create({
    key: "words",
    name: "Words generated",
    unit: "words",
    eventName: "draft.generated",
    aggregation: "SUM",
    valueProperty: "words",
});

const feature = await base316.catalog.features.create({
    key: "words",
    name: "Words generated",
    type: "METERED",
    meterId: meter.id,
});

const plan = await base316.catalog.plans.create({
    key: "pro",
    name: "Pro",
    currency: "USD",
    interval: "MONTH",
    prices: [
        { model: "FLAT", amount: "29.00" },
        { model: "PER_UNIT", featureId: feature.id, amount: "0.001" },
    ],
    entitlements: [{ featureId: feature.id, limit: 10_000 }],
});

await base316.subscriptions.create({
    customerId: customer.id,
    planVersionId: plan.versions[0].id,
});
```

以不同的单价收取一个活动字段的值——按AI模型计算, 使用a `MATRIX` 价钱。 每个行 `dimensions` 名称相同的密钥, 每个表的 `groupBy` 字段,计数器必须与 `SUM` 或者说 `COUNT`。 。 。 . `amount` 是未匹配的用法的默认行; 发票上显示的用途为: `unpriced` 已经 没有充电.

```ts
{
    model: "MATRIX",
    featureId: tokens.id,
    amount: "0.00001",
    rows: [
        { dimensions: { model: "opus" }, unitAmount: "0.000015" },
        { dimensions: { model: "haiku" }, unitAmount: "0.000001" },
    ],
}
```

来自矩阵的发票和即将发行的发票线 背负行的 `dimensions` (单位:千美元)`{}` 用于默认行),以及 `customers.entitlements()` 将周期的 每行内使用量 `byDimension`。 。 。 .

计划带有身份;a **版本** 带着条件,这就是 a 订阅点。 发布新版本 `catalog.plans.createVersion` 因此,永远不要重新定价 任何人已经在 旧的.

如果你只知道钥匙—— 应用程序代码中的通常案例—— 要求 直接版本 :

```ts
const version = await base316.catalog.plans.currentVersion("pro");
```

`null` 意味着计划没有发表任何内容. 草案不能签署.

### 审判和反向审判

一个版本的 `trialDays` 打开新订阅为 `TRIALING`; 其编号 `trialEndAction` 决定如何审判. `CONVERT` (违约)账单 计划. `DOWNGRADE` 移动一个没有卡片的付款人到 `trialDowngradePlanVersionId` - 实际操作,相同的订阅代号,否 发票——并转换一张卡:

```ts
const free = await base316.catalog.plans.currentVersion("free");

const team = await base316.catalog.plans.create({
    key: "team",
    name: "Team",
    currency: "USD",
    interval: "MONTH",
    trialDays: 14,
    trialEndAction: "DOWNGRADE",
    trialDowngradePlanVersionId: free!.id,
    prices: [{ model: "FLAT", amount: "49.00" }],
});

// A no-card trial without checkout; `trialDays` overrides the version's (0 = none).
await base316.subscriptions.create({
    externalId: "acct_42",
    planVersionId: team.versions[0].id,
    trialDays: 14,
});
```

降级是 `subscription.updated` 与 `change: "trial_downgraded"`。 。 。 . `PublicPlan` 包含两个字段,所以一个定价页可以说明 审判.

### 用户、租户和角色

您的应用程序本身的终端用户——而不是签入Base316的人 仪表板.

```ts
const admin = await base316.roles.create({
    key: "admin",
    name: "Administrator",
    // Your strings. Base316 matches them without interpreting them, and a
    // trailing `.*` grants everything under that prefix.
    permissions: ["billing.*", "reports.export"],
});

const tenant = await base316.organizations.create({ name: "Petronella Ltd", externalId: "t_42" });
const user = await base316.users.create({ externalId: "u_7", email: "ada@example.com" });

await base316.organizations.addMember(tenant.id, { userId: user.id, roleId: admin.id });
```

这就是迁徙之路:这里有人和房客 _在此之前_ 任何人签名 输入,所以第一个登录的人 加入他们自己的历史 而不是开始一个 旁边的新账号. `emailVerified: true` 带着确认书 已经给你的旧系统.

然后把租户与支付这笔钱的账户联系起来,或者每一次许可检查 答题 `NOT_A_MEMBER` 而账单看起来很健康:

```ts
await base316.customers.create({ externalId: "acct_42", runtimeOrganizationId: tenant.id });

await base316.access.check({ customerId, userId: user.id, permission: "billing.refund" });
```

`users.disable` 锁入账户并保存记录——离职的雇员,a 疑似妥协, 账户争议. `users.erase` 还有一件事, 然后它就还了一张收据 上面写着保存了什么和为什么.

### 管理下的租户:一家公司对其客户拥有控制权

承租人可以经营其他公司——会计师事务所对其客户公司的管理 在它的品牌。 深一关.

```ts
const firm = await base316.organizations.create({ name: "Hartley & Co" });
const client = await base316.organizations.create({ name: "Acme Ltd", parentId: firm.id });

// The firm's "accountant" acts as "editor" in every client. Unmapped roles grant nothing.
await base316.organizations.setInheritedRoles(firm.id, [
    { parentRoleId: accountant.id, childRoleId: editor.id },
]);

// The client's account bills to the firm's; this is what each client used this period.
const { data } = await base316.customers.billed(firmCustomer.id);
```

-   `organizations.children`, (中文(简体) ), `organizations.detach` 财务报告和审定财务报表 `inheritedRoles` 管理 树. `access.check` 成果记录 `permission.source` 财务报告和审定财务报表 `viaOrganizationId` 当通过公司进入.
-   客户的权利、信用和使用是公司的计划;它的活动 向律所收取 `InvoiceLine.breakdown` 每个客户。 添加标记 `countsManagedTenants` 保存在公司的客户数 `includedQuantity: 10` 头十个客户都是免费的,每个客户都是免费的 以加通的金额开出.
-   客户自己的会员 算上公司的计划 `client_seats` 特性,每个客户; 公司人员计算 `seats`。 。 。 .
-   `organizations.setBranding` 财务报告和审定财务报表 `addDomain` 编号 : `verifyDomain` 把公司 客户端主页上的品牌和签名域名; `Base316Browser.billing.tenantBranding` 用可出版的密钥读取.
-   `Base316Browser.billing.subscription` 返回时 `managedBy` 为客户,和 自服务器退出、 计划更改并取消答案 `403 billed_by_parent`。 。 。 .

### 收藏:你自己的数据模型

定义收藏是服务器操作;读取和写入其记录是 一个浏览器 。 分头行动就是为什么他们靠不同的客户生活.

```ts
await base316.collections.create({
    key: "tasks",
    name: "Task",
    fields: [
        { key: "title", label: "Title", type: "TEXT", required: true },
        { key: "status", label: "Status", type: "SELECT", options: ["open", "done"] },
        { key: "due", label: "Due", type: "DATE" },
    ],
});
```

以 `tasks.read` 财务报告和审定财务报表 `tasks.write` 权限已经 已经到位,所以 `<DataTable collection="tasks" />` 丢入页面执行 a 规则是存在的,而不是一个人必须记住.

一个字段可以重新被贴上标签,重新排序,并且需要或不需要制作. 内容 `type` 无法 更改: 已存储的每个值都被验证为旧值 .

### 进出口

```ts
// Find out what a file will do before doing it.
const preview = await base316.transfer.importCsv("customers", { csv, dryRun: true });

console.log(preview.mapping.providerName); // "Chargebee", detected from the header
console.log(preview.mapping.unmapped); // columns nothing read
console.log(preview.failed); // rows that will not land

const summary = await base316.transfer.importCsv("customers", { csv });
```

不良行会单独失败,而不是拒绝文件,所以有一行不正确 五千元就花你一行钱 奥米 `provider` 并且从中检测到 页眉; 已解决 `mapping` 随便哪条路都回来,你可以检查一下 在信任它之前就决定了.

`transfer.exportCsv("customers")` 返回 CSV 文本,而不是 JSON —— 将其写入 打开它.

### 他们付钱后会怎样

```ts
// A coupon on every invoice this subscription raises.
await base316.subscriptions.applyDiscount(subscriptionId, { code: "half-off" });

// A seat added mid-month.
await base316.addons.attach({ subscriptionId, addonId, quantity: 3 });

// A callout, billed on the next invoice.
await base316.pendingCharges.create({
    customerId,
    description: "Emergency callout",
    currency: "USD",
    amount: "250.00",
});

// A check that bounced. The invoice reopens.
await base316.invoices.reversePayment(invoiceId, paymentId, { reason: "bounced" });
```

名片过期或自动充电需要的客户,代用 在史戴克主机的网页上,从收费门户的付款方法部分或 信用页面。 您的服务器可以看到并清理文件上的卡片 :

```ts
// A single-use link straight to the portal's payment methods section.
const { url } = await base316.billingPortal.createSession(customerId, {
    page: "payment-methods",
});

const { data: cards } = await base316.paymentMethods.list(customerId);
await base316.paymentMethods.setDefault(customerId, cards[1]!.id);
```

两项规则值得你先知道,然后才能建立起来:

**钱包上加需要一个 `idempotencyKey`。 。 。 .** 网络超时后重试 一次付款的两次贷记账户是 没有人能从数据中回答. `duplicate: true` 结果报告 你是如何知道重试被认出来的.

**开具的发票从不重写.** 这是客户可能持有的文件 支付,税务机关可能已经看到。 减少一个, 提出一个信用记录—— `creditNotes.create` ——这是相反的条目而不是编辑. `void` 只有一张本不该存在的发票.

### 从代码注册的 Webhooks

```ts
const endpoint = await base316.webhooks.create({
    url: "https://yourapp.com/hooks/base316",
    eventTypes: ["invoice.paid", "subscription.canceled"],
});

// Store `endpoint.secret` now. Only a hash is kept here.
```

然后在您的操作器中验证一个交付:

```ts
const event = await constructWebhookEvent({
    payload: rawBody, // the exact bytes, not a re-serialized object
    signature: request.headers.get("base316-signature"),
    secret: process.env.BASE316_WEBHOOK_SECRET,
});
```

当一个融合变得平静, `webhooks.deliveries()` 说什么是寄来的 远的结局是怎样的. `webhooks.events()` 是另一个问题——什么 发生的事情,是否有人在听,以及你是如何向 通过投票,接生员无法接触到的机器 `cursor` 从 上页.

### 保护自己的API

```ts
const api = await base316.apiResources.create({
    name: "Your API",
    audience: "https://api.yourapp.com",
});

await base316.apiResources.addScope(api.id, {
    key: "invoices:read",
    // Gated on a plan feature: a customer without it gets a token without the
    // scope, rather than a token that works and a refusal deeper in.
    featureKey: "invoice_api",
});

const credential = await base316.apiClients.create({
    customerId,
    name: "Nightly sync",
    audience: "https://api.yourapp.com",
    scopes: ["invoices:read"],
});
```

`rateLimits.set` 第一场比赛是客户自己的政策 计划,然后资源默认——所以一个账户可以被解除,超过其计划 没有为他们设计计划.

### 引号

```ts
const quote = await base316.quotes.create({ customerId, planVersionId });

await base316.quotes.send(quote.id);

const accepted = await base316.quotes.accept(quote.id);
// accepted.subscriptionId — acceptance is what creates it
```

开票时不要开票 条件被冻结. 引用 `lines` 而不是一个 `planVersionId` 是一个引用工作 接受开具发票草稿而不是订阅.

读取 `status`没有 `storedStatus`:第一个适用过期,所以引用其 日期改为: `EXPIRED` 扫荡是否注意到.

### 报告,以及用来测试

```ts
const { byCurrency } = await base316.reports.mrr();
const aging = await base316.reports.ageing({ worstCustomerLimit: 10 });
```

宏观经济风险不转换为一种货币——需要汇率和 日期, 和发明 要么使数字 错误的方式没有人能看到。 过 `at` 以复制过去的数字.

在沙盒中,你可以移动时间:

```ts
await base316.sandbox.seed();
await base316.testClocks.create({ name: "Renewal rehearsal" });

const { effects } = await base316.testClocks.advance("2027-01-01T00:00:00Z");
// effects.subscriptionsRenewed — assert on this instead of polling
```

这就是"在发货前证明这个续约"的呼唤而不是 月等来. 两者都拒绝生产,因为提前时间将延长 每一个订阅和收费真正的卡.

### 将环境配置为代码

`authConfig`, (中文(简体) ), `email` 财务报告和审定财务报表 `paymentAccounts` 仅覆盖原设定 在仪表板中发生——一种环境之间的区别,即 可复制的 也是有人点击的记录 每个保存是一个 上升,所以部署 运行两次汇合而不是失败.

`auditLogs.list` 仅按构造读取。 没有写法和 将不会有: API 可以编辑的日志不是审计日志 .

## 浏览器

```ts
import { Base316Browser } from "@base316/sdk";

const base316 = new Base316Browser({ publishableKey: "b316_pk_live_..." });
const result = await base316.auth.signIn({ email, password });
```

## 网络呼号

在你信任之前先核实 未经证实的网钩身体是未经认证的 任何了解你终点的人的请求.

```ts
import { constructWebhookEvent } from "@base316/sdk";

const event = constructWebhookEvent({
    payload: rawBody, // the raw bytes, not the parsed JSON
    signature: request.headers.get("base316-signature"),
    secret: process.env.BASE316_WEBHOOK_SECRET,
});
```

首先解析身体并重排它 改变字节和 签名将不匹配 .

## 错误

每一次失败都是 `Base316Error` 拥有稳定 `code`,这样你就可以在 原因,而不是可能重新措辞的信息.

```ts
import { Base316Error } from "@base316/sdk";

try {
  await base316.events.record({ ... });
} catch (error) {
  if (error instanceof Base316Error && error.code === "rate_limited") {
    // back off
  }
}
```

## 常见问题

### @base316/sdk 是什么？

官方基础316 SDK:认证,应享权利和使用量度\.

### 如何安装 @base316/sdk？

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

### @base316/sdk 支持 TypeScript 吗？

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

### @base316/sdk 支持 ESM 还是 CommonJS？

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

### @base316/sdk 可以商用吗？

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

### @base316/sdk 的下载量有多少？

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

### @base316/sdk 还在维护吗？

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

