[[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)* 裏までとってないけど、ちゃんと使う場合は気をつけたほうがよさそう。