[[Bun]]の1.2.21で魅力的な対応がいくつか入ったので試してみる。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://bun.sh/logo.svg" />
<span class="link-card-v2-site-name">bun.sh</span>
</div>
<div class="link-card-v2-title">
Bun v1.2.21 | Bun Blog
</div>
<div class="link-card-v2-content">
Fixes 69 issues (addressing 204 👍). Bun.SQL now supports MySQL and SQLite, alongside PostgreSQL. Native YAML su ...
</div>
<img class="link-card-v2-image" src="https://bun.com/og/blog/bun-v1.2.21.png" />
<a href="https://bun.sh/blog/bun-v1.2.21"></a>
</div>
## バージョンアップ
[[mise]]を利用しているのでアップデートする。
```console
bun use -g bun@latest
```
## Bun.SQL - unified SQL client
[[Bun.SQL]]が統一の[[データベースクライアント|SQLクライアント]]になった。1.2.21で[[MySQL]]と[[MariaDB]]、[[SQLite]]に完全対応したとのこと。
以下のコードについて
```ts
import { SQL } from "bun";
const db = new SQL(":memory:");
await db`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`;
```
Bun 1.2.19で実行するとエラーになる。
```error
1 | import { SQL } from "bun";
2 |
3 | // Create an in-memory SQLite database
4 | const db = new SQL(":memory:");
^
TypeError: ":memory:" cannot be parsed as a URL.
code: "ERR_INVALID_URL"
at loadOptions (bun:sql:864:15)
at new SQL (bun:sql:961:35)
at /Users/tadashi-aikawa/tmp/bun-1.2.21-sandbox/index.ts:4:12
at loadAndEvaluateModule (2:1)
Bun v1.2.19 (macOS arm64)
```
Bun 1.2.21で実行すると動く。
ただ、以下のコードは `SQL.values` が型エラーになる。
```ts
import { SQL } from "bun";
const db = new SQL(":memory:");
await db`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`;
const names = ["Alice", "Bob"];
await db`INSERT INTO users (name) VALUES ${SQL.values(
names.map((name) => [name]),
)}`;
const users = await db`SELECT * FROM users ORDER BY name ASC`;
console.log(users);
```
実行結果。
```error
2 |
3 | const db = new SQL(":memory:");
4 | await db`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`;
5 |
6 | const names = ["Alice", "Bob"];
7 | await db`INSERT INTO users (name) VALUES ${SQL.values(
^
TypeError: SQL.values is not a function. (In 'SQL.values(names.map((name) => [name]))', 'SQL.values' is undefined)
at /Users/tadashi-aikawa/tmp/bun-1.2.21-sandbox/index.ts:7:48
Bun v1.2.21 (macOS arm64)
```
[[ChatGPT]]に聞いてみた。
> [!left-bubble] ![[chappy.webp]]
> SQL.values(...) は 1.2.21 の実装では存在しない(環境によって未定義)ため、sql(...) ヘルパを使うのが正解です。
>
> 公式ドキュメントの現行 API も、バルク INSERT は sql(objectsOrArrays) を推奨しています。
>
> > *[ChatGPT](https://chatgpt.com/c/68b84ffd-64e8-8331-91c6-9b3b02759229)*
確認してみた。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://bun.com/logo.svg" />
<span class="link-card-v2-site-name">bun.com</span>
</div>
<div class="link-card-v2-title">
SQL – API | Bun Docs
</div>
<div class="link-card-v2-content">
Bun provides fast, native bindings for interacting with PostgreSQL databases.
</div>
<img class="link-card-v2-image" src="https://bun.com/og/docs/api/sql.jpg" />
<a href="https://bun.com/docs/api/sql"></a>
</div>
たしかに `SQL.values` はない... サイドメニューにかろうじてあったけど、移動先を見ると `sql``.values()` なので変わったのかな...。
![[2025-09-03-23-40-34.avif]]
ちなみに上記メソッドは結果を取得するものであり、今回の用途 (Bulk Insert) とは異なる。Bulk Insertは `db` を使うらしい。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://bun.com/logo.svg" />
<span class="link-card-v2-site-name">bun.com</span>
</div>
<div class="link-card-v2-title">
SQL – API | Bun Docs
</div>
<div class="link-card-v2-content">
Bun provides fast, native bindings for interacting with PostgreSQL databases.
</div>
<img class="link-card-v2-image" src="https://bun.com/og/docs/api/sql.jpg" />
<a href="https://bun.com/docs/api/sql#bulk-insert"></a>
</div>
![[2025-09-03-23-43-30.avif]]
以下のように変更。
```ts
import { SQL } from "bun";
const db = new SQL(":memory:");
await db`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`;
const names = ["Alice", "Bob"];
await db`INSERT INTO users ${db(names.map((name) => ({ name })))}`;
const users = await db`SELECT * FROM users ORDER BY name ASC`;
console.log(users);
```
動いた。
```console
$ bun index.ts
[
{
id: 1,
name: "Alice",
}, {
id: 2,
name: "Bob",
}, count: 2, command: "SELECT", lastInsertRowid: null
]
```
## Native YAML support
ライブラリなしで[[YAML]]を扱えるようになったとのこと。個人的に一番これが気になった。
`users.yaml`
```yaml
# 総人数
total: 2
# ユーザー数
users:
- id: 1
name: "User 1"
- id: 2
name: "User 2"
```
importで読み込むスタイルらしい。
`main.ts`
```ts
import yml from "./users.yaml";
// JSONのようにymlの型推論はできなかった
console.log(yml);
```
```console
$ bun index.ts
{
total: 2,
users: [
{
id: 1,
name: "User 1",
}, {
id: 2,
name: "User 2",
}
],
}
```
ランタイム時に動的に読み込む方法。[[テキストファイルをロード (Bun)|テキストファイルをロード]]して[[Bun.YAML.parse()]]を使う。
```ts
const yml = await Bun.file("./users.yaml").text();
const r = Bun.YAML.parse(yml);
console.log(r);
```
> [!unresolved]
> `Bun.YAML` が型解決しない。。
[[Dynamic import (ESM)|Dynamic import]]でもOK。
```ts
const r = await import("./users.yaml");
console.log(r.total);
```
## Bun.secrets - native secrets manager for CLI tools
[[シークレットマネージャー]]を操作できる[[Bun.secrets]]が追加された。[[macOS]]の場合だと[[Keychain]]を使うとのことなので試してみる。
まずは存在しないはずのトークンを取得してみる。
```ts
const token = await Bun.secrets.get({
service: "bun-sandbox",
name: "bun-secret-token",
});
console.log(token);
```
```console
$ bun index.ts
null
```
次にトークンをセットしてみる。
```ts
await Bun.secrets.set({
service: "bun-sandbox",
name: "bun-secret-token",
value: "hogehogehoge",
});
```
そのうえで先程のコードをもう一度実行する。
```ts
const token = await Bun.secrets.get({
service: "bun-sandbox",
name: "bun-secret-token",
});
console.log(token);
```
```console
$ bun index.ts
hogehogehoge
```
[[Keychain]]も確認してみたが、ちゃんと追加されてそう。
![[2025-09-06-22-58-29.avif]]
ただ、ちょっと疑問に思ったのが、**これだと `name` と `service` 分かれば、どのスクリプトからでも情報抜けるのでは?** ということ。[[ChatGPT]]に聞いてみた。
> [!left-bubble] ![[chappy.webp]]
> 結論からいうと:
>
> - **Bun.secrets は macOS では Keychain Services を使っており、既定では(= 特別なアクセス制御を付けない限り)Touch ID などの確認ダイアログは基本的に出ません**。同一ユーザーのログイン・キーチェーンが開いていれば、service と name を知っているプロセスは読み出せます。
> - さらに **allowUnrestrictedAccess を有効にして保存すると、そのアイテムは「どのアプリからでもユーザー操作なしで読める」** ACLで作成されます。Bun の実装が SecAccessCreate(..., trustedList = nullptr) を指定しており、まさに「user interaction なしで全アプリに許可」とコメント付きで書かれています。**これは CI など非対話環境向けの“ゆるい設定”**です。
> - したがってご懸念のとおり、**怪しいスクリプトでも service と name を当てられれば取り出せる**可能性があります(特に allowUnrestrictedAccess: true だと危険度が上がります)
>
> > *[ChatGPT](https://chatgpt.com/share/68bc3fe2-ab80-800a-b3b9-fd1aee29f09f)*
裏までとってないけど、ちゃんと使う場合は気をつけたほうがよさそう。