Skip to content

Files

vb.files wraps the /api/v1/files/* endpoints. Pairs with the Files concept page for the server-side rules.

const file = inputEl.files[0]; // a Blob / File from <input type="file">
const meta = await vb.files.upload("posts", post.id, "cover", file);
// meta = {
// id: "u-…",
// filename: "uuid-…ext",
// originalName: "photo.jpg",
// size: 12345,
// mimeType: "image/jpeg",
// }

Multi-file fields accept an array; the response is meta[]:

await vb.files.upload("posts", post.id, "attachments", [file1, file2]);

The server enforces maxSize and mimeTypes from the field options before any bytes hit storage.

const url = vb.files.url(meta.filename);
// → "https://api.example.com/api/v1/files/uuid-…ext"
const thumb = vb.files.url(meta.filename, { thumb: "300x200" });
// → "https://api.example.com/api/v1/files/uuid-…ext?thumb=300x200"
const cropped = vb.files.url(meta.filename, { thumb: "400x300", fit: "cover" });
// → "…?thumb=400x300&fit=cover"

The URL is a plain GET, suitable for <img src> / <a href>.

Fields with protected: true (or any rule-based protection) need a ?token= to fetch. The SDK mints + caches one for you:

const tokenized = await vb.files.protectedUrl({
collection: "posts",
recordId: post.id,
field: "private_doc",
filename: "uuid-…pdf",
// optional: per-field IP-bound + one-time-token settings honored automatically
});
// → "https://api.example.com/api/v1/files/uuid-…pdf?token=<jwt>"

The token is good for ~1h (server-configurable via auth.file.window_seconds). The SDK caches it in-memory keyed by filename and refreshes ~60s before expiry.

// One file from a multi-file field
await vb.files.delete("posts", post.id, "attachments", filename);
// Every file under (record, field)
await vb.files.deleteAll("posts", post.id, "attachments");

vb.files.upload accepts any Blob / File-shaped object — useful in Node:

import { readFile } from "node:fs/promises";
const buf = await readFile("photo.jpg");
const blob = new File([buf], "photo.jpg", { type: "image/jpeg" });
await vb.files.upload("posts", post.id, "cover", blob);
StatusVaultbaseError.kindCause
401unauthenticatedNo auth + the field requires it (or rule denies anon)
403forbiddenRule deny / IP-bound mismatch
410goneOne-time token replayed
415unsupported_mediaMIME outside the global allow-list
422validationMIME outside the field’s mimeTypes or maxSize exceeded