# @beignet/web 中文文档

规范地址：https://npmcn.com/package/%40beignet/web/

版本：0\.0\.65
npm 元数据更新时间：2026-11-07T23:25:58.695Z
中文译文更新时间：2026-11-07T23:42:36.627Z
软件包许可：MIT

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

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

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

- 包体积（解压后）：385 kB，72 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.12\.0
- 运行依赖：1 个
- peer 依赖：@beignet/core \>=0\.0\.3 \<1\.0\.0
- 首次发布：2026-05-31T18:35:06.352Z
- 最新版本发布：2026-11-07T23:25:58.520Z
- 近 30 天下载量：2011（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：63（近 12 个月 63 个）

## 中文简介

Beignet 的 Web 获取适配器

## 安装

```sh
npm install @beignet/web
```

也可以使用：`pnpm add @beignet/web`、`yarn add @beignet/web`、`bun add @beignet/web`

## README

# @beignet/网络

> **运行时间 :** Beignet需要Node.js 22.12或更新. Bun是可选的.

> \[叹息\] Beignet是实验性的α软件. 这个 `0.0.x` 包行为早期 评估,且在框架结算时,API可能在发布之间发生变化.

Beignet 框架运行时间的 Web 获取适配器 .

运行时间接受标准时使用此软件包 `Request` 返回 a 标准 `Response`例如Cloudflare Works, Bun, Deno, Node 获取服务器, 或应避免特定框架适配器的测试.

## 安装

```bash
npm install @beignet/web @beignet/core
```

## 代理技能

这个包装的是谭斯塔克特意技能 `@beignet/web#fetch-server`。在编译 Web 获取运行时间时装入它, 配置 CLI 网络配置文件, 安装 Bun 或无服务器处理器, 返回 原生反应、添加生道或测试 `@beignet/web/testing`。 。 。 .

## 快开始

```typescript
import { createFetchServer } from "@beignet/web";
import { routes } from "./server/routes";

export const server = await createFetchServer({
  ports,
  routes,
  context: ({ ports, requestId }) => ({
    requestId,
    ports,
  }),
  mapUnhandledError: () => ({
    status: 500,
    body: {
      code: "INTERNAL_SERVER_ERROR",
      message: "Internal server error",
    },
  }),
});

export default {
  fetch: server.fetch,
};
```

## 阿宝

```typescript
import { server } from "./server";

Bun.serve({
  fetch: server.fetch,
});
```

## 服务工作

声明 `context.service` 当队列、时间表、任务、种子或其他 非 HTTP 工作需要与请求相同的组装应用程序上下文 。 使用 `server.runServiceContext(input?, fn)` 种子和一次性剧本中 环境相关性框架被限定为回调 :

```typescript
await server.runServiceContext(async (ctx) => {
  await runSeeds({ seeds, ctx });
});
```

`server.createServiceContext(input?)` 仍可供长期服务器使用, 并测试拥有周围合成寿命的过程.

## 原始路线

`server.rawRoute({ name, method, path, metadata, hooks }).handle(fn)` 构建获取 处理无法成为合同的线路的操作者——第三方召回, 签名验证的 webhoks, 流出端点—— 仍然运行整个 服务器管道:钩子、上下文创建、仪器和框架 错误映射 。 请求解析被跳过 身体保持未消费 处理器; `metadata` 输入元数据驱动钩钩, 如限制速率 就像合同元数据一样 原始路线不添加到路线中 注册 – 在路由自己的路径上挂载返回的处理器 .

对于服务器事件,返回 `createServerSentEventResponse(...)` 从 `@beignet/core/server`。帮助者 拥有可移植 SSE 框架、 JSON 编码、心跳、请求终止 `req.signal`,订阅清理,1 MiB 未读数据限制,可选 最大连接寿命,以及反缓冲头。 这个 `start(...)` c. 调用接收可同步设置的流视信号; 预期 `AbortError` 因溪流关闭导致的拒绝作为 取消 。 该应用程序仍然拥有授权,重放,连接限制, 和解.

## HTTP 操作处理器

