# @bunny\.net/database-client 中文文档

规范地址：https://npmcn.com/package/%40bunny.net/database-client/

版本：0\.0\.3
npm 元数据更新时间：2026-09-02T11:06:50.462Z
中文译文更新时间：2026-11-08T23:53:56.333Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40bunny.net/database-client
原文对照：https://npmcn.com/package/%40bunny.net/database-client/?lang=original
项目主页：https://github.com/BunnyWay/cli/tree/main/packages/database-client#readme
源码仓库：https://github.com/BunnyWay/cli

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

- 包体积（解压后）：48.8 kB，13 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=18\.17\.0
- 运行依赖：0 个
- 首次发布：2026-08-25T09:32:33.833Z
- 最新版本发布：2026-09-02T11:06:50.269Z
- 近 30 天下载量：1985（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：3（近 12 个月 3 个）

## 中文简介

Bunny Database 无依赖的 SQL 客户端 。 任何地方抓取的跑道都是: Bunny Edge Scripting, Bun, Node, 和 Deno.

## 安装

```sh
npm install @bunny.net/database-client
```

也可以使用：`pnpm add @bunny.net/database-client`、`yarn add @bunny.net/database-client`、`bun add @bunny.net/database-client`

## README

# @bunny.net/数据库客户端

一个小型 SQL 客户端 [兔子数据库](https://bunny.net/)。它没有依赖性和用途 `fetch` 所以同样的代码在Bunny Edge脚本(Deno),Bun,和Node上运行.

> \[尖叫声\] **仅限服务器侧. 永远不要将它运送给浏览器或其他任何不信任的客户端.**
> 
> 一个认证符允许访问整个数据库,这个客户端发送原始的SQL. 输入客户端代码 每位访客都可以读写每张桌子 不管你的UI提供什么. [为什么没有浏览器](https://npmcn.com/package/%40bunny.net/database-client/#readme-why-not-the-browser) 有细节.

## 安装

```bash
bun add @bunny.net/database-client
```

## 快开始

`connect()` 读取 `BUNNY_DATABASE_URL` 财务报告和审定财务报表 `BUNNY_DATABASE_AUTH_TOKEN` a. 与《公约》有关的其他事项 `bunny db quickstart --lang typescript` 您的指纹( 或 `bunny db create --token --save-env` 直接写入),且边缘脚本已经设置的 :

```ts
import { connect } from "@bunny.net/database-client";

const db = connect();

const user = await db.prepare("SELECT * FROM users WHERE id = ?").bind(1).first();
```

需要时明确通过:

```ts
const db = connect({
  url: "libsql://your-db.lite.bunnydb.net",
  authToken: "your-token",
});
```

Edge 脚本、 Bun、 节点、 Hono、 Next.js、 Astro 和 SvelteKit 的可运行示例 [`packages/database-client/examples`](https://github.com/BunnyWay/cli/tree/main/packages/database-client/examples)。 。 。 .

## API 密码

### `connect(config?)`

回返a `Database`。每个选项都是可选的.

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `url` | `string` | `BUNNY_DATABASE_URL` | `libsql://`, (中文(简体) ), `https://`,或 `http://` 连接 URL. |
| `authToken` | `string` | `BUNNY_DATABASE_AUTH_TOKEN` | 发送为 `Authorization: Bearer <token>`。 。 。 . |
| `fetch` | `typeof fetch` | 全球 `fetch` | 代替测试、追踪或定制代理. |
| `headers` | `Record<string, string>` | 无 | 每一个请求都要加头. |
| `signal` | `AbortSignal` | 无 | 适用于每一个请求. |
| `timeout` | `number` | 无 | 单项请求中止前的毫秒数 。 正整数可达2147483647. |

客户端重写 a `libsql://` URL为 `https://`。它拒绝在 URL 中的证书,两者 `user:pass@` 还有一个 `authToken` 查询参数,所以通过 `authToken` 换句话说 默默地放出一个符号 会让你调试一个无法解释的401.

每个请求都携带 `User-Agent: bunny-database-client`中页眉名称 `headers` 被匹配的大小写不敏感, 所以通过自己的 `User-Agent` 替换默认,而不是同时发送.

无 `timeout` 请求在运行时间允许的情况下等待,在边缘函数上意味着被挂起的取来可以将整个引用点烧掉. `timeout` 财务报告和审定财务报表 `signal` 作曲:以哪个起火先中止请求.

### `db.prepare(sql)`

回返a `Statement`. 语句是不可改变的,所以你可以保持一个周围,并按你喜欢的频率绑住它.

```ts
const byId = db.prepare("SELECT * FROM users WHERE id = ?");

const alice = await byId.bind(1).first();
const bob = await byId.bind(2).first();
```

传出一行的字型,使其贯穿该语句的每次执行. 见 [类型](https://npmcn.com/package/%40bunny.net/database-client/#readme-types)。 。 。 .

### `` db.sql`...` ``

绑定每个内插值的模板文字,所以写出查询的最短方式也是参数化的:

```ts
const note = await db.sql`SELECT * FROM notes WHERE id = ${id}`.first();
```

每个 `${...}` 变成一个 `?` 占位符及其值是绑定的,从未被分解入 SQL 字符串。 它返回一个 `Statement`,所以所有的东西 [执行](https://npmcn.com/package/%40bunny.net/database-client/#readme-executing) 适用情况不变.

数值遵循与 `bind()`,有一个区别:插入对象抛出而不是被读取为被命名的参数,因为在模板中,它更有可能是一个错误.

用同样的方式通过一行 `prepare()`,作为 `` db.sql<User>`...` `` 。 。 。 .

只有值可以参数化,它是一个SQLite限制而不是客户端限制. 以 `prepare()` 当表格或列名必须更改时.

### `statement.bind(...values)`

绑定参数并返回新语句。 接受 `null`, (中文(简体) ), `boolean`, (中文(简体) ), `number`, (中文(简体) ), `bigint`, (中文(简体) ), `string`,以及 `Uint8Array`。 。 。 .

传出值为 `?` 占位符 :

```ts
await db.prepare("SELECT * FROM users WHERE id = ? AND active = ?").bind(1, true).all();
```

为 SQLite 的命名表单通过一个单一对象, `:name`, (中文(简体) ), `@name`,以及 `$name`数字 :

```ts
await db
  .prepare("SELECT * FROM users WHERE id = :id AND active = :active")
  .bind({ id: 1, active: true })
  .all();
```

名字可能带了相片,或者把它留下,所以 `{ id: 1 }` 财务报告和审定财务报表 `{ ":id": 1 }` 两者都绑定 `:id`。一个语句使用一种样式:将位置值和对象混合在同一语句中 `bind()` 而不是为你挑一个赢家.

`undefined` 扔出而不是绑定 NULL,所以错误的属性(`bind(user.nmae)`)表面而不是悄悄地写出NULL. 过 `null` 当你指NULL.

任何其它的投出,而不是被悄悄地转换,因为SQLite无处可放. `Date` 得到自己的信息建议 `.toISOString()` 或者说 `.getTime()`既然你猜到哪一个会改变 最终在栏目.

整数 `number`s是作为INTEGER发送的,而它们完全合适,最高可达2^53. 过去的每双都是整数,所以客户端发送时是真实的,真实的存储值是不变的. 传出 a `bigint` 当你需要一个那么大的整数。 Bigints必须符合SQLite的64位签名范围.

### 执行

运行声明的四种方式:

```ts
const rows = await db.prepare("SELECT id, name FROM users").all();
// [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]

const row = await db.prepare("SELECT * FROM users WHERE id = ?").bind(1).first();
// { id: 1, name: "Alice" }  or  null

const name = await db.prepare("SELECT name FROM users WHERE id = ?").bind(1).first("name");
// "Alice"  or  null

const rows = await db.prepare("SELECT id, name FROM users").raw();
// [[1, "Alice"], [2, "Bob"]]
```

`run()` 返回行加写入元数据 :

```ts
const result = await db
  .prepare("INSERT INTO users (name) VALUES (?) RETURNING id")
  .bind("Carol")
  .run();

// {
//   rows: [{ id: 3 }],
//   columns: ["id"],
//   rowsAffected: 1,
//   lastInsertRowid: 3,
// }
```

`runRaw()` 返回与位置数组相同的有行的元数据。 当结果可能包含同名的两列时, 联系它, 因为对象行只保留上一列 :

```ts
const result = await db.prepare("SELECT a.id, b.id FROM a JOIN b").runRaw();
// { rows: [[1, 99]], columns: ["id", "id"], rowsAffected: 0, lastInsertRowid: null }
```

在其中之一被调用之前,声明什么都不做,所以 `prepare()` 财务报告和审定财务报表 `bind()` 安全地通过.

### `db.batch(statements, options?)`

在一次交易和一次往返中运行每个语句。 他们都承诺或没有.

```ts
const [inserted, count] = await db.batch([
  db.prepare("INSERT INTO users (name) VALUES (?)").bind("Dan"),
  db.prepare("SELECT COUNT(*) AS c FROM users"),
]);
```

你得到一个 `Result` 按顺序排列. `batchRaw()` 相同但有位置行。 如果有声明失败, 交易会回滚 `batch()` 丢弃该语句错误, 与 `error.batchIndex` 设置到失败的语句位置.

批次是交易,所以你自己的声明开始 `BEGIN`, (中文(简体) ), `COMMIT`, (中文(简体) ), `END`,或 `ROLLBACK` 在发送任何信息之前被拒绝。 保存点是好的.

`{ mode: "immediate" }` 打开交易 `BEGIN IMMEDIATE`写字锁在前面。 SQLite的默认值, `deferred`,在首个写作时取下它,这样一批读取然后写作就会失败 `SQLITE_BUSY` 如果另一个作家进来了 使用 `immediate` 你认识的批次会写. `exclusive` 也予以接受.

`batch()` 从语句中推断出每个结果的行类型,所以 `prepare<User>(...)` 语句恢复为 `Result<User>` 乃至于无型相相相相. 见 [类型](https://npmcn.com/package/%40bunny.net/database-client/#readme-types)。 。 。 .

`{ foreignKeys: false }` 将交易以 `PRAGMA foreign_keys=off` 财务报告和审定财务报表 `=on`。Schema 更改需要它: SQLite 的表格重建程序和若干 `ALTER TABLE` 形式要求真正取消执法,而不仅仅是延后实施. `bunny db migrations apply` 运行这边.

```ts
await db.batch(
  [
    db.prepare("CREATE TABLE users_new (id INTEGER PRIMARY KEY, email TEXT NOT NULL)"),
    db.prepare("INSERT INTO users_new SELECT id, email FROM users"),
    db.prepare("DROP TABLE users"),
    db.prepare("ALTER TABLE users_new RENAME TO users"),
  ],
  { foreignKeys: false, mode: "immediate" },
);
```

保持这个顺序:以临时名称来构建替换,将原名放下后再重命名. 重新命名原版,让原版脱颖而出。 。 `REFERENCES users` 在其它表格中,要跟随重命名,它们最后指向一个你即将掉落的表格.

### `db.exec(sql)`

运行多语句脚本。 它不需要参数,也不返回行,所以它主要用于设置一个计划.

```ts
await db.exec(`
  CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL);
  CREATE INDEX IF NOT EXISTS users_name ON users (name);
`);
```

任何你需要运行不止一次, 到达移民(`bunny db migrations`相反.

### 错误

一切抛出 `DatabaseError`数字 :

```ts
import { DatabaseError } from "@bunny.net/database-client";

try {
  await db.prepare("INSERT INTO users (email) VALUES (?)").bind("dupe@example.com").run();
} catch (error) {
  if (error instanceof DatabaseError && error.code === "SQLITE_CONSTRAINT") {
    // handle the duplicate
  }
}
```

| 财产 | 说明 |
| --- | --- |
| `message` | 服务器的信息,或对本地验证失败的描述. |
| `code` | SQLite 代码 (`SQLITE_CONSTRAINT`),或客户端代码(`UNAUTHORIZED`, (中文(简体) ), `URL_MISSING`) (中文(简体) ). |
| `status` | HTTP状态,当故障来自运输而不是从SQL. |
| `batchIndex` | 失败的语句的位置, 当您之一的语句在 `batch()` 失败 . |

在SQL运行之前发生的失败也被包住,所以一个 `catch (error) { if (error instanceof DatabaseError) ... }` 覆盖整个地表 而不是让一个 `TypeError` 通过:

| `code` | 原因 |
| --- | --- |
| `NETWORK` | DNS,TLS,连接拒绝,或者回应不是JSON. |
| `TIMEOUT` | 这个 `timeout` 截止日期已过. |
| `ABORTED` | 这个 `signal` 你通过了 流产. |
| `PROTOCOL` | 服务器用一个不是管道反应的躯体回答200. |

对于这三人, `error.cause` 保存运行时间的原错误 .

## 类型

整数者回来 `number` 而他们完全合身 `bigint` 外加 `Number.MAX_SAFE_INTEGER`。客户端从不检查一个值使其适合.

| SQL 点 | Java 脚本 |
| --- | --- |
| 无效 | `null` |
| 进口 | `number`,或 `bigint` 历经2^53 |
| 真实 | `number` |
| 文本 | `string` |
| 块 | `Uint8Array` |

SQLite 没有布尔类型 . `bind(true)` 存储 `1`,并读回 `1`。 。 。 .

行为 `Record<string, SqlValue>` 默认。 传出自己的形状来跳过铸币局:

```ts
interface User {
  id: number;
  name: string;
}

const users = await db.prepare("SELECT id, name FROM users").all<User>();
```

或者一次输入语句,让其每次执行都继承形状:

```ts
const byId = db.prepare<User>("SELECT id, name FROM users WHERE id = ?");

const alice = await byId.bind(1).first(); // User | null
const both = await byId.bind(1).all(); // User[]
```

执行器上的一类参数仍然胜过声明,所以 `all<Row>()` 编号 `Statement<User>` 让你排回未打过的字.

这种类型是一种断言。 在运行时没有任何东西可以验证行与它相对,所以它只能像您的SQL那样准确.

## 边缘脚本

Edge脚本运行 Deno,因此可以从npm直接导入. 一个独立的脚本通过边框脚本SDK服务请求:

```ts
import * as BunnySDK from "npm:@bunny.net/edgescript-sdk@0.12.1";
import { connect } from "npm:@bunny.net/database-client";

const db = connect();

BunnySDK.net.http.serve(async (request: Request): Promise<Response> => {
  const users = await db.prepare("SELECT id, name FROM users LIMIT 10").all();
  return Response.json(users);
});
```

在模块范围构建客户端是好的. `connect()` 打开无套接字和 I/O , 所以没有需要加热或拆卸的请求 .

Edge Script也是持有数据库符号的正确地点. 代码及其环境一直停留在兔子的边缘上,浏览器只看到了你选择返回的响应.

## 警卫

### 为什么没有浏览器

客户端只使用 `fetch`,所以它会很高兴运行 在浏览器。 它还是不应该去那里.

一个数据库认证令牌授权连接,这意味着任何持有它的东西都可以运行任何令牌允许的SQL对接任何表格. 在客户端代码中,符号出现在网络标签、JS捆绑、 `localStorage`,以及任何注入的脚本。 一旦它泄露,一个访客可以尽你所能, `DROP TABLE` 包含.

值得我们知道: `bunny db tokens create` 因此,你最有可能躺在周围的标志也是最糟糕的.

仅读的符号缩小了损坏而不修复:

```bash
bunny db tokens create --read-only --expiry 30d
```

这仍然把每张表格的每行都交出来,因为符号授权连接而不是查询,而SQLite没有行级的安全性可以回落.

### 怎么办呢

在您的服务器上保留此令牌, 只披露您实际想要允许的查询 。 通常指坐在数据库前的边缘脚本:

```ts
// Edge Script: the token stays here, the browser gets only this shape.
import * as BunnySDK from "npm:@bunny.net/edgescript-sdk@0.12.1";
import { connect } from "npm:@bunny.net/database-client";

const db = connect();

BunnySDK.net.http.serve(async (request: Request): Promise<Response> => {
  const url = new URL(request.url);
  const author = url.searchParams.get("author");
  if (!author) return new Response("author required", { status: 400 });

  // Parameterized, and scoped to the columns and rows the caller may see.
  const posts = await db
    .prepare("SELECT id, title FROM posts WHERE author = ? AND published = 1 LIMIT 50")
    .bind(author)
    .all();

  return Response.json(posts);
});
```

浏览器调用您的端点,您的端点决定了SQL的运行.

### 处理令牌

-   在环境变量中而不是在源中保留符号. `connect()` 读取 `BUNNY_DATABASE_URL` 财务报告和审定财务报表 `BUNNY_DATABASE_AUTH_TOKEN`,所以一个符号 从来没有出现在代码.
-   连接 URL 中的证书被拒绝,因为 URL 最终会出现在日志, 裁判员和错误报告中. 过 `authToken` 换句话说.
-   首选短寿活符(`bunny db tokens create --expiry 12h`)和最狭小的授权有效. 如果有人漏掉的话, `bunny db tokens invalidate` 取消数据库的每个符号.
-   `DatabaseError` 携带服务器的信息和SQLite代码,所以直接传递到客户端可以泄露出计划细节. 记录下来,然后还一些通用的.

## 发展

```bash
bun test
```

`scripts/smoke.ts` 运行客户端与两个运行时间的真实数据库。 它创造和放弃自己的桌子, 并留下任何东西:

```bash
bun run scripts/smoke.ts
deno run --env-file=.env --allow-net --allow-env scripts/smoke.ts
```

## 常见问题

### @bunny\.net/database-client 是什么？

Bunny Database 无依赖的 SQL 客户端 。 任何地方抓取的跑道都是: Bunny Edge Scripting, Bun, Node, 和 Deno\.

### 如何安装 @bunny\.net/database-client？

在项目目录运行 npm install @bunny\.net/database-client，或使用 pnpm add / yarn add / bun add。

### @bunny\.net/database-client 支持 TypeScript 吗？

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

### @bunny\.net/database-client 支持 ESM 还是 CommonJS？

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

### @bunny\.net/database-client 需要什么版本的 Node\.js？

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

### @bunny\.net/database-client 可以商用吗？

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

### @bunny\.net/database-client 的下载量有多少？

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

### @bunny\.net/database-client 还在维护吗？

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

