Files
Work with files through the SDK
All file operations live on vaze.files. Every method returns the
response envelope — check error before using
data.
The File object
File objects returned by the SDK look like this:
type File = {
id: string;
name: string; // unique within its folder
key: string; // object key, e.g. "projects/demo/photo.png"
mimeType: string; // e.g. "image/png"
size: number; // bytes
folderId: string;
visibility: "public" | "private";
url: string; // absolute hosting URL
createdAt: string;
updatedAt: string;
};For a public file, url is ready to embed in an <img> tag or share
directly. For a private file the same URL is the canonical address but
returns 404 without credentials — use sign to get a link that
works.
List options
Methods that return multiple files accept an optional ListOptions object:
type ListOptions = {
limit?: number; // default: no limit
offset?: number; // default: 0
orderBy?: "createdAt" | "updatedAt" | "name" | "size"; // default: "createdAt"
orderDirection?: "ASC" | "DESC"; // default: "DESC"
};Upload files
Upload one or more File objects (Web API File, e.g. from fetch, form
inputs, or Node's fs.openAsBlob). Optionally pass a target folder path —
nested folders are created automatically:
const { data, error } = await vaze.files.upload({
files: [new File(["hello"], "hello.txt", { type: "text/plain" })],
folder: "projects/demo", // optional, defaults to the root folder
visibility: "private", // optional, defaults to the instance setting
});
// data => { files: File[] } including the hosting URLsFiles keep the name you upload them with, so you control the public URL.
Names are unique per folder — the same name in two folders is fine, but
uploading over an existing name returns a 409 error.
Uploads stream to disk and are moved into the target folder only once the
whole request has been received. A file over the maximum upload size returns
413, and a full volume returns 507.
From React Native
React Native has no Web File, so pass a FileReference instead: the uri
a picker returns, plus a name and MIME type. React Native streams the file from
disk without reading it into memory.
import * as DocumentPicker from "expo-document-picker";
const result = await DocumentPicker.getDocumentAsync();
if (!result.canceled) {
const [asset] = result.assets;
await vaze.files.upload({
files: [{ uri: asset.uri, name: asset.name, type: asset.mimeType ?? "application/octet-stream" }],
});
}Progress and canceling
upload reports no progress. To show it, send the same multipart form to
vaze.files.uploadUrl() yourself with
authHeaders(), for example with
XMLHttpRequest or Expo's UploadTask. An upload aborted mid-request is
recorded in the activity history as canceled. Ones you drop from your own
queue before sending never reach the server, so report them:
await vaze.files.reportCanceled(["holiday.mov", "notes.txt"]);Get all files
const { data, error } = await vaze.files.getAll({
limit: 20,
orderBy: "size",
orderDirection: "DESC",
});
// data => { files: File[] }Get a file by ID
const { data, error } = await vaze.files.getById("file-id");
// data => { file: File }Returns an error with status 404 if no file matches.
Get a file by key
const { data, error } = await vaze.files.getByKey("projects/demo/photo.png");
// data => { file: File }Search files by name
const { data, error } = await vaze.files.getByName(
"hello.txt",
{ limit: 10 }, // optional ListOptions
);
// data => { files: File[] } — empty array when nothing matchesDownload a file
Downloads the raw file content as a Blob:
const { data, error } = await vaze.files.download("file-id");
if (data) {
const { blob, filename, contentType } = data;
await fs.writeFile(filename ?? "download", Buffer.from(await blob.arrayBuffer()));
}The underlying endpoint supports byte ranges and ETag revalidation, so a
plain fetch against it can resume an interrupted transfer. download itself
always retrieves the whole file.
Download several files as a zip
const { data, error } = await vaze.files.downloadMany(["file-id", "other-id"]);
if (data) {
// e.g. "photos.zip", named after the folder the files share
await fs.writeFile(data.filename ?? "files.zip", Buffer.from(await data.blob.arrayBuffer()));
}Entries keep their paths below the deepest folder the files share. Every id must
exist, otherwise error is set and no archive is returned. The zip is read into
a Blob, so for selections too large to hold in memory, stream the
endpoint with
fetch instead.
URLs for your own requests
Some clients fetch a file themselves: an image component, or a download manager
that writes straight to disk. These return the URL to request, and
authHeaders() gives the headers to send
with it:
vaze.files.downloadUrl("file-id"); // what download() fetches
vaze.files.downloadManyUrl(); // where downloadMany() posts { ids }
vaze.files.thumbnailUrl("file-id"); // a WebP preview of an image fileA thumbnail is only available for image files; other files respond 404.
import { File, Paths } from "expo-file-system";
const saved = await File.downloadFileAsync(
vaze.files.downloadUrl(file.id),
new File(Paths.cache, file.name),
{ headers: await vaze.authHeaders() },
);Rename a file
const { error } = await vaze.files.rename({
id: "file-id",
name: "new-name.txt",
});The name must be a single path segment. Renaming to a name already taken in
the same folder returns a 409 error.
Move a file
const { data, error } = await vaze.files.move({
id: "file-id",
folder: "projects/archive", // or: folderId: "folder-id"
});
// data => { file: File } at its new key, with an absolute urlfolder is a key that is created if missing, and "" is the root. A name
already taken in the destination returns a 409 error. The file keeps its id
and visibility, but its URL changes, so links to the old location stop working.
Move several files
const { data, error } = await vaze.files.moveMany(["file-id", "other-id"], {
folder: "projects/archive",
});
console.log(data.files); // the files that were moved, at their new keys
console.log(data.failed); // [{ id, message }] for the ones that were notLike deleteMany, a single clash or bad id does not stop the others, and
error is only set when the whole request fails.
Change visibility
const { error } = await vaze.files.setVisibility({
id: "file-id",
visibility: "private",
});Making a file private stops /api/hosting from serving it to anonymous
callers. The file's bytes and key are untouched.
To flip a whole tree at once, use
folders.setVisibility.
Sign a URL
Mints a time-limited link that reads a file without an API key — how you hand a private object to a browser or a third party:
const { data, error } = await vaze.files.sign({
key: "projects/demo/report.pdf", // or: id: "file-id"
expiresIn: 900, // seconds, optional
});
// data => { url: string, expiresAt: string }url is absolute and ready to use. expiresIn defaults to the instance's
default signed link lifetime and is capped at its maximum, both set under
Settings in the dashboard.
Signed links cannot be revoked individually — they are stateless signatures,
not stored grants. Prefer short lifetimes. Rotating AUTH_SECRET invalidates
every outstanding link at once.
Delete a file
const { error } = await vaze.files.delete("file-id");Removes the file from both disk and the database.
Delete several files
const { data, error } = await vaze.files.deleteMany(["file-id", "other-id"]);
console.log(data.deleted); // ids that were removed
console.log(data.failed); // [{ id, message }] for the ones that were notOne request per batch, and a single bad id does not stop the others. error is
only set when the whole request fails — for example when none of the ids exist.
Vaze