Vaze
SDK

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 URLs

Files 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 matches

Download 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 file

A 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 url

folder 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 not

Like 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 not

One 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.

On this page