`@beignet/web` 用品 `createHealthRoute`, (中文(简体) ), `createStorageRoute`, (中文(简体) ), `createUploadRoute`, (中文(简体) ), `createWebhookRoute`, (中文(简体) ), `createPaymentWebhookRoute`, (中文(简体) ), `createOutboxDrainRoute`, (中文(简体) ), `createScheduleRoute`, (中文(简体) ), `createOpenAPIHandler`,以及 `createSwaggerUIHandler`。这些使用标准 `Request` 财务报告和审定财务报表 `Response` 对象. 下一个应用程序通过相同的执行 `@beignet/next`。 。 。 .

在明确的主机路径上挂载返回的方法处理器 。 创建处理器 不注册到 `server.fetch`,将其添加到合同登记处,或 将其列入合同衍生的OpenAPI。 不支持的方法返回 `405` 与 `Allow`; 准备状态和文件 回应。 排程和发箱触发器只接受GET和POST.

例如,在Bun主机上挂载一个有界限、经认证的排水管:

```ts
import { createOutboxDrainRoute } from "@beignet/web";
import { createAppServer } from "@/server";
import { outboxRegistry } from "@/server/outbox";
import { env } from "@/lib/env";

const server = await createAppServer();
const drain = createOutboxDrainRoute({
  server,
  registry: outboxRegistry,
  secret: env.CRON_SECRET,
  batchSize: 50,
  pipeline: { path: "/api/cron/outbox/drain" },
});

Bun.serve({
  fetch(request) {
    if (new URL(request.url).pathname === "/api/cron/outbox/drain") {
      return request.method === "GET" ? drain.GET(request) : drain.POST(request);
    }
    return server.fetch(request);
  },
});
```

应用程序必须绑定 `outbox` 以及其登记处使用的发送端口。 留着 主机的关闭处理和呼叫 `server.stop()` 当它停止。 时间表 处理人员同样执行每个经认证的请求的登记时间表; 帮助者都没有启动背景循环 。 失踪的秘密被关闭 在加载服务器或创建上下文之前,拒绝未经授权的请求 .

Webhook,支付-webhook,发件箱,调度处理器使用服务器的 `rawRoute` 保留其钩子、元数据、上下文, 出错映射和仪表. `pipeline.path` 识别挂载 路径到钩。 最小值 `RouteServer<Ctx>` 测试双人只能曝光 `createRequestContext`,在此情况下,帮助者不直接执行 钩子. 保健、公共储存和文件处理人员是独立的; 上传授权和上下文属于上传路由器.

Webhooks 绑定并抓取生体后再装入服务器. 核查 即使上下文代码读取了请求 也会收到被俘尸体 付款 webhooks 在读取身体前需要签名头. 使用运行时间 由安装的提供者 SDK 支持; 仅获取处理器并不意味着 边缘相容性.

对于上传,请通过静态 `{ uploadName, action }` 选项或主机解析 参数改为: `POST(request, { uploadName, action })`。网络处理器不会 从 URL 中推断参数。 下一个 `createUploadRoute` 调整其 App 路由器 `context.params` 给同一个处理器。 从当前构建请求上下文 构建上传路由器时请求; 绝不重用一个用户的上下文 后上传.

`createHealthRoute(serverOrLoader, healthConfig, environment?)` 返回时 `GET` 与 `Cache-Control: no-store`。 。 。 . `createStorageRoute(storageOrLoader, options?)` 返回时 `GET` 财务报告和审定财务报表 `HEAD` 且只服务于公共物品; 私人和缺失 对象均返回 `404`。 。 。 .

### 私人下载

打电话 `createStorageDownloadResponse({ storage, key, fileName?, method? })` 内部 在其使用大小写解决和授权文件后认证的路径 记录。 从这个包中导入它 。 将房客和房主的检查保留在 ; 帮助者不授权访问或从密钥推断所有权.

它返回了串行附件 `Response`,或 `null` 缺少字节,所以 路由可以丢出其应用目录出错. 存储失败 。 答复使用情况 `Cache-Control: private, no-store`, (中文(简体) ), `X-Content-Type-Options: nosniff`,以及 `Referrer-Policy: no-referrer`。 。 。 . `fileName` 默认键的最后一段; Unicode 文件名被保留,而空名、路径分隔符和 控制字符被拒绝。 内容类型、长度和修改时间 从存储,有一个 `application/octet-stream` 内容类型倒置. 将原始上传文件名规范化,然后将其传递给帮助者 .

