关于 blob-storage
介绍如何在 Val Town 中使用 `std/blob` 持久化简单值,说明 val 级与账户级存储、数据操作,以及何时改用 `std/sqlite`。
主要功能
- 01存储 JSON 和原始数据
- 02val 级或账户级 Blob
- 03列出、删除和复制操作
- 04缺失键处理说明
- 05存储限制与使用提示
适用场景
- 01持久化 val 配置
- 02缓存 API 响应
- 03保存上传文件或二进制资源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ val-town/ plugins --skill blob-storage安装后在 Claude Code 中输入/blob-storage确认已加载。
详细介绍
Blob 存储
Val Town 通过 std/blob 模块提供内置键值 Blob 存储。只要 val 需要按字符串键持久化简单值(例如 JSON 文档、缓存的 API 响应、上传的文件或二进制资源),就可以使用它。对于需要使用 SQL 查询的关系型或结构化数据,请改用 std/sqlite。
作用域:根据导入方式,可为账户全局或单个 val
Blob 工具提供两个导出:global.ts 的作用域为用户账户,main.ts 的作用域为 val 本身。对于新建的 val,优先使用 main.ts 接口和 val 作用域。
以下是作用域导入:
/**
* Importing from `main.ts` provides an interface to val-scoped blobs.
*/
import { blob } from "https://esm.town/v/std/blob/main.ts";
以下是全局导入:
/**
* Importing from `global.ts` provides a blob interface that is scoped
* to your account.
*/
import { blob } from "https://esm.town/v/std/blob/global.ts";
/**
* This entrypoint is also available as `v/std/blob`. This is common
* in older vals.
*/
import { blob } from "https://esm.town/v/std/blob";
作用域和全局 blob 接口具有相同的方法。
作用域 Blob 和全局 Blob 分开存储:你无法通过作用域接口访问全局 Blob,反之亦然。
基本用法(JSON)
import { blob } from "https://esm.town/v/std/blob/main.ts";
await blob.setJSON("config", { theme: "dark", count: 0 });
const config = await blob.getJSON("config");
// config = { theme: "dark", count: 0 }, or undefined if the key doesn't exist
当键不存在时,getJSON 会返回 undefined,因此在使用结果前要进行检查:
const config = (await blob.getJSON("config")) ?? { theme: "light", count: 0 };
原始数据和二进制数据
字符串、二进制数据或任何 BodyInit 都可以使用 set/get。get 会返回标准的 Response,因此可以使用其主体辅助方法(.text()、.json()、.arrayBuffer()、.blob()):
await blob.set("logo.png", imageBytes); // string | BodyInit (Blob, ArrayBuffer, ReadableStream, …)
const res = await blob.get("logo.png");
const bytes = await res.arrayBuffer();
与 getJSON 不同,如果键不存在,get 会抛出 ValTownBlobNotFoundError。当键可能不存在时,请将其放在 try/catch 中。
列出、删除和复制
const entries = await blob.list("user_"); // optional key prefix filter
// entries = [{ key, size, lastModified }, …]
for (const { key } of entries) {
await blob.delete(key);
}
await blob.copy("config", "config.bak"); // duplicate under a new key
await blob.move("draft", "published"); // rename / relocate
list(prefix?) 会返回一个 { key: string; size: number; lastModified: string } 数组——返回的是对象,而不是单独的键字符串。
限制
- **键长度:**最多 512 个字符。
- **总存储空间:**免费计划为 10 MB,Pro 为 1 GB,由账户中的所有 Blob 共享。
- 请将大型或结构化数据集存储在
std/sqlite中,而不是作为一个巨大的 Blob 存储。
通过工具读取/写入 Blob
使用 storeBlob、readBlob、listBlobs 或 deleteBlob 工具操作属于某个组织(而非个人账户)的 val 时,请将组织句柄作为 org 参数传入,以便调用访问该组织的 Blob 存储。例如:{ key: "myapp:config", org: "some-org" }。这仅适用于工具调用——val 中的代码会自动读写其所属账户的存储。请注意,storeBlob 接受最多 100 KB 的 UTF-8 文本;对于更大的 Blob 或二进制 Blob,请在代码中使用 blob.set 写入。
规则
- 将键视为扁平命名空间。使用前缀(
feature:subkey)进行组织,并限定list的范围。 - 对于缺失的键,
getJSON会返回undefined;get会抛出ValTownBlobNotFoundError。请根据相应情况进行处理。 - 不要在 Blob 中存储机密信息——请使用环境变量存储凭据。
参考
完整 API 文档:https://docs.val.town/std/blob/