# @broberg/apikey 中文文档

规范地址：https://npmcn.com/package/%40broberg/apikey/

版本：0\.3\.1
npm 元数据更新时间：2026-08-07T08:37:50.858Z
中文译文更新时间：2026-11-08T15:51:39.912Z
软件包许可：MIT

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

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

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

- 包体积（解压后）：146 kB，30 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：hono \>=4
- 首次发布：2026-06-15T20:07:04.394Z
- 最新版本发布：2026-08-07T08:37:50.514Z
- 近 30 天下载量：7472（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：5（近 12 个月 5 个）

## 中文简介

Broberg.ai车队的框架不可知的 API- key 原始: 薄荷前缀密钥, 时间安全验证( hashed 或 plaintext), 滑动窗率限制于可插件商店, Cloudflare 式的授权级联( permission × 资源过滤器)

## 安装

```sh
npm install @broberg/apikey
```

也可以使用：`pnpm add @broberg/apikey`、`yarn add @broberg/apikey`、`bun add @broberg/apikey`

## README

# @broberg/ apikey (英语)

框架不可知性 **输入 API- key 原始** 为了兄弟会的舰队 它拥有危险到错误的位点——薄荷,常时核查,限速,和云浮式的授权级联——并离开 **存储、租赁和请求文本解决方案**带上你自己的 `lookup`。 。 。 .

由9-repo分舰队勘测(trail ^ carmem → cms → upmethers → vn)所设计:包裹从不强迫散发,租借模式,固定前缀,或限速后端.

```bash
npm i @broberg/apikey      # exact-pin for prod-auth deps
```

## 核心项目`@broberg/apikey`(中文(简体) )

```ts
import { generateKey, hashKey, verifyKey, makeKeyPreview, hasScope } from "@broberg/apikey";

const raw = generateKey("trail");           // "trail_<64 hex>"  — show ONCE
const stored = hashKey(raw);                // sha256 — store this (hash-at-rest)
const preview = makeKeyPreview(raw);         // "trail_0a1b2c3d" — display/grep anchor

// On each request — YOU do the DB read; the package does the constant-time compare:
verifyKey(presented, stored);               // hashed (default): timingSafeEqual(sha256(presented), stored)
verifyKey(presented, stored, { hashed: false }); // plaintext-revealable (upmetrics-style)

hasScope(["content:*"], ["content:write"]); // true — exact / `*` / `area:*`
```

`timingSafeEqual(a, b)` 也导出 `a !== b` 代币支票.

## 速率限制——可插件存储

默认内相(单机). 对a **无国籍的多机** 车队,通过一个共享商店,这样窗口就不会每台机器漏出:

```ts
import { SlidingWindowRateLimiter, type RateLimitStore } from "@broberg/apikey";

const limiter = new SlidingWindowRateLimiter({ windowMs: 60_000, max: 100 });
const { allowed, remaining, resetAt } = await limiter.check(clientKey);

// One limiter, per-key caps — pass a per-check `max` override (v0.1.1):
await limiter.check(clientKey, { max: keyRecord.rateLimitPerHour });

// Shared backend (Turso/Redis): implement one method.
const turso: RateLimitStore = {
  async hit(key, now, windowMs) { /* … */ return { count, oldest }; },
};
new SlidingWindowRateLimiter({ windowMs: 60_000, max: 100, store: turso });
```

## 授权级联`@broberg/apikey/authorize`(中文(简体) )

可选的丰富级——允许相×资源-过滤相×CIDR相×TTL(型号为cms F134). 简单领养者跳过此选项并使用 `hasScope`。 。 。 .

```ts
import { evaluateToken, type TokenGrant } from "@broberg/apikey/authorize";

const grant: TokenGrant = {
  permissions: ["deploy:trigger"],
  resources: [{ scope: "site", effect: "include", targets: ["fysiodk"] }],
  ipFilters: [{ mode: "in", cidrs: ["203.0.113.0/24"] }],
  notBefore: Date.parse("2026-01-01"),
  notAfter: Date.parse("2027-01-01"),
};

const decision = evaluateToken(grant, {
  permission: "deploy:trigger",
  resource: { scope: "site", target: "fysiodk" },
  ip: "203.0.113.5",
});
// → { allowed: true } | { allowed: false, reason: "expired" | "permission_denied" | "resource_denied" | "ip_denied" }
```

