Svelte

The full Files API in the browser, idiomatic Svelte - useFiles returns the verbs plus Svelte stores for ambient state (read with $store), with useList / useFile / useSearch.

files-sdk/svelte brings the full Files API to the browser as idiomatic Svelte. useFiles returns one method per Files verb — upload, download, url, list, and the rest — plus ambient upload/error state as Svelte stores you read with the $ prefix.

<script lang="ts">
  import { useFiles } from "files-sdk/svelte";
  import { onDestroy } from "svelte";

  const files = useFiles({ endpoint: "/api/files" });
  const { isUploading, progress, error } = files;
  onDestroy(files.abort); // cancel any in-flight calls on unmount

  async function onUpload(event: Event) {
    const file = (event.currentTarget as HTMLInputElement).files?.[0];
    if (file) {
      await files.upload(file);
    }
  }
</script>

<input type="file" on:change={onUpload} />
{#if $isUploading}<progress value={$progress.fraction} />{/if}
{#if $error}<p>{$error.message}</p>{/if}

The binding ships no Svelte runtime — its stores are a tiny implementation of the store contract, so $store auto-subscription works exactly as with writable.

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:

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 (stores)

files.isUploading; // Readable<boolean>      → $isUploading
files.progress; // Readable<{ loaded, total, fraction }>
files.uploads; // Readable<FileUploadState[]> — per-file live state
files.error; // Readable<FilesError | undefined> — last error from any verb
files.reset(); // clear ambient error + upload state (re-arms after abort)
files.abort(); // abort every in-flight call — wire to onDestroy

Svelte's lifecycle hooks need the compiler, so cancel in-flight work by calling files.abort from onDestroy — one line, as above.

Reactive reads

The query stores load on creation and expose data / error / isLoading / isFetching stores plus refetch(). Svelte's reactivity lives at the component level, so re-run them from a $: block when a dependency changes:

<script lang="ts">
  import { useList } from "files-sdk/svelte";

  let prefix = "docs/";
  const { data, isLoading, refetch } = useList({ prefix });

  $: prefix, refetch(); // re-run whenever `prefix` changes
</script>

{#if $isLoading}Loading…{:else}
  <ul>{#each $data?.items ?? [] as item}<li>{item.key}</li>{/each}</ul>
{/if}

useFile(key) (a head() for previews) and useSearch(pattern, opts) work the same way.

Setting up the gateway

Point the binding at a mounted gatewaycreateFilesRouter on Next, Hono, Express, or any Web-Request runtime — and lock it down with authorize.

On this page