`method` 默认为 `"GET"`· ; `"HEAD"` 发送信头并释放未读出的身体. 帮助者不执行范围请求或有条件的GET. 登记 通过应用程序的正常合同或原始路线管道进行认证 钩而跑. `createStorageRoute(...)` 仅服务于公共对象.

直接存储对象的下载, 先授权然后呼叫 `storage.temporaryUrl(key, { expiresInSeconds, fileName })`处理 `ready`, (中文(简体) ), `not_found`,以及 `unsupported` 明确; 不支持的提供者可以使用此选项 流来相助. 见 [私人下载指南](https://beignetjs.com/storage#private-downloads) 用于路由组成和临时链接语义.

### 推迟交货

`createOutboxDrainTrigger({ defer, createContext, registry, ... })` 这是 可选主机排程,最佳交付优化. 以后再打电话 一个成功的交易,提供主机的延迟工作原始,并保持 耐久或工人排水恢复。 下一个通过它 `createNextOutboxDrainTrigger({ defer: after, ... })`HTTP排出和排出时间 使用错误报告 `beignet.outbox.http` 财务报告和审定财务报表 `beignet.schedule.http`; 推迟 排水沟的使用 `beignet.outbox.deferred`。默认调度运行源是 `http-schedule-route`; 应用程序可以设置 `source` 当然.

## 低级助手

```typescript
import {
  createFetchHandler,
  toRequestLike,
  toWebResponse,
  webFetchAdapter,
} from "@beignet/web";
```

-   `createFetchHandler(server)` 适应 Beignet 服务器实例或 API 处理器 改为 `(req: Request) => Promise<Response>`。 。 。 .
-   `toRequestLike(req)` 转换标准 `Request` 给Beignet的 框架中性请求形状,保留本地请求及其中止 信号.
-   `toWebResponse(response)` 将 Beignet 响应转换为标准 `Response`,将数组值响应标题中的每个项目作为附件 单独的字段。 用于重复字段, 如 `Set-Cookie`。 。 。 .
-   `webFetchAdapter` 是混凝土 `HttpAdapter<Request, Response>` 用于 Web 获取运行时间的执行 .

土著 `Response` 处理者返回的示例保持不变. 明确退回 `ReadableStream` 也传递给当地人 不变,包括流式 `application/json` 和结构化 `+json` 回应。 其他平庸的Beignet响应在 `Content-Type` 缺席, `application/json`,或结构化 `+json` 媒体 类型。 故意返回文本或二进制数据,设置明确的非JSON `Content-Type` 返回网络 `BodyInit` 值 :

```typescript
return {
  status: 200,
  headers: { "content-type": "text/plain; charset=utf-8" },
  body: "hello",
};
```

使用本地语言 `Response` 当运输特定行为如方向调整或 多段边界生成需要直接Web API控制.

## 适应合同

`@beignet/core/server` 拥有框架行为: 路由匹配、 钩子、 请求 验证、反应解析、误差映射、反应所有权和提供者 生命周期。 对于框架中立的路由响应,解析的响应-shema 输出成为主体 `@beignet/web` 连载. `@beignet/web` 拥有 Web 获取边缘转换和共享可操作的 HTTP 管理者.

路由器生成的 404/405 回复跳过请求解析和应用上下文 创建. `onRequest`, (中文(简体) ), `beforeSend`,以及 `afterSend` 仍在运行,包括 关联、 CORS 和安全头; 接收响应钩 `ctx: undefined`。在自定义钩子中提供上下文访问。 405美元包括: `Allow`, (中文(简体) ), 404 运行上下文和授权 通常情况下.

导出 `webFetchAdapter` 执行正式的核心适配器合同:

```typescript
import type { HttpAdapter } from "@beignet/core/server";

export const adapter: HttpAdapter<Request, Response> = webFetchAdapter;
```

对具有非 Fetch 本地请求的未来运行时间适配器使用相同的形状 或反应类型.

## 测试

使用 `@beignet/web/testing` 通过同一 Web 抓取来练习路径 不打开网络端口的适配器 。 使用 `@beignet/core/testing` 旁边 当路由需要应用样式上下文并测试端口时.

```typescript
import { createTestContextFactory, createTestPorts } from "@beignet/core/testing";
import { createTestApp } from "@beignet/web/testing";
import { getTodo } from "./features/todos/contracts";
import { routes } from "./server/routes";

const fixture = createTestPorts<AppContext["ports"]>({
  base: initialPorts,
  overrides: { todos: createInMemoryTodoRepository() },
});
const createContext = createTestContextFactory<AppContext, AppContext["ports"]>({
  ports: fixture.ports,
});
const app = await createTestApp({
  ports: fixture.ports,
  routes,
  context: () => createContext(),
});

const todo = await app.request(getTodo, {
  path: { id: "todo_1" },
});
```

`app.request(contract, args)` 使用与 `@beignet/core/client`时 `app.safeRequest(contract, args)` 返回键入 成功/错误的结果而不是扔出.

`createTestApp(...)` 应用两个方便测试的默认值,以及明确 选项总是赢 :

-   `onUnboundPorts` 默认为 `"ignore"`,所以应用与延迟提供者 端口启动, 不安装每个提供者 。 仍然读取一个未绑定的端口 抛出使用。 制作服务器 `createFetchServer(...)` 保留 严格 `"error"` 默认.
-   `mapUnhandledError` 默认为返回的映射器 `{ status: 500, body: { code: "INTERNAL_SERVER_ERROR", message: err.message } }`, (中文(简体) ), 因此失败的测试显示的是真实的错误消息而不是通用的响应.

元数据驱动的行为需要两分之一的线: `metadata.rateLimit` 或者说 `metadata.idempotency` 只有在 匹配钩子( r)`createRateLimitHooks(...)` 编号 : `createIdempotencyHooks(...)`(中文(简体) ) 在测试应用程序中 `hooks` **财务报告和审定财务报表** 其端口已约束. `createTestApp(...)` 当注册合同宣布应用程序不能行为时提醒创建 执行,所以"429从未发生过" 响亮的失败而不是沉默 路过. `createTestPorts(...)` 从 `@beignet/core/testing` 已绑定 内存 `rateLimit` 财务报告和审定财务报表 `idempotency` 端口,所以通过应用程序的钩是 通常是唯一缺失的一块 :

```typescript
const app = await createTestApp({
  ports: fixture.ports,
  context: appContext,
  trustedProxy: { clientIp: "x-forwarded-for-last" },
  hooks: [
    createRateLimitHooks(),
    createIdempotencyHooks(),
  ],
  routes,
});

// Declared limits now produce real 429s...
const responses = await Promise.all(
  Array.from({ length: 61 }, () => app.fetch("http://beignet.test/api/search")),
);
expect(responses.at(-1)?.status).toBe(429);

// ...and repeated idempotency keys replay instead of re-running the handler.
const replay = await app.fetch("http://beignet.test/api/todos", {
  method: "POST",
  headers: { "idempotency-key": "todo-1", "content-type": "application/json" },
  body: "{}",
});
expect(replay.headers.get("idempotency-replayed")).toBe("true");
```

声明其背景蓝图的应用程序 `defineServerContext(...)` 内 `server/context.ts` 可以将相同的值传递给运行时服务器和 `createTestApp(...)`数字 :

```typescript
import { appContext } from "../server/context";

const app = await createTestApp({ ports, routes, context: appContext });
```

基础 `app.server` 保留蓝图的服务输入类型,所以 测试可以调用 `app.server.runServiceContext(input?, fn)` 用于非HTTP工作.

使用 `createTestRequester(...)` 当一个测试套房重复同样的认证, 相关性,或请求形状标题 :

```typescript
import { createTestApp, createTestRequester } from "@beignet/web/testing";

const app = await createTestApp({ ports, routes, context: createContext });
const authedRequest = createTestRequester(app, {
  headers: {
    "x-user-id": "user_1",
    "x-request-id": "req_1",
  },
});

const todo = await authedRequest.request(getTodo, {
  path: { id: "todo_1" },
});
```

`createFetchServer(...)` 财务报告和审定财务报表 `createTestApp(...)` 接受相同的建议 服务器级别 `trustedProxy` 政策。 请求上下文厂和服务器 钩子收到一个解开 `requestInfo`; 转发头仍然不可信 当该选项被省略时.

## 类型广播

`createBroadcastRoute` 从 `@beignet/web` 使用 SSE 显示授权频道 服务器上下文、元数据、路由钩以及 HTTP 错误管道。 原始路线 还接受 `hooks`;这些钩子所添加的字段在其处理器中被推断出.

```ts
// server/broadcast-route.ts
import { createBroadcastRoute, type FetchServer } from "@beignet/web";
import type { AppContext } from "@/app-context";
import { channels } from "@/server/broadcasts";

export function createAppBroadcastRoute(server: FetchServer<AppContext>) {
  return createBroadcastRoute({
    server,
    channels,
    maxLifetimeMs: 60_000,
  });
}
```

CLI网络简介生成了这家工厂. 通过您组装的服务器 应用程序 `createAppServer()` 到它和路线 `/api/broadcasts` 返回时 处理者。 例如, 将此发送合并到 Bun 主机的“ 获取” 条目 :

```ts
import { createAppServer } from "@/server";
import { createAppBroadcastRoute } from "@/server/broadcast-route";

const server = await createAppServer();
const broadcasts = createAppBroadcastRoute(server);

Bun.serve({
  idleTimeout: 60,
  fetch(request) {
    if (new URL(request.url).pathname === "/api/broadcasts") {
      return broadcasts.GET(request);
    }
    return server.fetch(request);
  },
});
```

保持您的应用程序的现有关闭处理和呼叫 `server.stop()` 当 主机停止。 广播处理器返回 `405` 用于非GET请求.

登记每个频道,明确授权具有约束力,包括公共 频道。 过 `hooks: [auth.required()]` 当您的应用程序拥有了这个钩子时; 否则 在约束中申明身份. `server` 接受一个实例或一个懒惰的装载器. 选项还包括 `metadata`, (中文(简体) ), `path` (默认) `/api/broadcasts`),以及 `resolveOrigin({ ctx, request })` (a) 将启动客户排除在外. 挂载 `GET` 在已配置的路径中. `maxLifetimeMs` 默认为 `60_000` 财务报告和审定财务报表 接受正安全整数 `1` 结束 `3_600_000` (一个小时). 对于允许5分钟请求的主机,请使用 `maxLifetimeMs: 240_000` 财务报告和审定财务报表 留下剩下的一分钟进行设置/清理。 更长的流减少更新 和调节频率,但增加授权间隔 检查。 每个新连接都会重新检查访问权限.

