Vue
The full Files API in the browser as a Vue 3 composable - useFiles returns the verbs plus refs for ambient state, with reactive useList / useFile / useSearch.
files-sdk/vue brings the full Files API to the browser as an idiomatic Vue 3 composable. useFiles returns one method per Files verb — upload, download, url, list, and the rest — plus ambient upload/error state as refs that unwrap automatically in templates.
<script setup lang="ts">
import { useFiles } from "files-sdk/vue";
const files = useFiles({ endpoint: "/api/files" });
const onUpload = async (event: Event) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
await files.upload(file);
}
};
</script>
<template>
<input type="file" @change="onUpload" />
<progress
v-if="files.isUploading.value"
:value="files.progress.value.fraction"
/>
<p v-if="files.error.value">{{ files.error.value.message }}</p>
</template>The verbs
Every verb mirrors the SDK — upload, download, head, exists, list, listAll, search, url, delete, copy, move, signedUploadUrl, capabilities — including the bulk array forms. They are plain methods (no .value):
const { key } = await files.upload(file); // keyless → server mints the key
const stored = await files.download("report.pdf"); // → a lazy StoredFile
const link = await files.url("avatar.png"); // → string, for <img :src>
await files.delete(["a.txt", "b.txt"]); // bulk → { deleted, errors? }Ambient state (refs)
Upload progress and the last error are exposed as refs, so they unwrap automatically in templates and stay reactive in script:
files.isUploading; // Ref<boolean>
files.progress; // Ref<{ loaded, total, fraction }>
files.uploads; // Ref<FileUploadState[]> — per-file live state
files.error; // Ref<FilesError | undefined> — last error from any verb
files.reset(); // clear ambient error + upload state (re-arms after abort)
files.abort(); // abort every in-flight callThe composable owns an AbortController that is aborted automatically on scope dispose (component unmount), so in-flight requests are cancelled for you.
Reactive reads
The query composables accept MaybeRefOrGetter inputs, so they re-run when their source changes — a file browser bound to a reactive prefix updates itself:
import { useList, useFile, useSearch } from "files-sdk/vue";
const prefix = ref("docs/");
const list = useList(() => ({ prefix: prefix.value })); // re-runs when prefix changes
const file = useFile(selectedKey); // head() for a preview
const hits = useSearch(query, { match: "substring" });
// each returns refs:
list.data; // Ref<ListResult | undefined>
list.isLoading; // Ref<boolean>
list.error; // Ref<FilesError | undefined>
list.refetch(); // re-run on demandLike the React versions they are cache-free and dependency-light; for shared caching, reach for a query library and call the imperative useFiles() methods inside it.
Setting up the gateway
Point the composable at a mounted gateway — createFilesRouter on Next, Hono, Express, or any Web-Request runtime — and lock it down with authorize.