blob-storage

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Blob Storage

Blob 存储

Val Town provides built-in key/value blob storage via the
std/blob
module. Reach for it whenever a val needs to persist simple values — JSON documents, cached API responses, uploaded files, or binary assets — keyed by a string. For relational or structured data you query with SQL, prefer
std/sqlite
instead.
Val Town 通过
std/blob
模块提供内置键值Blob存储。当val需要持久化以字符串为键的简单值——如JSON文档、缓存的API响应、上传文件或二进制资产——时,可使用该模块。若需通过SQL查询的关系型或结构化数据,请优先使用
std/sqlite
。

Scoping: account-global or per-val depending on import

作用域:账户全局或单val级,取决于导入方式

There are two exports of the blob utility:
global.ts
, which is scoped to the user account, and
main.ts
, which is scoped to the val itself. Prefer the
main.ts
interface and val scoping for new vals.
Here is the scoped import:
ts
/**
 * Importing from `main.ts` provides an interface to val-scoped blobs.
 */
import { blob } from "https://esm.town/v/std/blob/main.ts";
Here are the global imports:
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";
The scoped & global
blob
interfaces have the same methods.
Scoped & global blobs are stored separately: you cannot access global blobs with the scoped interface or vice versa.
Blob工具包含两个导出项:作用域为用户账户的
global.ts
,以及作用域为val本身的
main.ts
。对于新建的val,建议优先使用
main.ts
接口和val级作用域。
以下是作用域级导入:
ts
/**
 * Importing from `main.ts` provides an interface to val-scoped blobs.
 */
import { blob } from "https://esm.town/v/std/blob/main.ts";
以下是全局导入:
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,反之亦然。

Basic usage (JSON)

基础用法(JSON)

ts
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
returns
undefined
when the key is missing, so guard before using the result:
ts
const config = (await blob.getJSON("config")) ?? { theme: "light", count: 0 };
ts
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
,因此在使用结果前需做兜底处理:
ts
const config = (await blob.getJSON("config")) ?? { theme: "light", count: 0 };

Raw and binary data

原始数据与二进制数据

Use
set
/
get
for strings, binary, or any
BodyInit
.
get
returns a standard
Response
, so use its body helpers (
.text()
,
.json()
,
.arrayBuffer()
,
.blob()
):
ts
await blob.set("logo.png", imageBytes); // string | BodyInit (Blob, ArrayBuffer, ReadableStream, …)

const res = await blob.get("logo.png");
const bytes = await res.arrayBuffer();
Unlike
getJSON
,
get
throws
ValTownBlobNotFoundError
if the key doesn't exist — wrap it in
try/catch
when the key may be absent.
对于字符串、二进制数据或任何
BodyInit
类型,请使用
set
/
get
方法。
get
会返回标准
Response
对象,因此可使用其body辅助方法(
.text()
、
.json()
、
.arrayBuffer()
、
.blob()
):
ts
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
包裹调用。

Listing, deleting, copying

列举、删除、复制

ts
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?)
returns an array of
{ key: string; size: number; lastModified: string }
— objects, not bare key strings.
ts
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 }
对象组成的数组——而非单纯的键字符串。

Limits

限制

  • Key length: up to 512 characters.
  • Total storage: 10 MB on the free plan, 1 GB on Pro — shared across all blobs in the account.
  • Store large or structured datasets in
    std/sqlite
    rather than as one giant blob.
  • 键长度: 最多512个字符。
  • 总存储容量: 免费版10 MB,专业版1 GB——账户内所有Blob共享该额度。
  • 大型或结构化数据集请存储在
    std/sqlite
    中,请勿作为单个巨型Blob存储。

Reading/writing blobs via tools

通过工具读写Blob

When using the
storeBlob
,
readBlob
,
listBlobs
, or
deleteBlob
tools against a val owned by an organization (not your personal account), pass the org handle as the
org
parameter so the call hits that organization's blob storage. Example:
{ key: "myapp:config", org: "some-org" }
. This only matters for the tool calls — code inside the val reads and writes its owning account's storage automatically. Note
storeBlob
accepts UTF-8 text up to 100 KB; write larger or binary blobs from code with
blob.set
.
当对组织(而非个人账户)所有的val使用
storeBlob
、
readBlob
、
listBlobs
或
deleteBlob
工具时,请将组织标识作为
org
参数传入,以确保调用访问该组织的Blob存储。示例:
{ key: "myapp:config", org: "some-org" }
。该参数仅对工具调用有效——val内部的代码会自动读写其所属账户的存储。注意:
storeBlob
仅支持最大100 KB的UTF-8文本;更大的文件或二进制Blob请通过代码使用
blob.set
写入。

Rules

规则

  • Treat keys as a flat namespace. Use prefixes (
    feature:subkey
    ) for organization and to scope
    list
    .
  • getJSON
    returns
    undefined
    for missing keys;
    get
    throws
    ValTownBlobNotFoundError
    . Handle the absent case accordingly.
  • Don't store secrets in blobs — use environment variables for credentials.
  • 请将键视为扁平命名空间。可使用前缀(
    feature:subkey
    )进行组织,也可用于
    list
    的前缀过滤。
  • 键不存在时,
    getJSON
    返回
    undefined
    ;
    get
    会抛出
    ValTownBlobNotFoundError
    。请根据实际情况处理键不存在的场景。
  • 请勿在Blob中存储敏感密钥——凭证类信息请使用环境变量存放。

Reference

参考