浏览器以五秒钟的监察优雅 来纪念公布的一生 期间。 它的最后期限涵盖整个连接; 以后的准备状态信息 心跳不会延长 心跳和初期准备暂停 独立。 每条准备信息都必须包括有效的 `maxLifetimeMs`· ; 缺少或无效的寿命 。 正常过期发送 a 关闭前的连接宽更新控制框架 。 计划续约 触发 `onSync`。 。 。 .

全球钩子故障保留了它们的HTTP状态. 每道拒绝返回 控制帧; 临时 429/5xx 失败可重试 。 客户端必须调试 在准备/重新连接后,因为广播没有持久的重播。 用这个 流式抓取,支持动态头,多轴最多可达20个频道. 当出版工作和流处理器运行在不同的过程中时使用 Redis.

对于没有服务器的主机,允许流出和输出提供者连接并设置 设置/清理头室. 60秒后,主机请求截止时间为120秒出站; 通过主机的设置配置此选项, 但须遵守其限制 。 获取 适配器不会使节点专用提供者与Edge 运行时兼容. 见 [广播指南](https://beignetjs.com/broadcasting)。 。 。 .

将主机和代理机闲置超时超过25秒心跳间隔. 这个 Bun 实例使用 `idleTimeout: 60`; Bun 默认的 10 秒闲置超时也 用于静音广播流的简写. 禁用此端点的代理缓冲 .

### 保留连接槽

新选择 `admit({ ctx, request, signal })` 钩子每个物理运行一次 上下文/认证钩后和SSE前的多轴连接 反应。 它可能返回释放函数(同步或同步),或 没什么 丢弃目录错误以拒绝整个 HTTP 请求 。 HTTP 429和 5xx回复可重新测试; `Retry-After` 被浏览器所尊重。 入学 不取代每个频道的独立授权.

此示例使用已有的 `LocksPort` 执行 **应用程序拥有** 三分机政策. 声明 `locks: LocksPort` 内 `AppPorts` 把锁系上 提供者在 `server/providers.ts`。内存锁限制一个进程;已分发 限制需要一个共享的原子租赁商店。 Redis是一个选项,而不是一个要求. 添加 `BroadcastConnectionLimit` 改为 `features/shared/errors.ts` 有状态 `429`, (中文(简体) ), 代码 `BROADCAST_CONNECTION_LIMIT`和消息 `Too many broadcast connections`。 。 。 . 将策略放入 `server/broadcast-admission.ts`数字 :

```ts
import type { LocksPort } from "@beignet/core/locks";
import { appError } from "@/features/shared/errors";

export async function reserveBroadcastConnection({
  locks, userId, signal,
}: { locks: LocksPort; userId: string; signal: AbortSignal }) {
  for (let slot = 0; slot < 3; slot++) {
    signal.throwIfAborted();
    const result = await locks.acquire(`broadcast:${userId}:${slot}`, {
      ttlMs: 300_000,
      waitMs: 0,
    });
    if (result.acquired) {
      // Return ownership even if cancelled while awaiting acquisition.
      return async () => { await result.lease.release(); };
    }
  }
  throw appError("BroadcastConnectionLimit", { headers: { "Retry-After": "5" } });
}
```

在终点上注册 `server/broadcast-route.ts`。此示例 假设在 `ctx.auth`· ; `requireUserId(ctx)` 购入前声称:

```ts
import { createBroadcastRoute, type FetchServer } from "@beignet/web";
import type { AppContext } from "@/app-context";
import { auth } from "@/lib/route-auth";
import { requireUserId } from "@beignet/core/ports";
import { reserveBroadcastConnection } from "@/server/broadcast-admission";
import { channels } from "@/server/broadcasts";

export function createAppBroadcastRoute(server: FetchServer<AppContext>) {
  return createBroadcastRoute({
    server, channels, hooks: [auth.required()], maxLifetimeMs: 240_000,
    admit: ({ ctx, signal }) => reserveBroadcastConnection({
      locks: ctx.ports.locks, userId: requireUserId(ctx), signal,
    }),
  });
}
```

挂载返回 `GET` 时间 `/api/broadcasts`。东道主拥有其请求 持续时间设定; 允许此四分钟的流量使用五分钟 .

Beignet在到期后调用每个已获取的发布功能, 请求/ body 取消、 提供者关闭 , 或失败的流设置 。 如果只是一些频道 失败时,它们的资源会在接受的频道保留连接时释放. 如果在取消或设立十秒录取后完成收购 超时,其返回的资源立即被放出. 过 `signal` 改为: 支持时获取 API; 示例在尝试中检查, 然后 返回成功的获取,即使等待取消时发生了 这个 获取后抛出而不返回释放会泄露资源.

清理失败发出 `broadcast.cleanup-error` 不跳过其他发布. 不需要应用程序流事件听众 。 每次续约都新鲜 录取和批准. **分配的租约仍需期满** 因为 程序突然终止无法进行清理 。 将 TTL 租赁在溪流之上 寿命加购置/设置/清理前厅;此示例对等 a 5分钟的租借 4分钟的溪流。 托管请求的限制也必须 离开头室。 保留储存、槽数、过期和拒绝政策 应用程序拥有;框架没有强制设置连接限制存储.

## 常见问题

### @beignet/web 是什么？

Beignet 的 Web 获取适配器

### 如何安装 @beignet/web？

在项目目录运行 npm install @beignet/web，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@beignet/core（\>=0\.0\.3 \<1\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @beignet/web 支持 TypeScript 吗？

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

### @beignet/web 支持 ESM 还是 CommonJS？

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

### @beignet/web 需要什么版本的 Node\.js？

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

### @beignet/web 可以商用吗？

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

### @beignet/web 的下载量有多少？

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

### @beignet/web 还在维护吗？

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