连带命令: TTL ~ 权限 ~ 资源 (**排除胜负**\+ CIDR(IPv4 + IPv6,0-dep). 没有过滤器的瞄准镜不受限制 .

### 租户选择者(铁路选择者-非赠与者)

```ts
import { selectTenant, TenantAccessError } from "@broberg/apikey/authorize";

// A `spansAll` key lets the owner pick any tenant they belong to via a header.
// A non-member slug is a HARD refuse — never a silent fall-back to home.
try {
  const tenant = selectTenant({ requestedSlug, homeTenant, spansAll: true, isMember });
} catch (e) {
  if (e instanceof TenantAccessError) return new Response(null, { status: 401 });
}
```

## 适配器

```ts
// Stack B — Hono
import { honoApiKeyMiddleware, honoRateLimit } from "@broberg/apikey/hono";
app.use("/api/*", honoApiKeyMiddleware({ lookup, authorize }));   // 401/403; c.get("apiKey")
app.use("/api/*", honoRateLimit(limiter));                         // 429 + Retry-After

// Stack A — Next.js (Web-standard Request/Response, edge-safe, no `next` dep)
import { withApiKeyAuth, nextRateLimit } from "@broberg/apikey/next";
export const POST = withApiKeyAuth(async (req, record) => Response.json({ ok: true }), { lookup });
```

### 你的错误合同,不是我们的(v0.2.0)

默认机构是 `{ error: "missing_api_key" }` ——a. 国家 **字符串**时 API回答其他问题(如:. `{ error: { code, message } }`,该机器 客户端可以切换, 让它自己而不是重写中间软件 :

```ts
app.use("/api/*", honoApiKeyMiddleware({
  lookup,
  authorize,
  onUnauthorized: (c, reason) =>            // reason: "missing" | "invalid"
    c.json({ error: { code: `unauthorized_${reason}` } }, 401),
  onForbidden: (c, record) =>
    c.json({ error: { code: "forbidden", at: record.id } }, 403),
}));

app.use("/api/*", honoRateLimit(limiter, keyFn, {
  onLimited: (c, r) => c.json({ error: { code: "rate_limited", retryAt: r.resetAt } }, 429),
}));
```

中间的软件仍然决定 **什麽** 发生了;只有钩子决定它是如何 写下来。 状态代码和 `X-RateLimit-Remaining` 编号 : `Retry-After` 标题不变。 解开钩子和反应 字节相同 (原始内容存档于2013-10-01). v. 1.1.

`reason` 值得采取行动的是: **401 (中文(简体) )** 表示 _"我不知道你是谁"_ (无) 指使,未知指使,刚被撤销),通过取出指使来固定; **403 (韩语)** 表示 _"我知道你到底是谁, 这不是你的"_ 由 请求不同的角色。 反应是唯一能告诉 打电话的.

> **限速桶键.** 没有 `keyFn`,在 `x-forwarded-for`后退为 `"unknown"` 当信头缺席时。 在一个 在前面没有代理的回放服务意味着 **每一个呼叫者份额 一个桶** - 通过一个 `keyFn` 代之以代号/记录id上的密钥.

### 每条路线的上限不同,1个限制(v0.3.0)

`keyFn` 可能返回 `{ key, max }` 而不是一个赤裸的字符串,所以一个单一的限定器 每个路由执行不同的上限——您不需要每个上限的限制实例 :

```ts
app.use("/admin/*", honoRateLimit(limiter, (c) => ({ key: tokenId(c), max: 600 })));
app.use("/write/*", honoRateLimit(limiter, (c) => ({ key: tokenId(c), max: 300 })));
```

两套适配器 **`X-RateLimit-Limit`** 以及 `X-RateLimit-Remaining` —— 说 `Limit` 报告 _有效_ 该请求的上限(每条路线) `max` 何时 ),因为你无法解释的剩余数并不多用. `RateLimitResult.limit` 直接驱动限制器时带相同的号码.

### 您的处理器( v0. 3. 0)

默认情况下 **整体** 查询记录是什么 `c.set(contextKey, …)` 存储 (Hono)和作为处理器的第二论点(Next)——包括: 无论你的存储行携带,例如 `hash` 栏。 大麻不是一个 可用证书,所以这不是证书泄露,但不止是 处理器需要,一个 `c.json(caller)` 后来它成为一个反应机构.

过 `project` 选择自己形状的呼叫者:

```ts
honoApiKeyMiddleware({ lookup, project: (r) => ({ id: r.id, role: r.role }) });
withApiKeyAuth(handler, { lookup, project: (r) => ({ id: r.id, role: r.role }) });
```

> **适配器不对称,明确声明:** 页:1 `onUnauthorized` 编号 : `onForbidden` 编号 : `onLimited` 上面有钩子 **浩诺** 仅限适配器. 下一个适配器 仍然释放内置的字符串体。 将问题归档是正确之举,如果 你需要他们在那里.

> **如果你把自己的429个尸体 引用同样的话 `result`。 。 。 .** 信头来了 从中间的软件 和身体来自你 `onLimited`,所以他们是 在两个地方生产。 打电话的人说 _"每60个1"_ 在体内 `X-RateLimit-Limit` 说 `600` 无法判断该相信什么。 使用 `result.limit` 编号 : `result.resetAt` 在身体中,而不是一个常数 你持有 - 包不能为您断言这一点,所以值得测试 你那边.

`Retry-After` 下层为 `1` (自v.3.1起):与一个共享远程商店,该商店 绕行超过剩余窗口, 原始计算可能为负数 发射 `Retry-After: 0` - 让客户重新尝试 _马上_ 还在 有限.

`lookup(presented) => record | null` 是您的: 散列 + DB/ 文件系统读取, 您的存储, 您的租赁 。 包裹没看到你的店.

## 边界(它故意不做的事)

-   **无存储** – 没有 DB/ CRUD 层; 您拥有 schema( Drizzle / libSQL / JSON) .
-   **无要求-租户解决** - 这是你的代理/路由器;将结果输入 `selectTenant`。 。 。 .
-   **无捆绑的 Redis/ Turso** - 船舶 `RateLimitStore` 接口 + 仅内存.
-   **核心加密为节点/ Bun** (单位:千美元)`node:crypto`) (中文(简体) ). 在边缘处,通过网络加密的散列 `lookup`;适配器本身是边缘安全.

麻省理工学院的一部分 [broberg.ai 共享库存](https://discovery.broberg.ai/)。 。 。 .

## 常见问题

### @broberg/apikey 是什么？

Broberg\.ai车队的框架不可知的 API- key 原始: 薄荷前缀密钥, 时间安全验证\( hashed 或 plaintext\), 滑动窗率限制于可插件商店, Cloudflare 式的授权级联\( permission × 资源过滤器\)

### 如何安装 @broberg/apikey？

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

### @broberg/apikey 支持 TypeScript 吗？

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

### @broberg/apikey 支持 ESM 还是 CommonJS？

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

### @broberg/apikey 可以商用吗？

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

### @broberg/apikey 的下载量有多少？

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

### @broberg/apikey 还在维护吗？

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

